Login
Create

Help, my server is crashing! A guide on how to improve server stability for your codes Last updated December 30, 2020

This tutorial will serve as a guide to improve the stability of your codes and to prevent it from crashing. The workshop provides a lot of super useful tools, but start to use too many of them at once and suddenly things will start crashing.

We will go over several ways to improve stability, hopefully at least one will be of use to you.

Index

Disabling the inspector

A common way for long-running gamemodes to crash is because they did not disable the inspector (mostly seen in cookie clicker, RPGs, etc).

In any kind of gamemode, if you have finished debugging and are releasing the gamemode, you should execute the Disable Inspector() action.

Waitless loops

A waitless loop is when you use any kind of loop without a Wait action. For short loops this can be alright. For example, looping over 10 array elements without any waits will be just fine. But loop over 50 array elements and things will start getting out of control. Or worse yet, loop infinitely and your server will crash without a doubt.

Example of a waitless loop:

For Global Variable(A, 0, 100, 1);
  Small Message(All Players(All Teams), Custom String("I'm looping!"));
End;

This will loop 100 times in just 1 frame, likely crashing your server.

Another example is with using Loop if.

rule("Looping") {
  conditions {
    Is Button Held(Event Player, Button(Interact)) == True;
  }

  actions {
    Small Message(All Players(All Teams), Custom String("I'm looping!"));
    Loop If Condition Is True;
  }
}

This will show a Small Message while holding down Interact and do it again if you're still holding the button. It doesn't matter how short you hold that button for, it will execute hundreds of times before you have a chance to let go, resulting in a crash.

If you're running a loop for multiple players at once keep in mind that this will be far more stressing on the server. 1 Loop running on 12 different players will be very taxing. In which case you will most definitely want to use a Wait action.

How to fix

The easiest way to solve this is to add a Wait action to your loop. It doesn't matter how short, anything will help tremendously. It doesn't matter where you add this wait, but typically you will want to add it just before the end of the loop.
If you do necessarily need things to happen at the same time you could considering batching your actions. For example, loop over something 20 times, then wait for least amount of time possible (0.016 seconds), and then continue your loop.

< Your actions >

Global.batch++
if Global.batch == 20
  Wait(0.016)
  Global.batch == 0
end

Condition ordering

Condtion order matters! Let's go in to an example before anything else;

rule("I'm alive") {
  conditions {
    Is Button Held(Event Player, Button(Interact)) == True;
    Is Alive(Event Player) == True;
  }
}

rule("I'm dead") {
  conditions {
    Is Button Held(Event Player, Button(Interact)) == True;
    Is Dead(Event Player) == True;
  }
}

Here we have 2 rules, one that fires if we hold Interact and are alive, and one that fires if we hold Interact and are dead.
Condtions are handled in order. This means that in this case if we hold Interact both rules will need to be checked, even though we know for sure only one of them can fire, since we can't be both dead and alive.
With this in mind we would want to swap both conditions around. With the least frequently changing condition first. Of course this example is super simple and the order will not make a noticable difference. But imagine if you have 100 rules, each triggered by holding Interact as the first condition, but with other conditions for each rule. Now when you hold Interact 100 rules will need to be checked all at once.

Another example might be with complex calculations. Let's imagine we have an array with 100 different positions. If the player is standing on one of those positions and is holding Interact something happens.

Is True For Any(Global.PositionsArray, Distance Between(Current Array Element, Event Player) <= 2) == True;
Is Button Held(Event Player, Button(Interact)) == True;

The first condition is constantly checking if we are on any of the 100 positions. In reality it only needs to check our position when we are holding down the button. But since we've put this condition first it will check regardless, and only when we've reached a position will it check if we're also holding down Interact. We would want this to be the other way around, which we can easily do by swapping the order of the conditions.
How we currently have it might also work just fine when you're on your own, but with 12 players, and with a bunch more rules going on, condition order will have a huge impact.


Event types

Let's imagine we have a rule and we want to check if a player is playing as Mercy. We could do this with a condition like so;

rule("Is Mercy") {
  event {
    Ongoing - Each Player;
    All;
    All;
  }
  conditions {
    Hero Of(Event Player) == Hero(Mercy);
  }
}

And this will work just fine. But alternatively, we could use some of the properties the Ongoing - Each Player event gives us, like so:
Is playing as Mercy example image

rule("Is Mercy") {
  event {
    Ongoing - Each Player;
    All;
    Mercy;
  }
}

Realistically this will be a small difference in performance and it won't be the make or break point between your server crashing and not crashing, but hey, every little bit helps.


Too many actions

The server can only handle so many actions at once (the exact number will completely depend on what you're doing). Let's say we have a gamemode, and when you press Interact a whole bunch of stuff starts happening. You're initialising all sorts of variables, you're teleporting all players, etc. You end up with over 20 actions in 1 rule. All these actions will try to execute in the same frame. Meaning they will essentially all try to execute before moving on to whatever is next.

The solution here is simple; add a Wait action! After a certain number of actions, simply add a short wait. Anything goes, no matter how short.


Too many conditions at start up

Is your server crashing right from the start? You may have too many conditions that need to be checked at the start. When the server first starts it will need to go by every single rule and check all of their conditions. If you have 100+ rules this may start to be a problem.

In some cases this can be difficult to fix, but there's a few things you can try.

  • Defer expensive actions to a later point. If you have rules that for example create HUDs, In-World text, or simply set a variable, consider delaying them a little bit. For example only initiate them when the player has actually spawned. Or simply add a start Wait.
  • Make sure expensive conditions that don't need to be checked yet don't get checked yet. Chances are you have some expensive conditions (with complex calculations or checking large arrays) that don't need to be checked the very second the server starts. Hide them behind other conditions that are definitely not true at start up so these more expensive condition don't need to be checked. Refer back to Condition Order for more info. You could use conditions such as Total Time Elapsed or Number Of Living Players to defer these rules to when they are actually needed.
  • Merge multiple rules in to 1. You might be able to get away with merging rules with similar conditions in to 1, and using If Else statements in the actions instead. These If Else actions are more expensive, but if all you need is more headroom at start up, this could be an option.

Anti-crash rules

A way to reduce the chance of crash is to use anti-crash rules. It works by setting slow motion if the server load goes past a certain threshold ; slow motion lowers the tick rate, letting the server with more time to do the calculations.

variables
{
    global:
        127: antiCrashActivated
}

rule("anti crash") {
    event  {
        Ongoing - Global;
    }
    conditions {
        Global Variable(antiCrashActivated) == False;
        Server Load > 230;
    }
    actions {
        Wait(1, Abort When False);
        Small Message(All Players(All Teams), Custom String("Anti crash system activated", Null, Null, Null));
        Set Slow Motion(10);
        Set Global Variable(antiCrashActivated, True);
    }
}
rule("disable anti crash") {
    event {
        Ongoing - Global;
    }
    conditions {
        Global Variable(antiCrashActivated) == True;
        Server Load < 200;
    }
    actions {
        Set Slow Motion(100);
        Set Global Variable(antiCrashActivated, False);
    }
}

Although this is not a silver bullet (as your players might not like playing at 10% speed), it is very useful to prevent crashes due to spikes in load (eg if too many players use your custom ability at the same time).

Elo Hell Logo_H-M-Dark
Join the Elo Hell Workshops Discord