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.

How to debug

May 31, 2020
How to debug
  • Why you are here
    Debugging is essentially problem-solving. Every programmer must know how to debug.

    In this short tutorial, I'll demonstrate ways of debugging your problems in Skript



    Debugging
    [[ Introduction ]]

    Debugging is essentially checking if everything works correctly
    for instance, A -> B -> C... -> Z
    and if A doesn't show Z, it means that anything could have gone wrong

    This tutorial covers console debugging as well as other good practices

    [[ Explicitly showing the problem ]]

    A bad code here looks like this - source : skUnity Discord
    Code (Text):
    1.  
    2. format gui slot 24 of player with glowing iron sword named "&6{@flower} &eKitPVP &6{@flower}" with lore "&c&lKitPVP is currently under development!", "&f", "&7Kill other players to", "&7gain exp and level up!", "&f", "&e{@flower} &fKits", "&e{@flower} &fPvP Levels", "&e{@flower} &fLeaderboards" "&f", "&fVersions &b1.8.x - 1.15.x", "&b%{_players_kitpvp}% players online!", "&aClick here to connect!" to close then run player command "/kitpvp"
    3.  
    And the person says that this is not working because of named ""
    If someone were to debug this, it would take ages. So? you should explicitly show what is wrong

    Code (Text):
    1.  
    2. format gui slot 24 of player with glowing iron sword named "test"
    3.  
    Then, you can see that it works
    So lets test more things

    Code (Text):
    1.  
    2. format gui slot 24 of player with glowing iron sword named "test" with lore "hi"
    3.  
    it also works

    then you start making it longer and longer until you realize
    Code (Text):
    1.  
    2. "&e{@flower} &fLeaderboards" "&f", "&fVersions &b1
    3.  
    you forgot to add a comma there


    [[ Condition checking / Debug messages]]
    Your problems most occur when you least expect it. So it is a good idea to check if everything else is working

    NOTE: DO NOT USE MESSAGE/SEND INSTEAD OF BROADCAST
    here is why:
    send effects are often unreliable
    here is an example
    Code (Text):
    1.  
    2. on right click:
    3.     send "fired"
    this debug seems to work until you right click on a player
    this is because send doesn't always send to the person who is activating the event

    there are more examples where send might not work
    Code (Text):
    1.  
    2. on projectile hit:
    3.     send "hit"
    when you are debugging, you need to make sure that everything besides the things you are testing is working properly

    also, broadcast sends the message to console as well. if you have really long debugs, you can scroll up on your console whereas default minecraft clients have that scroll limit

    please use broadcasts over sends/messages

    A simple example is a person arguing that 'on mine' doesn't work

    Code (Text):
    1.  
    2. on mine:
    3.     if {mine} is 1:
    4.         give 1 diamond to player
    5.  
    6.  
    If we want to be sure that 'on mine' doesn't work, we can add debug messages

    Code (Text):
    1.  
    2. on mine:
    3.     broadcast "on mine called"
    4.     broadcast "{mine} is %{mine}%"
    5.     if {mine} is 1:
    6.         broadcast "{mine} = 1 condition passed"
    7.         give 1 diamond to player
    8.  
    9.  
    when they ran the code, it broadcasted

    on mine called
    {mine} is <none>

    that means, {mine} was not set at the first place


    For example, let's look at a bad code posted on the skUnity Discord
    Code (Text):
    1.  
    2. every 1 second:
    3.      loop all players:
    4.          if {kit.%loop-player%::dwarf} is 1:
    5.              if loop-player is sneaking:
    6.                  add 1 to {dwarf.timer::%loop-player%}
    7.              if loop-player is not sneaking:
    8.                  remove 2 from {dwarf.timer::%loop-player%}
    9.                  if {dwarf.timer::%loop-player%} is less than 1:
    10.                      set {dwarf.timer::%loop-player%} to 0
    11.  
    12.  
    As you can see, there can be multiple things going wrong
    • is {kit.%loop-player%::dwarf} not set?
    • is loop-player is sneaking condition working?
    • is adding 1 to {dwarf.timer::%loop-player%} working?
    • ...

    So, here is a code with debug messages
    Code (Text):
    1.  
    2. every 1 second:
    3.      loop all players:
    4.          broadcast "looping player %loop-player%"
    5.          if {kit.%loop-player%::dwarf} is 1:
    6.              broadcast "dwarf is 1"
    7.              if loop-player is sneaking:
    8.                  add 1 to {dwarf.timer::%loop-player%}
    9.                  broadcast "%{dwarf.timer::%loop-player%}%"
    10.              if loop-player is not sneaking:
    11.                  broadcast "happening"
    12.                  remove 2 from {dwarf.timer::%loop-player%}
    13.                  broadcast "%{dwarf.timer::%loop-player%}%"
    14.                  if {dwarf.timer::%loop-player%} is less than 1:
    15.                      set {dwarf.timer::%loop-player%} to 0
    16.                      broadcast "stopped"
    17.  
    18.  
    They should use lists; other than that,
    when they ran the code, it broadcasted
    looping player notch

    so that means, {kit.%loop-player%::dwarf} is not set


    [[ Step checking ]]
    The use of Functions allows us to embed multiple actions into one line. Because of this, they are prone to bugs

    For example
    Code (Text):
    1.  
    2. set {_elo} to {_k} * (1 - 1 / (1 + (10^(-1 * (({_a} - {_b}) / {_n}))))))
    3.  
    There are a number of things that can go wrong here
    So, split the thing into multiple parts

    Code (Text):
    1.  
    2. set {_awin} to {_a} - {_b}
    3. set {_aexponent} to -1 * ({_awin} / {_n})
    4. set {_aexpected} to 1 / (1 + (10^{_aexponent}))
    5. return {_k} * (1 - {_aexpected})
    6.  
    Add broadcast as much as you like

    [[ Examples ]]
    Examples are a good way of debugging things

    For example
    Let's say you want to use metadata but the code is not working
    Code (Text):
    1.  
    2. if metadata {_str} or (substring of {_wtf} from {_a} to 10) of {_p}= "{@optionsomething}":
    3.  
    Start from the examples.

    If the example was
    Code (Text):
    1.  
    2. metadata "lastchat" of player
    3.  
    Then check if the below works in the first place
    Code (Text):
    1.  
    2. command /debug:
    3.     trigger:
    4.         set {_metadata} to metadata ("lastchat" or "2ndlastchat") of player
    5.         send "%{_metadata}%"
    6.  
    And, without a doubt, that code doesn't work.
    That means you cant just use 2 values on metadata.
    That also means you cant read syntax :emoji_frowning:


    Debugging Tools
    Debugging is tedious, debugging is hard. And programmers want to automate such stuff

    [[ List debugging tool ]]
    I created a debugging tool for lists.
    It helps you inspect the layers of a list with ease

    Requires Skript 2.4+
    Code (Text):
    1.  
    2. function List_Print(node: string, layer: string="    ", list: string="", currentlayer: string="") :: strings:
    3.     # Prints a list
    4.     # example
    5.     # set {listname::*} to online players
    6.     # send List_Print("listname")
    7.     #
    8.     # do not touch list and current layer
    9.     # layer is customizeable and is defaulted to 4 spaces
    10.     set {_returnarr::1} to "%{_currentlayer}%[%{_node}%]"
    11.     set {_t} to 1
    12.     loop indices of {%{_list}%%{_node}%::*}:
    13.         add 1 to {_t}
    14.         set {_returnarr::%{_t}%} to "%{_currentlayer}%%{_layer}%%loop-value%:%{%{_list}%%{_node}%::%loop-value%}%" if {%{_list}%%{_node}%::%loop-value%} is set
    15.         if {%{_list}%%{_node}%::%loop-value%::*} is set:
    16.             loop List_Print(loop-value, {_layer}, "%{_list}%%{_node}%::", "%{_currentlayer}%%{_layer}%"):
    17.                 add 1 to {_t}
    18.                 set {_returnarr::%{_t}%} to loop-value-2
    19.     return {_returnarr::*}
    20.  
    example response
    executing 'broadcast List_Print("island")'
    [island]
    [farm]
    [admin]
    069a79f4-44e9-4726-a5be-fca90e38aaf5:Notch
    b22b0d29-ce73-4b98-8aad-f6a7aa47c1af:lilMelon
    e2016a5c-f93b-4e60-984d-d794ce853d03:Nopeful
    [config]
    [permname]
    0:banned
    1:visitor
    2:member
    3: owner
    4:admin
    [size]
    1:2
    2:4
    3:6
    [id]
    [-1]
    [setting]
    [player]
    build:4
    [0]
    [setting]
    spawnpoint:x: -12, y: 128, z: -12
    [1]
    reference:0
    [4]
    level:1
    owner:nopeless
    reference:5
    [statistic]
    createdtime:1/2/20 6:2 PM
    lastactive:1/2/20 6:2 PM
    [5]
    [children]
    4:true
    8:true
    level:1
    owner:nopeless
    [setting]
    [permission]
    df5f766e-8d62-42af-9f10-18f95e671067:3
    [player]
    ban:3
    build:2
    chest:2
    damageentity:2
    drop:2
    enter:1
    entityinteract:2
    item:2
    kick:2
    nofalldamage:1
    nofiredamage:1
    pvp:3
    redstone:2
    trample:5
    [statistic]
    createdtime:1/2/20 6:2 PM
    lastactive:1/2/20 6:2 PM
    [8]
    level:1
    owner:nopeless
    reference:5
    [statistic]
    createdtime:1/2/20 6:2 PM
    lastactive:1/2/20 6:2 PM
    [9]
    level:1
    owner:nopeless
    [setting]
    [permission]
    df5f766e-8d62-42af-9f10-18f95e671067:3
    [player]
    ban:3
    build:2
    chest:2
    damageentity:2
    drop:2
    enter:1
    entityinteract:2
    item:2
    kick:2
    nofalldamage:1
    nofiredamage:1
    pvp:3
    redstone:2
    trample:5
    [statistic]
    createdtime:1/2/20 6:2 PM
    lastactive:1/2/20 6:2 PM
    [player]
    [df5f766e-8d62-42af-9f10-18f95e671067]
    [island]
    nopeless's farm - 1:5
    nopeless's farm - 2:8
    nopeless's farm - 3:9
    nopeless's farm:4
    maxisland:100

    [[ Create your own debugging tool ]]
    Sometimes, you might want to create a debugging tool yourself, here is an example
    Code (Text):
    1.  
    2. command /debuginventory:
    3.     # sends every inventory action
    4.     trigger:
    5.         if {debug::inventory} = true:
    6.             set {debug::inventory} to false
    7.         else:
    8.             set {debug::inventory} to true
    9.         send "set debuginventory to %{debug::inventory}%"
    10.  
    11.  
    12.  
    13. on inventory click:
    14.     if {debug::inventory} = true:
    15.         send "inventory name:%inventory name of event-inventory%"
    16.         send "event-item:%event-item%"
    17.         send "event-inventoryaction:%event-inventoryaction%"
    18.         send "event-inventory:%event-inventory%"
    19.         set {_slot} to event-slot
    20.         send "event-slot:%{_slot}%"
    21.         send "event-clicktype:%event-clicktype%"
    22.         send "hotkey:%event-key%"
    23.         send "hotkey slot:%event-hotbar-slot%"
    24.         send "cursor slot:%cursor slot of player%"
    25.         send inventory name of event-inventory
    26.         send "-slot:%index of event-slot%"
    27.         send "-count:%item amount of {_slot}%"
    28.  
    This is a debugging tool I use when scripting things related to GUI

    Tips & Tricks
    [[ Skript effects ]]

    Did you know that you can run Skript™ can run effects on the fly?

    go to
    Skript/config.sk
    turn on

    Code (Text):
    1.  
    2. enable effect Commands: false
    3. to
    4. enable effect Commands: true
    5.  
    6. allow ops to use effect Commands: false
    7. to
    8. allow ops to use effect Commands: true
    9.  
    then, in a Minecraft server where you are op, try typing
    !send "hello world"
    it will say something like

    executing 'send "hello world"'
    hello world

    this feature allows you to run Functions as well
    if you are wondering what {block::1} is, just type
    !send "%{block::1}%"
    without the hassle of going to scripts and putting a command debug for that :emoji_slight_smile:

    more detail can be found here
    https://forums.skunity.com/wiki/run-effect/

    [[ Debug option ]]
    Tired of deleting broadcast every time you fixed the problem only to type it again?
    There is an easy way to toggle broadcast on these
    Code (Text):
    1.  
    2. options:
    3.     debug:broadcast
    4.  
    5. on mine:
    6.     {@debug} "on mine called"
    7.     # stuff
    8.  
    to turn it off,
    Code (Text):
    1.  
    2. options:
    3.     debug:set {_faioeal} to
    4.     # remember to set it to something that has a 0 possibility of creating conflicts
    5. on mine:
    6.     {@debug} "on mine called"
    7.     # stuff
    8.  
    [[ Debug broadcast works but code doesn't ]]

    a code from skUnity Discord
    Code (Text):
    1.  
    2. function survivalscoreboard(p: player):
    3.     send "true" to {_p}
    4.     <some effect> "World = %{_p} <some expression>%" to {_p}
    5.  
    The debug "true" gets sent but the line below doesn't.
    The person also tested the code outside the function and said it executed the second line

    This means one of 2 things are happening
    1. the second line expression bugged out for some reason
    • a) this is possible if addon developers didn't fully consider or put exception handling on their code. => Check console
    • b) this is possible if the expression doesn't work on Functions. => clearly show the code not working, issue a bug report on their respective repositories.
    2. the second line effect broke for some reason
    • a) this is possible on some Functions, where addon developers didn't fully consider the use of effects inside Functions. => try changing parameters to a fixed global variable. if that works, submit a bug issue on git.
    • b) the effect doesn't work in those particular parameters inside the function => change all parameters into global Variables and then test it inside and outside a function
      - i) if the global variable version doesn't work, it means that the object has a problem referencing/serializing the data. => submit a bug on git
      - ii) if the global variable works, test if the parameter version is the same. for example
      Code (Text):
      1. # is the object same
      2. command objtest:
      3.     trigger:
      4.         set {global} to <something>
      5.         if {global} = param({global}):
      6.             send "no problems"
      7.         else:
      8.             send "something went wrong"
      9.  
      10. function param(o: object) :: object:
      11.     return {_o}



    [[ Flawless Debug ]]
    If you are checking a string, don't broadcast the string only
    Bad example
    Code (Text):
    1.  
    2. set {_str} to substring of "whatever" from {_a} to {_b}
    3. broadcast {_str}
    4.  
    Good example
    Code (Text):
    1.  
    2. set {_str} to substring of "whatever" from {_a} to {_b}
    3. broadcast "{_str} = %{_str}%"
    4.  
    This is because if {_str} is not set(<none>), Skript will not broadcast at all, which might confuse you a lot.
    Generally a good practice to add more info when debugging


    [[ Recursive things ]]
    Using recursive features? Good! you are an above-average programmer. However, you are also putting yourself at a high risk of constantly crashing your server.
    Put delays and emergency stops on those Functions

    Bad example
    Code (Text):
    1.  
    2. function factorial(n: number) :: number:
    3.     return 1 if {_n} = 1
    4.     return {_n} * factorial({_n} - 1)
    5.  
    Good example
    Code (Text):
    1.  
    2. function factorial(n: number) :: number:
    3.     stop if {emergencystop} = 1
    4.     wait 1 tick
    5.     return 1 if {_n} = 1
    6.     return {_n} * factorial({_n} - 1)
    7.  
    If you are so confident that it will never break, you can safely remove those delays and stops
    However, it is crucial when developing


    [[ Types ]]
    Skript Variables have types. strings, integers(longs), booleans, etc. But there seems to be virtually no way to test the type of the variable, right?

    Rezz created a snippet that allows you to inspect the type of a variable. https://forums.skunity.com/threads/rezzs-snippets-things-you-can-do-in-pure-skript-2-2.2471/ <- original link. All credits to Rezz
    Code (Text):
    1.  
    2. options:
    3.  
    4.     DATA: Skript-types
    5.  
    6. function declareUsableType(addon: text, user-input: text):
    7.  
    8.     set {_type} to {_user-input} parsed as type
    9.  
    10.     {_type} is set
    11.  
    12.     add {_type} to {{@DATA}::types::*}
    13.     set {_index} to amount of {{@DATA}::types::*}
    14.  
    15.     set {{@DATA}::type-of::%{_user-input}%} to {_type}
    16.     set {{@DATA}::user-input-of::%{_type}%} to {_user-input}
    17.     set {{@DATA}::index-of::%{_type}%} to {_index}
    18.  
    19.     add {_index} to {{@DATA}::addons::%{_addon}%::types::*}
    20.  
    21.     if {{@DATA}::addons::%{_addon}%} isn't set:
    22.  
    23.         set {{@DATA}::addons::%{_addon}%} to {_addon}
    24.  
    25. function declareUsableTypes(addon: text, types: Texts):
    26.  
    27.     loop {_types::*}:
    28.         declareUsableType({_addon}, loop-value)
    29.  
    30. on script load:
    31.  
    32.     delete {{@DATA}::*}
    33.  
    34.     set {{@DATA}::object-type} to "object" parsed as type
    35.  
    36.     # Data Types
    37.     declareUsableTypes("Skript", ("type", "boolean", "integer", "number", and "text"))
    38.  
    39.     # Players & Entities
    40.     declareUsableTypes("Skript", ("player", "offline player", "command sender", "living entity", "entity", and "projectile"))
    41.  
    42.     # Blocks & Locations
    43.     declareUsableTypes("Skript", ("block", "location", "vector", and "direction"))
    44.  
    45.     # Worlds
    46.     declareUsableTypes("Skript", ("biome", "chunk", "world", and "weather"))
    47.  
    48.     # Items & Inventories
    49.     declareUsableTypes("Skript", ("item", "item type", "potion effect", "inventory", "slot", "inventory action", and "click action"))
    50.  
    51.     # Enchantments
    52.     declareUsableTypes("Skript", ("enchantment", and "enchantment type"))
    53.  
    54.     # Time
    55.     declareUsableTypes("Skript", ("time", "timespan", "timeperiod", and "date"))
    56.  
    57.     # Misc
    58.     declareUsableTypes("Skript", ("gamemode", "damage cause", "color", "tree type", and "particle effect"))
    59.  
    60. on script unload:
    61.  
    62.     delete {{@DATA}::*}
    63.  
    64. function typeof(var: object) :: type:
    65.  
    66.     loop {{@DATA}::types::*}:
    67.         if {_var} is loop-value:
    68.             return loop-value
    69.     return {{@DATA}::object-type}
    70.  
    typeof(<variable>) returns type
    - Returns the variable's type, or 'object' if its type isn't declared.
    declareUsableTypes(<addon name>, <list of types>)
    - Declare all types listed in their user-input form. This function simply calls declareUsableType() on each list item.

    declareUsableType(<addon name>, <type in standard user-input form>)
    - Declare a usable type. It's important to declare specific types before general types because declaration order is preserved. i.e. A variable of a specific type, like 'player', can also be considered a more general type as well -- 'offline player' in this example. If 'offline player' is declared before 'player', 'player' type Variables will always be considered 'offline players'.

    You can check more details and examples on the link

    [[ Console ]]
    If your code creates errors on console, believe it or not, it's actually a good sign. You can find the problem of your code by reading the error logs

    Here are some common bugs and how to fix them
    • NullPointer
      - this usually happens when the variable you put inside the function as an argument is not set. Also, see array out of bounds exception
    • OutOfBounds
      - this happens when you put 2 values in 1 argument when you are only allowed to put 1. This is not your fault. Skript tries to create lists whenever they see a comma. To fix this problem, add parentheses. ex) func(1, 2, 3) -> func((1), (2), (3))
    • TypeError
      - this happens when you have the incorrect type. Some of them are unintuitive. If you get "expected integer but number", add round({_thevariable}) to it. Some other TypeErrors are hard to fix but if you encounter them, please shorten your code so the error can be explicit
    • IllegalArgument
      - you entered an argument that is out of the range of that function. For example, you cant set slot 100 of an inventory
    • StackOverflow
      this is a rare error. but most fall into 2 categories
      - lack of ram: simply give your server more ram
      - recursive function: there is a recursive function in your code that isn't working properly.
    Common mistakes
    just some common mistakes from people

    [[ Color ]]
    - bold, italics don't show -> color codes reset Formatting. if you want do disable it, go to the Skript config
    - color does not change to Minecraft color doe -> use colored expression
    [[ List ]]
    - lists don't work properly -> lists are probably not what you think. read above and get listprint
    - list keeps deleting after restart -> are you sure you don't have a "clear {list::*}" somewhere
    - list is not ordered -> list's indices are not what you think. read above and get listprint
    - adding stuff to lists is slow -> adding is slow. use set and Loops instead
    [[ Addons ]]
    - using skquery, wild Skript, umbaska, skrayfall -> just no
    - using Skript-mirror for simple stuff -> why
    idk ill add more if i see more

    Addition to things
    Something is wrong? Want to contribute to this page? PM me on this account with details, I will update it.



    Update log
    - 2020/1/23 : Created page
    - 2020/2/5 : added [ Debug sends but code doesn't work ]
    - 2020/2/25 : edited format so it looks better
    - 2020/2/29 : added Skript effects tutorial
    - 2020/3/1 : added more information
    - 2020/5/30 : added common mistakes section
Ris, Runakai and nope like this.