Skript Sorting Method / Toplists

  • Welcome to skUnity!

    Welcome to skUnity! This is a forum where members of the Skript community can communicate and interact. Skript Resource Creators can post their Resources for all to see and use.

    If you haven't done so already, feel free to join our official Discord server to expand your level of interaction with the comminuty!

    Now, what are you waiting for? Join the community now!

AsuDev

VIP
Jan 27, 2017
241
22
18
24
United States
Requirements: Skript and Skript-Mirror 2.0
Tested on: 1.8.8, 1.13.2, 1.14.4
Difficulty: Semi-Basic/Complex

This is a small tutorial on how to create a toplist with Skript based on a couple expressions made in skript-mirror.

The skript-mirror expressions / sorting algorithm:
code_language.skript:
import:
    java.util.ArrayList
    java.util.Collections
    java.util.Map$Entry
    ch.njol.skript.variables.Variables

expression replace values %strings% with %strings% in %string%:
    get:
        set {_string} to expression-3
        loop expressions-1:
            add 1 to {_index}
            replace all "%loop-value%" with "%{_index}th element of expressions-2%" in {_string}
        return {_string}
 
plural expression [the] (1¦(highest|top)|2¦(lowest|last)) %integer% values of %objects% [formatted] as %string%:
    get:
        set {_list} to new ArrayList(Variables.getVariable(raw expressions-2.getName().toString(event), event, raw expressions-2.isLocal()).entrySet())
        {_list}.sort(Entry.comparingByValue())
        if parse mark = 1:
            Collections.reverse({_list})
        loop ...{_list}:
            "%loop-value.getValue()%" is not "0"
            add 1 to {_index}
            set {_sorted::%{_index}%} to replace values "@place", "@index" and "@value" with "%{_index}%", "%loop-value.getKey()%" and "%loop-value.getValue()%" in expression-3
            {_index} = expression-1
            stop loop
        return {_sorted::*}
These expressions will allow us to make toplists. The syntax is not that hard to use and it uses a very efficient sorting algorithm. It is much faster than anything you can really make with vanilla Skript. I did some testing and this algorithm can sort up to 50,000 values in one second!

You may be thinking, what are "@place" and "@index" and "@value" in this list. @place represents what place the value is in, for example, first place or second place. @index represents the key. For example, in a toplist, the key would be the player name or UUID. @value represents the value. For example, if a toplist was based on kills, it would be the amount of kills the player has.

Note: it is recommended to make an auto-updator for leaderboards and not update it every time they use a command. Player's that spam a command like this could crash the server! This is just an example.
Example toplist #1 ( Top Kills based on {Kills::*} ):
code_language.skript:
command /topkillers:
    trigger:
        set {_topKillers::*} to the highest (size of {Kills::*}) values of {Kills::*} as "&e@place. &b@index &7- &6@value"
        message "&eTop Killers"
        loop {_topkillers::*}:
            message loop-value
            #if loop-index is "10":
            #    stop loop
This toplist example will sort everything in {Kills::*} from highest to lowest.

Note: it is recommended to make an auto-updator for leaderboards and not update it every time they use a command. Player's that spam a command like this could crash the server! This is just an example.
Example toplist #2 ( Top Kills based on {Kills::*}, 10 displayed per page )
code_language.skript:
command /topkillers [<integer=1>]:
    trigger:

        # Example amount to show per page. In this example, its 10
        set {_showPerPage} to 10
        set {_toSortTo} to arg 1 * {_showPerPage}

        set {_topKillers::*} to the highest {_toSortTo} values of {Kills::*} as "&e@place. &b@index &7- Kills: &6@value"
        message "&eTop Killers Page %arg 1%"
        loop {_topkillers::*}:
            if ("%loop-index%" parsed as integer) is between {_toSortTo} - ({_showPerPage} - 1) and {_toSortTo}:
                message loop-value
This toplist example will set values until a certain point (more efficient than sorting all unless you need to). This toplist uses a page system.

Picture Example of toplist #2:
Capture.PNG


I could add a few more examples but I should have given you enough info to get started on your own. Good luck with your toplists!

Credits: EWS (I didn't originally make this method of sorting. I edited the original version from Mirrorutils and also showed how to use it.)
 
Last edited:
  • Like
Reactions: WilderPizza
Also add that this is from Mirrorutils
While it is originally from Mirrorutils, I will simply state that it was originally from Mirrorutils but I am not saying that you need it as a requirement. This is a standalone piece of code that was edited and credit was given.
 
This is exactly what I needed! You've just saved me a lot of time reworking my old toplist code lol. Thanks @AsuDev! :emoji_heart:
 
Try using skript 2.2-dev36 as it is the most recent working version for 1.8.8. You can find it here:
https://github.com/SkriptLang/Skript/releases/download/dev36/Skript.jar
I have tested this on 1.8.8 with that Skript version so it should work.
I'll try it tomorrow :emoji_stuck_out_tongue:
[doublepost=1571601742,1571527659][/doublepost]
Try using skript 2.2-dev36 as it is the most recent working version for 1.8.8. You can find it here:
https://github.com/SkriptLang/Skript/releases/download/dev36/Skript.jar
I have tested this on 1.8.8 with that Skript version so it should work.
still geting that error :/
 
I'll try it tomorrow :emoji_stuck_out_tongue:
[doublepost=1571601742,1571527659][/doublepost]
still geting that error :/
I don't know what to say then. It works for me perfectly when I use those versions. Maybe someone else can clarify it.

I actually just checked my Skript version on my 1.8.8 server and it said it was a custom version. I don't know if that makes a difference or not but you can try this one instead: https://drive.google.com/file/d/1hkiAHyGb9mGixiOVC5qehytr4QGZCRww/view

Also I just made sure again, and sure enough it works fine on that version.
 
Last edited:
You shouldn't sort your values directly in the command. If it takes 1 second to sort 50k variables, someone spamming the command will crash the server rather easily.
Also, I don't understand why you replaced expr/exprs with expression. For me it only reduces readability by making lines longer.

Here's how I usually do it in my scripts:
code_language.skript:
function top_sort() :: strings:
    clear {top::values::*}
    set {top::lastsorted} to now
    set {top::values::*} top 100 elements of {list::*} formatted as "<pos> <index> <value>"
       
function top_get() :: strings:
    if difference between now and {top::lastsorted} > 10 minutes:
        top_sort()
    else if {top::values::*} is not set:
        top_sort()
    return {top::values::*}
   
# Use top_get() to return the top values.
It only sorts when the values are needed, and with a configurable delay.

You can also further extend the sorting feature to UUIDs:
code_language.skript:
loop top 10 elements of {list::*} formatted as "<index>;<value>":
    add 1 to {_n}
    set {_s::*} to split loop-value at ";"
    set {_p} to {_s::1} parsed as offlineplayer
    set {top::values::%{_n}%} to "%{_n}% %{_p}% %{_s::2}%"

Also note that what makes it sort 50k values/second is not Java's sorting method, but setting the list variable. Always use the least amount of values possible for better performance.
 
  • Like
Reactions: Farid