-
Notifications
You must be signed in to change notification settings - Fork 0
Examples
Complete scripts you can copy. Every one of these was run on a real three server network first.
Put them in plugins/Skript/scripts/ on each server, or push them from the proxy with
script sharing so one copy runs everywhere.
Balances follow the player everywhere. The starting balance is given once for the whole network, whichever server sees them first.
on join:
if network is not synced:
stop
atomically set {?eco::bal::%player%} to 500 if it is not set
atomically add 1 to {?eco::joins::%player%}
command /bal [<offline player>]:
trigger:
set {_target} to arg-1 ? player
send "&e%{_target}%&7: &a$%{?eco::bal::%{_target}%} ? 0%"
command /pay <offline player> <number>:
trigger:
if arg-2 <= 0:
send "&cAmount must be positive."
stop
if arg-1 is player:
send "&cYou cannot pay yourself."
stop
atomically remove arg-2 from {?eco::bal::%player%} without going below 0 and wait
if the atomic change was refused:
send "&cNot enough money: %the atomic error%"
stop
if the atomic change timed out:
send "&cThe network is slow. Check your balance before trying again."
stop
atomically add arg-2 to {?eco::bal::%arg-1%} and wait
if the atomic change succeeded:
send "&aSent $%arg-2% to %arg-1%. You have $%{?eco::bal::%player%}% left."
else:
# put it back, the other half did not go through
atomically add arg-2 to {?eco::bal::%player%}
send "&cCould not send that. Your money was returned."/pay shows the careful shape. Take the money first with a floor, add it to the other
player only once that succeeded, and put it back if the second half fails.
command /price <text> <number>:
permission: skript.admin
trigger:
set {?shop::price::%arg-1%} to arg-2
send "&a%arg-1% now costs $%arg-2%"
command /buy <text>:
trigger:
set {_price} to {?shop::price::%arg-1%}
if {_price} is not set:
send "&cNo such item."
stop
atomically remove {_price} from {?eco::bal::%player%} without going below 0 and wait
if the atomic change succeeded:
give player 1 of arg-1 parsed as item type
send "&aBought %arg-1% for $%{_price}%. Balance: $%the atomic result%"
else if the atomic change timed out:
send "&eThe network did not answer. Check your balance before buying again."
else:
send "&cCould not buy: %the atomic error%"Two servers running this at once can't both succeed on the last coin. Tested with three servers, 20 purchases each, one balance of 30: 30 sold, 30 refused, balance 0.
skNetwork keeps this list for you, so the short version is:
command /netlist:
trigger:
send "&e-- Network --"
loop all network servers:
send "&f%loop-value% &7(%size of network players on loop-value%)&7: %network players on loop-value%"
command /find <text>:
trigger:
set {_where} to network server of arg-1
if {_where} is set:
send "&a%arg-1% is on %{_where}%."
else:
send "&c%arg-1% is not online."The proxy rebuilds that list from what each server reports, so a crash takes the server's players out of it by itself. See Network players.
The long version below keeps the list in a variable. It still works, and it shows the pattern for any per server list you keep yourself.
on network sync:
delete {?online::%network server name%::*}
loop all players:
add loop-player's name to {?online::%network server name%::*}
on join:
add player's name to {?online::%network server name%::*}
on quit:
remove player's name from {?online::%network server name%::*}
command /netlist:
trigger:
send "&e-- Network --"
send "&flobby &7(%size of {?online::lobby::*}%)&7: %{?online::lobby::*}%"
send "&flobby2 &7(%size of {?online::lobby2::*}%)&7: %{?online::lobby2::*}%"
send "&fsurvival &7(%size of {?online::survival::*}%)&7: %{?online::survival::*}%"
command /find <text>:
trigger:
loop "lobby", "lobby2" and "survival":
loop {?online::%loop-value-1%::*}:
if loop-value-2 is arg-1:
send "&a%arg-1% is on %loop-value-1%."
stop
send "&c%arg-1% is not online."Note the nested loop. You can't write {?online::*::*}, because Skript only allows a *
at the very end of a name. List the servers you have, or keep a second variable saying
where each player is, like the stats example below.
The on network sync block is what makes this survive a crash. A server that dies never
runs on quit, so its players would stay listed forever.
One file, pushed to every server. It works on each one because it asks where it's running.
on join:
set {?stats::server::%player%} to network server name
set {?stats::seen::%player%} to now
on quit:
set {?stats::seen::%player%} to now
on death of player:
atomically add 1 to {?stats::deaths::%victim%}
if attacker is a player:
atomically add 1 to {?stats::kills::%attacker%}
atomically add 50 to {?eco::bal::%attacker%}
command /stats [<offline player>]:
trigger:
set {_t} to arg-1 ? player
set {_u} to {_t}
send "&e%{_t}%"
send "&7kills &f%{?stats::kills::%{_u}%} ? 0%&7 deaths &f%{?stats::deaths::%{_u}%} ? 0%"
send "&7last on &f%{?stats::server::%{_u}%} ? "unknown"%&7 at &f%{?stats::seen::%{_u}%} ? "never"%"Use atomically add for the counters. Two servers can kill the same player at nearly the
same moment, and a plain add 1 would lose one of them.
command /daily:
trigger:
set {_today} to now formatted as "yyyy-MM-dd"
atomically set {?daily::%player%} to {_today} if it is not set and wait
if the atomic change succeeded:
atomically add 100 to {?eco::bal::%player%} and wait
send "&aFirst daily reward. +$100, balance $%the atomic result%"
stop
set {_last} to {?daily::%player%}
if {_last} is {_today}:
send "&7You already claimed today. Come back tomorrow."
stop
atomically set {?daily::%player%} to {_today} if it is "%{_last}%" and wait
if the atomic change succeeded:
atomically add 100 to {?eco::bal::%player%} and wait
send "&aDaily reward. +$100, balance $%the atomic result%"
else:
send "&eSomeone claimed that on another server a moment ago."The second form matters. Two servers could both see yesterday's date and both pay out. By saying "change it to today only if it's still yesterday", exactly one wins.
An event, an arena, a boss spawn. Only one server should run it.
command /claim <text>:
trigger:
atomically set {?lock::%arg-1%} to network server name if it is not set and wait
if the atomic change succeeded:
send "&a%network server name% now holds %arg-1%"
else:
send "&e%arg-1% is already held by %{?lock::%arg-1%}%"
command /release <text>:
trigger:
atomically set {?lock::%arg-1%} to "free" if it is network server name and wait
if the atomic change succeeded:
delete {?lock::%arg-1%}
send "&aReleased %arg-1%"
else:
send "&cThat is not ours to release: %the atomic error%"release uses the compare form so one server can't release a lock another server holds.
command /kit:
trigger:
set {_now} to unix timestamp of now
set {_last} to {?cooldown::kit::%player%}
# first time ever: the variable does not exist, so use the "not set" form
if {_last} is not set:
atomically set {?cooldown::kit::%player%} to {_now} if it is not set and wait
if the atomic change succeeded:
give player 1 diamond sword
send "&aHere is your kit."
else:
send "&cYou just claimed that on another server."
stop
if {_now} - {_last} < 3600:
set {_left} to 3600 - ({_now} - {_last})
send "&cWait %{_left}% more seconds. Switching servers will not help."
stop
atomically set {?cooldown::kit::%player%} to {_now} if it is {_last} and wait
if the atomic change succeeded:
give player 1 diamond sword
send "&aHere is your kit."
else:
send "&cYou just claimed that on another server."Two details here are easy to get wrong, and both turned up in testing.
The first claim needs the if it is not set form. The if it is ... form can never
succeed against a variable that doesn't exist yet, so a player's very first /kit would
always be refused.
The comparison uses {_last}, not "%{_last}%". Wrapping it in a string turns a number
into text, and the proxy compares exactly, so text never matches a stored number.
Every server pushes the same file, and /hub moves the player to the lobby unless
they're already there or it's down.
command /hub:
trigger:
if network server "lobby" is not online:
send "&cThe lobby is down right now."
stop
if network server name is "lobby":
send "&eYou are already in the lobby."
stop
send "&7Sending you to the lobby..."
connect network player "%player%" to "lobby"The two checks come first because connect does nothing when the target is missing,
and a player would otherwise wait for a move that never comes.
The /pay from the economy example, with the receiver told wherever they are.
command /pay <offline player> <number>:
trigger:
if arg-2 <= 0:
send "&cAmount must be positive."
stop
set {_where} to network server of "%arg-1%"
if {_where} is not set:
send "&c%arg-1% is not online anywhere."
stop
atomically remove arg-2 from {?eco::bal::%player%} without going below 0 and wait
if the atomic change was refused:
send "&cNot enough money: %the atomic error%"
stop
if the atomic change timed out:
send "&cThe network is slow. Check your balance before trying again."
stop
atomically add arg-2 to {?eco::bal::%arg-1%} and wait
if the atomic change succeeded:
send "&aSent $%arg-2% to %arg-1% on %{_where}%."
send network message "&a%player% sent you $%arg-2%. You now have $%the atomic result%." to network player "%arg-1%"
else:
atomically add arg-2 to {?eco::bal::%player%}
send "&cCould not send that. Your money was returned."The receiver gets the message on whichever server they're standing on. If they logged off in the meantime, the money still arrived and only the message is lost.
One server changes a score, every server sees it change, without polling.
on network variable change of "score::*":
set {_team} to the last element of the changed variable split at "::"
broadcast "&6%{_team}% &7now has &f%the new value% &7points (was %the old value% ? 0)"
command /score <text> <number>:
permission: skript.admin
trigger:
atomically add arg-2 to {?score::%arg-1%}the old value is right even on the server that ran /score, because the proxy
supplies it. Reading the variable yourself inside the event would already show the new
number there.
on network disconnect:
broadcast "&cLost the network. Money and stats are read only for now."
on network sync:
broadcast "&aNetwork is back."
command /netstatus:
trigger:
if network is synced:
send "&aNetwork is up. This server is %network server name%."
else:
send "&cNetwork is down. Values you see may be out of date."Everything that touches the network on join, in the order that works.
on join:
if network is not synced:
send "&eThe network is still starting up. Some things may not work yet."
stop
atomically set {?eco::bal::%player%} to 500 if it is not set
atomically add 1 to {?eco::joins::%player%}
set {?stats::server::%player%} to network server name
add player's name to {?online::%network server name%::*}
wait 1 tick
send "&aWelcome back. Balance: $%{?eco::bal::%player%} ? 500%"The guard at the top isn't optional. Before the first sync every is not set check says
yes, so without it this hands a fresh 500 to a player who already has money.
# reading then writing, on a network
if {?coins::%player%} >= 100:
remove 100 from {?coins::%player%}Both servers read the old value and both subtract. Use atomically remove ... without going below 0.
# writing every tick for every player
every tick:
loop all players:
set {?pos::%loop-player%} to location of loop-playerEvery one of those is a message to the proxy. This slows the whole network down. Write on a real event instead, or every few seconds at most.
# reading a value you just changed
atomically add 50 to {?coins::%player%}
send "You have %{?coins::%player%}%"The second line usually prints the old number. Add and wait and use
the atomic result.
# deleting a huge list while players are online
delete {?bigdata::*}The proxy checks every variable it holds to do this, and nothing else is written while it works. Do it at a quiet time.
- Syntax reference for every pattern on one page.
- Atomic changes for the atomic forms in full.
- Network players for messaging, moving and looking players up.
- Sync and events for the startup rules and the events.
- Limitations for what won't work at all.
Guides
Reference