Just so you know, we don't know the file format for every file. If it's just a bunch of random characters, it's probably a .zip or .jar.
# #########################################################################################
# Kill Leaderboard Examples by AsuDev
# Requirements: Skript for your version, Skript-Mirror 2.0.0+, SkQuery-Lime
# Versions: 1.8.8 - 1.14.4
# #########################################################################################
# EXTRA INFORMATION
# The sorting method used in this script can sort up to 50,000 values a second!
# This script is just a collection of examples of making a toplist!
# You may edit this script however you want and you can make whatever you want with it.
# THIS CURRENT VERSION IS FOR SKRIPT 2.3.6 AND LOWER! TO MAKE IT COMPATIBLE WITH THE HIGHER
# VERSIONS, YOU MUST CHANGE THE SEND MESSAGE TO "send formatted" instead of "send" for the
# json formatting. This will not throw an error, but the json formatting will be messed up
# when using Skript 2.3.7+
# #########################################################################################
# CREDITS
# AsuDev for making the script and all of the examples.
# EWS for making this sorting algorithm for skript variables in skript-mirror
# #########################################################################################
# List of java class imports
import:
java.util.ArrayList
java.util.Collections
java.util.Map$Entry
ch.njol.skript.variables.Variables
java.lang.System
org.json.simple.JSONValue
# These options are for if you are going to actually use this script instead
# of taking from it and making your own thing. You can experiment with these
# and use or change whatever you want.
options:
updaterBreak: 15 minutes # How often to update the leaderboard automatically
indexesPerPage: 10 # Amount of players to show per page in the toplist
FirstPlaceFormat: &6&l # Format of first place
SecondPlaceFormat: &b&l # Format of second place
ThirdPlaceFormat: &2&l # Format of third place
OtherPlaceFormat: &3 # Format of everything else
Splitter: - # What to split the player data with when sorting players
OutputFormat: @place-@index-@value # The output for sorting players / Make sure splitter is correct with this
ChatBorder: &8&m----------------------------------------------------
# @StartIndex is the value the list starts at / @EndIndex is the where the page ends / @LastUpdated is the last time the leaderboard was updated
ChatOutputHeader: &eTop Killers &8- &7Showing &6@StartIndex-@EndIndex &8- &7Last Updated: &b@LastUpdated ago # The header of the leaderboard command
# @place is the place the player is in / @index is the player name / @value is the amount of kills they have
ChatOutputFormat: &8➵ @place &7@index &8- &a@value Kills # The chat output for the leaderboard command for each player
# #########################################################################################
# For null values when sorting
# Gets the name of an offline player based on UUID
function getOfflinePlayerName(uuid: text) :: string:
replace all "-" with "" in {_uuid}
set {_jsonInfo} to text from "https://api.mojang.com/user/profiles/%{_uuid}%/names"
set {_nameValue} to JSONValue.parseWithException({_jsonInfo})
set {_player} to {_nameValue}.get({_nameValue}.size()-1).toString()
set {_nameObject} to JSONValue.parseWithException({_player})
return {_nameObject}.get("name").toString()
# #########################################################################################
# EXPRESSIONS
# Expression used to replace multiple values within a string at once.
# Original version made by EWS
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}
# Expression used for sorting. Uses java collections for sorting and is very fast.
# Original version made by EWS, edited by AsuDev.
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}
if "%(loop-value.getKey()) parsed as offline player%" is not "null":
set {_sorted::%{_index}%} to replace values "@place", "@index" and "@value" with "%{_index}%", "%(loop-value.getKey()) parsed as offline player%" and "%loop-value.getValue()%" in expression-3
else:
loop {CachedOfflinePlayers::*}:
if loop-value-2 contains "^%loop-value-1.getKey()%":
set {_v::*} to loop-value-2 split by "^"
set {_name} to {_v::1}
set {_sorted::%{_index}%} to replace values "@place", "@index" and "@value" with "%{_index}%", {_name} and "%loop-value-1.getValue()%" in expression-3
set {_continue} to false
if {_continue} is not set:
set {_name} to getOfflinePlayerName(loop-value.getKey())
set {_sorted::%{_index}%} to replace values "@place", "@index" and "@value" with "%{_index}%", {_name} and "%loop-value.getValue()%" in expression-3
message "&cError when getting name from uuid '%loop-value.getKey()%'. Retrieving name from Mojangs database may severely slow down the sorting time! This should not occur with this uuid again as data is now stored for this uuid." to console
add "%{_name}%^%loop-value-1.getKey()%" to {CachedOfflinePlayers::*}
delete {_continue} and {_name} and {_v::*}
{_index} = expression-1
stop loop
return {_sorted::*}
# #########################################################################################
# EXAMPLE EVENTS / FUNCTIONS
# Updates the leaderboard
function updateKillsLeaderboard(senders: objects):
delete {KillLB::*}
set {_timeNow} to ceil(System.currentTimeMillis())
loop {_senders::*}:
send "&7Updating the Kill leaderboard..." to loop-value
set {KillLB::*} to the highest (size of {Kills::*}) values of {Kills::*} as "{@OutputFormat}"
set {_timeAfter} to (ceil(System.currentTimeMillis()) - {_timeNow})
loop {_senders::*}:
send "&7Update complete. The update took &b%{_timeAfter}%ms&7." to loop-value
set {LastLeaderboardUpdate} to ceil(System.currentTimeMillis())
# Gets the ordinal string of an integer
function ordinalNumber(i: integer) :: string:
set {_lastDigit} to mod({_i}, 10)
set {_lastTwoDigits} to mod({_i}, 100)
if {_lastTwoDigits} is between 10 and 20:
return "%{_i}%th"
else if {_lastDigit} is 1:
return "%{_i}%st"
else if {_lastDigit} is 2:
return "%{_i}%nd"
else if {_lastDigit} is 3:
return "%{_i}%rd"
else:
return "%{_i}%th"
# Gets a player's place on the leaderboard and formats it into an ordinal ranking format
function getKillPlacing(p: offline player) :: string:
loop {KillLB::*}:
if loop-value contains "-%{_p}%-":
set {_placing} to loop-index parsed as integer
if {_placing} is 1:
return "{@FirstPlaceFormat}%ordinalNumber(1)%."
else if {_placing} is 2:
return "{@SecondPlaceFormat}%ordinalNumber(2)%."
else if {_placing} is 3:
return "{@ThirdPlaceFormat}%ordinalNumber(3)%."
else:
return "{@OtherPlaceFormat}%ordinalNumber({_placing})%."
stop
# Converts an integer into an ordinal ranking format by integer
function ordinalNumberRankFormat(placing: integer) :: string:
if {_placing} is 1:
return "{@FirstPlaceFormat}%ordinalNumber(1)%."
else if {_placing} is 2:
return "{@SecondPlaceFormat}%ordinalNumber(2)%."
else if {_placing} is 3:
return "{@ThirdPlaceFormat}%ordinalNumber(3)%."
else:
return "{@OtherPlaceFormat}%ordinalNumber({_placing})%."
# Example calculation of KDR of a player
function calculateKDR(p: offline player) :: string:
set {_uuid} to uuid of {_p}
set {_kills} to {Kills::%{_uuid}%}
set {_deaths} to {Deaths::%{_uuid}%}
if {_kills} and {_deaths} is 0:
return "&60"
if {_kills} is not 0:
if {_deaths} is 0:
add 1 to {_deaths}
return "&6%{_kills}/{_deaths}%"
# Formats seconds into a nice, more readable time.
function formatTime(i: number) :: string:
set {_s} to "s"
set {_days} to floor({_i} / 86400)
set {_hours} to floor({_i} / 3600)
set {_minutes} to floor((mod({_i}, 3600)) / 60)
set {_seconds} to floor(mod({_i}, 3600))
set {_seconds} to floor(mod({_seconds}, 60))
set {_format} to ""
if {_days} is not 0:
set {_format} to "%{_days}%d "
if {_hours} is not 0:
set {_format} to "%{_format}%%{_hours}%h "
if {_minutes} is not 0:
set {_format} to "%{_format}%%{_minutes}%m "
return "%{_format}%%{_seconds}%%{_s}%"
# Example scheduler to update the leaderboard
every {@updaterBreak}:
updateKillsLeaderboard(console)
loop all players:
if loop-player has permission "boardupdator":
message "&7The Kills leaderboard has just been updated." to loop-player
# Example, set the players stats when they join
on join:
{Kills::%uuid of player%} is not set
set {Kills::%uuid of player%} to 0
set {Deaths::%uuid of player%} to 0
# Example event to add kills/deaths to a player
on death of player:
add 1 to {Deaths::%uuid of victim%}
attacker is a player
add 1 to {Kills::%uuid of attacker%}
# #########################################################################################
# EXAMPLE COMMANDS
# Example, manual command for updating the kills leaderboard
command /updateKillsLeaderboard:
permission: leaderboard.update
permission message: &cYou do not have permission to execute this command.
trigger:
updateKillsLeaderboard(player and console)
# A cache for offline players in case sorting returns a null value
command /cachedofflineplayers:
aliases: coplayers
permission: cachedview.admin
trigger:
message "&6Cached Offline Players"
loop {CachedOfflinePlayers::*}:
set {_values::*} to loop-value split by "^"
message "&8- &b%{_values::1}% &8(&e%{_values::2}%&8)"
# Example, K/D stats for a specified player
command /kills [<offline player=%player%>]:
aliases: deaths, kdr
trigger:
if {Kills::%uuid of arg 1%} and {Deaths::%uuid of arg 1%} is set:
message "&e%arg 1%'s K/D Stats"
message "&7Kills: &a%{Kills::%uuid of arg 1%}%"
message "&7Deaths: &c%{Deaths::%uuid of arg 1%}%"
message "&7KDR: &a%{Kills::%uuid of arg 1%}%&7/&c%{Deaths::%uuid of arg 1%}% &7= %calculateKDR(arg 1)%"
if getKillPlacing(arg 1) is not set:
message "&7Leaderboard: &3Not on leaderboard."
else:
message "&7Leaderboard: %getKillPlacing(arg 1)%"
else:
message "&cThat player has no stats logged for kills or deaths."
# Example, Get a player's placing index
command /placing [<offline player=%player%>]:
trigger:
if {Kills::%uuid of arg 1%} and {Deaths::%uuid of arg 1%} is set:
if getKillPlacing(arg 1) is not set:
message "&e%arg 1% &7is currently not on the kill leaderboard."
else:
message "&e%arg 1% &7is currently %getKillPlacing(arg 1)% &7on the kill leaderboard."
else:
message "&cThat player has no stats logged for kills or deaths."
# Example, Get a player at a specified placing
command /place [<integer=1>]:
trigger:
if arg 1 is less than or equal to 0:
message "&cInvalid placing. Please specify a number greater than 0."
stop
if size of {KillLB::*} is less than arg 1:
message "&cInvalid placing. The number you specified exceeded the total amount of players in the leaderboard. The max is currently %size of {KillLB::*}%."
stop
set {_placing::*} to {KillLB::%arg 1%} split by "{@Splitter}"
set {_p} to {_placing::2} parsed as offline player
set {_placing} to ordinalNumberRankFormat({_placing::1} parsed as integer)
message "&7The player in %{_placing}% &7place on the kill leaderboard is &e%{_p}%&7."
# Example, Leaderboard command
command /topkills [<integer=1>]:
aliases: topk, topkiller, topkillers, toplb, topleaderboard
trigger:
if arg 1 is less than or equal to 0:
message "&cYou must specify a page over 0."
stop
set {_lastUpdated} to formatTime((ceil(System.currentTimeMillis()) - {LastLeaderboardUpdate}) / 1000)
set {_showPerPage} to {@indexesPerPage}
set {_indexesToShow} to arg 1 * {_showPerPage}
set {_startingIndex} to {_indexesToShow} - ({_showPerPage} - 1)
set {_maxpage} to ceil(size of {KillLB::*} / {_showPerPage})
if arg 1 is {_maxpage}:
set {_showingMax} to size of {KillLB::*}
else:
set {_showingMax} to {_indexesToShow}
if {KillLB::%{_startingIndex}%} is not set:
message "&cThe page you specified wasn't found. Valid pages are 1-%{_maxpage}%."
stop
message "{@ChatBorder}"
message replace values "@StartIndex", "@EndIndex" and "@LastUpdated" with "%{_indexesToShow} - ({_showPerPage} - 1)%", "%{_showingMax}%" and "%{_lastUpdated}%" in "{@ChatOutputHeader}"
message "{@ChatBorder}"
#message ""
loop {KillLB::*}:
if (loop-index parsed as integer) is between {_startingIndex} and {_indexesToShow}:
set {_info::*} to loop-value split by "{@Splitter}"
set {_placing} to ordinalNumberRankFormat({_info::1} parsed as integer)
set {_p} to {_info::2} parsed as offline player
set {_uuid} to uuid of {_p}
set {_format} to replace values "@place", "@index", "@value" with "%{_placing}%", "%{_info::2}%", "%{_info::3}%" in "{@ChatOutputFormat}"
send " <tooltip:&e%{_p}%'s K/D Stats%nl%&7Kills: &a%{Kills::%{_uuid}%}%%nl%&7Deaths: &c%{Deaths::%{_uuid}%}%%nl%&7KDR: &a%{Kills::%{_uuid}%}%&7/&c%{Deaths::%{_uuid}%}% &7= %calculateKDR({_p})%>%{_format}%&r" to player
delete {_info::*} and {_placing} and {_p} and {_uuid} and {_format}
#message ""
message " <tooltip:&eClick to go back a page.><cmd:/topkills %arg 1 - 1%>&7←&r <tooltip:&eClick to go forward one page.><cmd:/topkills %arg 1 + 1%>&7→&r"
message "{@ChatBorder}"
# Example, Admin command for manipulating stats of players
command /killsadmin [<text>] [<text>] [<offline player>] [<integer>]:
permission: killsadmin
permission message: &cYou do not have permission to use this command.
aliases: kadmin, killadmin
trigger:
if arg 1 is not set:
message "&fSets the amount of kills or deaths a player has."
message "&f/killsadmin set kills,deaths <player> <amount>"
message "&fAdds to the kills or deaths a player has."
message "&f/killsadmin add kills,deaths <player> <amount>"
message "&fRemoves from the amount of kills or deaths a player has."
message "&f/killsadmin remove kills,deaths <player> <amount>"
stop
if arg 1 and arg 2 and arg 3 and arg 4 is set:
if arg 2 is "kills" or "deaths":
if arg 4 is greater than or equal to 0:
if arg 1 is "set":
if {%arg 2%::%uuid of arg 3%} is not set:
set {Kills::%uuid of arg 3%} to 0
set {Deaths::%uuid of arg 3%} to 0
set {%arg 2%::%uuid of arg 3%} to arg 4
message "&7You set the &c%arg 2% &7value of &b%arg 3% &7to &e%arg 4%&7."
else if arg 1 is "add":
if {%arg 2%::%uuid of arg 3%} is not set:
set {Kills::%uuid of arg 3%} to 0
set {Deaths::%uuid of arg 3%} to 0
add arg 4 to {%arg 2%::%uuid of arg 3%}
message "&7You added &e%arg 4% &7to the &c%arg 2% &7value of &b%arg 3%&7."
else if arg 1 is "remove":
if {%arg 2%::%uuid of arg 3%} is not set:
set {Kills::%uuid of arg 3%} to 0
set {Deaths::%uuid of arg 3%} to 0
remove arg 4 from {%arg 2%::%uuid of arg 3%}
message "&7You removed &e%arg 4% &7from the &c%arg 2% &7value of &b%arg 3%&7."
if {%arg 2%::%uuid of arg 3%} is less than 0:
set {%arg 2%::%uuid of arg 3%} to 0
else:
make player execute command "killsadmin"
else:
message "&cYou must specify an amount above or equal to 0."
else:
message "&cYou must specify either kills or deaths."
else:
make player execute command "killsadmin"
# #########################################################################################