1. 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!

Dismiss Notice
This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Skript Player Data System

Discussion in 'Tutorials' started by ShaneBee, Mar 23, 2020.

  1. ShaneBee

    Supporter + Addon Developer

    Sep 7, 2017
    Likes Received:
    One of the main performance issues with Skript is the variable system.
    If used correctly it can be great, but it is often abused/overused which can cause major performance issues with a server.

    Let's do some basic math:
    Let's say per-player you have the following variables:
    - Money
    - Points
    - Homes (5)
    - A player-vault with 27 slots
    - Nickname
    - team/group/clan
    This alone is 36 variables.... per player. (Most servers have a lot more than this, this is just a small example)
    Now let's say over a short period of time, you've had 1000 unique joins.
    That is 36,000 variables saved in one file.
    Each time your server loads, it loads ALL of these variables into RAM. Most of these players won't ever come back but you've got a lot of variables loading each time.

    Things like this can cause great stress on your server. So what can we do to alleviate that pressure on your server? Well, this is where I introduce to you, a PlayerData system using skript-yaml.

    This system is quite easy to use, and is very flexible. The goal here is to create a PlayerData file per player, and only load into RAM the players that are online.

    So let's get started.
    This system uses skript-yaml, if you need more info check out the SKRIPT-YAML REPO for more information.

    Loading PlayerData into RAM:
    When the player joins, we will load their data into RAM for easy/quick access.
    As stated, this allows us to load into RAM the data for players which are currently online, and not the 100s or 1000s of players who won't ever come back.
    We will also set their current name and last-login for future use
    Code (Skript):
    1. on join:
    2.     load yaml "plugins/MyData/%uuid of player%.yml" as "data-%uuid of player%"
    3.     set yaml value "name" in "data-%uuid of player%" to name of player
    4.     set yaml value "last-login" in "data-%uuid of player%" to now
    5.     save yaml "data-%uuid of player%"
    Unloading PlayerData:
    When the player quits, we will save/unload their data.
    This again will help keep our RAM at efficient usage.
    Code (Skript):
    1. on quit:
    2.     save yaml "data-%uuid of player%"
    3.     unload yaml "data-%uuid of player%"
    Saving PlayerData periodically to file:
    Rather than saving PlayerData to file every time we make a change to it, we will do it periodically.
    Why you ask? Thing of systems like jobs, where players get payed money everytime they do an action, like for example mining. Now imaging 100 players online, mining hundreds of blocks a second. We don't want to constantly be writing to file, this would put a lot of strain on the server and affect performance.
    So we periodically save to file.
    Don't worry, the PlayerData will always be in ram, you can write to/read from without affecting performance. The save we are talking about here is writing to your yaml file.
    Code (Skript):
    1. # Every 5 minutes we will save all current online player data just to be safe
    2. # Adjust time to your liking
    3. every 5 minutes:
    4.     loop all loaded yaml:
    5.         save loop-value
    6.         # We add a small wait between each player data to prevent
    7.         # a massive amount of lag if a lot of players are online
    8.         # Adjust to suit your server's needs
    9.         wait 2 ticks
    Accessing/Modifying our PlayerData:
    We will create some functions for quick access to player data
    I'm using money and points as an example, but you can use whatever data you need for your server.
    These simple functions allow you to easily get/set/add/remove info from PlayerData files.
    Code (Skript):
    1. # Money
    2. function getMoney(p: player) :: number:
    3.     return yaml value "money" from "data-%uuid of {_p}%"
    5. function setMoney(p: player, n: number):
    6.     set yaml value "money" in "data-%uuid of {_p}%" to {_n}
    8. function addMoney(p: player, n: number):
    9.     set {_money} to yaml value "money" in "data-%uuid of {_p}%"
    10.     add {_n} to {_money}
    11.     set yaml value "money" in "data-%uuid of {_p}%" to {_money}
    13. function removeMoney(p: player, n: number):
    14.     set {_money} to yaml value "money" in "data-%uuid of {_p}%"
    15.     remove {_n} from {_money}
    16.     set yaml value "money" in "data-%uuid of {_p}%" to {_money}
    18. # Points
    19. function getPoints(p: player) :: number:
    20.     return yaml value "points" from "data-%uuid of {_p}%"
    22. function setPoints(p: player, n: number):
    23.     set yaml value "points" in "data-%uuid of {_p}%" to {_n}
    25. function addPoints(p: player, n: number):
    26.     set {_points} to yaml value "points" in "data-%uuid of {_p}%"
    27.     add {_n} to {_points}
    28.     set yaml value "points" in "data-%uuid of {_p}%" to {_points}
    30. function removePoints(p: player, n: number):
    31.     set {_points} to yaml value "points" in "data-%uuid of {_p}%"
    32.     remove {_n} from {_points}
    33.     set yaml value "points" in "data-%uuid of {_p}%" to {_points}

    So how do we use these functions? Well I'm glad you asked, if you haven't used functions before I recommend checking out the FUNCTIONS WIKI for more info. If you have used functions before you will know how extremely easy they are to use.

    Here is an example command using our newly created functions:
    Code (Skript):
    1. # Now that we have our base set up, lets use our data
    2. # Quick example of a points command using our data functions
    3. # In this example i will be skipping some obvious conditions for args
    4. # I just want to show the basic usage of the functions
    5. # I will also not be putting obvious messages, again, just to simply show how this works
    7. command /points <text> [<player=%player%>] [<number>]:
    8.     trigger:
    9.         if arg-1 = "get":
    10.             # here we can simply print a message with the points of the player/arg
    11.             send "Points for %arg-2%: %getPoints(arg-2)%"
    12.         else if arg-1 = "set":
    13.             # here we can set points
    14.             setPoints(arg-2, arg-3)
    15.         else if arg-1 = "add":
    16.             # Here we can add to the points
    17.             addPoints(arg-2, arg-3)
    18.         else if arg-1 = "remove":
    19.             # Here we can remove from the points
    20.             removePoints(arg-2, arg-3)
    Here is a sample event using our newly created functions:
    Code (Skript):
    1. # We're going to use on join, to set the defaults for the player
    2. # If the values are not currently set, let's set them
    4. on join:
    5.     # Here we set the player's points to 10 when they join if its not currently set
    6.     if getPoints(player) is not set:
    7.         setPoints(player, 10)
    8.     # Here we set the player's money to 500 when they join if its not currently set
    9.     if getMoney(player) is not set:
    10.         setMoney(player, 500.00)
    Clearing old PlayerData:
    Lastly, lets say we want to clear out old player data (player's who havent logged in for a while)
    We can simply run a command to clear out old data
    Obviously this command will need permission checks and stuff, again, this is just an example

    Special Note: A command like this should not be run when a lot of players are online
    Code (Skript):
    1. command /clearOldData:
    2.     trigger:
    3.         set {_n} to 0 # lets create a counter
    4.         loop all offline players:
    5.             # here we are going to load each offline player's data, and check the difference between now and last-login
    6.             # if grater than 100 days, we will delete their data
    7.             # else we will just unload it and move onto the next
    8.             load yaml "plugins/MyData/%uuid of loop-offline player%.yml" as "off-%uuid of loop-offline player%"
    9.             set {_t} to yaml value "last-login" from "off-%uuid of loop-offline player%"
    10.             if difference between now and {_t} > 100 days:
    11.                 delete yaml "off-%uuid of loop-offline player%"
    12.                 # lets just let the console know we're deleting this
    13.                 send "Deleting data for %loop-offline player%" to console
    14.                 # We will add 1 to {_n} so we know how many player data's we cleared
    15.                 add 1 to {_n}
    16.             else:
    17.                 unload yaml "off-%uuid of loop-offline player%"
    18.             wait 1 tick
    19.         # Now we tell the console how many data's we cleared
    20.         send "Removed player data for %{_n}% inactive player(s)" to console
    Example PlayerData file:
    Here is an example of what MY PlayerData file looks like, using this code:
    Code (YAML):
    1. name: ShaneBee
    3. last-login: !skriptdate '2020-03-23T13:59:42.570-07:00'
    5. points: 10
    7. money: 500.0
    #1 ShaneBee, Mar 23, 2020
    Last edited: Apr 3, 2020
    • Like Like x 3
    • Winner Winner x 2
  2. AsuDev


    Jan 27, 2017
    Likes Received:
    This is fantastic. Thank you so much for this!

    Just one question though, how would we go about creating an efficient toplist using skript-yaml? Since things like mirror-util's sorting function use list variables for sorting. What would be the most efficient way of pulling all the data from the yaml of all players and sorting it be?
    #2 AsuDev, Mar 29, 2020
    Last edited: Mar 29, 2020
    • Winner Winner x 1
  3. ShaneBee

    Supporter + Addon Developer

    Sep 7, 2017
    Likes Received:
    I recommend creating a new thread for a question like that, as it doesn't really fit the theme of this thread.
  4. NiceFinal

    NiceFinal Member

    Feb 24, 2018
    Likes Received:
    Thanks for the guide, it's help me a lot !
    I like the way how you write the example.
    • Friendly Friendly x 1
  5. The system works flawlessly!! Thank you Shane!
    • Friendly Friendly x 1
  6. Laukage

    Laukage Member

    Jan 26, 2017
    Likes Received:
    Could you provide some pictures of how your directories look?

    I currently use Skutilities, but i want to switch - is it worth or would the performance be the same?
  7. ShaneBee

    Supporter + Addon Developer

    Sep 7, 2017
    Likes Received:
    No real reason to show an image of the directory, it would look about the same.
    As for skUtilities, that addon died years ago, and the performance of skUtil vs Skript-yaml is horrible. Skript-yaml is the way to go.
    • Like Like x 1
  8. Laukage

    Laukage Member

    Jan 26, 2017
    Likes Received:
    But i do not understand what the "-" in "data-%uuid of player%" does?
  9. ShaneBee

    Supporter + Addon Developer

    Sep 7, 2017
    Likes Received:
    it'll create a file like "Data-some-uuid-here.yaml" the hyphen is to differentiate the word "data" from the uuid
  10. Laukage

    Laukage Member

    Jan 26, 2017
    Likes Received:
    oh so its purely just because you like it that way? it doesn't do anything other than the name of the file?

Share This Page