Accumulators
An accumulator
is a special type of field that can store a sortable number on a player entity
persistently between games. It is used for generating ranked leaderboards.
pub accumulator owner.NumLifetimeGames
pub game fn World.Main() {
SpawnEachPlayer owner {
NumLifetimeGames(delta=1, showOnLeaderboard=true)
}
}
pub page fn owner.HomePage() {
Content {
P { "Loading leaderboard..." }
}
let leaderboard = await FetchLeaderboard([&NumLifetimeGames])
Content {
for player in leaderboard %%{
P {
%(player.PlayerName + " has played " + player.NumLifetimeGames + " games")
}
}
}
}
Declaration
Every accumulator must have a subject parameter, and the subject parameter must be owner
,
representing the player who owns the accumulator.
The accumulator's name must begin with an uppercase letter.
accumulator owner.NumLifetimeGames
An accumulator may optionally be given an initial value.
accumulator owner.Rating = 1000
Accumulators can be declared as public using the pub
keyword,
which allows them to be accessed from all files in the program.
Otherwise they are private and can only be accessed from within the same file.
It is not possible to have two accumulators with the same name, even if they are both private and in separate files.
Doing so will generate a compiler error.
This is because the accumulator name forms a globally unique key
which is used to look up the value from persistent storage.
pub accumulator owner.NumLifetimeGames = 0
Reading an accumulator
An accumulator can be read the same way as any other property:
let value = Rating // implicit subject
let value = owner.Rating // or explicit subject
The subject parameter owner
must be either a player entity,
or one of the map
entries returned by FetchLeaderboard
.
It is possible to await
on an accumulator to detect when it changes.
Like all other await
functions, it is possible to use with
, on
or once
to handle the change.
with Rating {
Transmission {
P { "Your current rating: " + Rating }
}
}
Modifying an accumulator
Accumulators can are modified by calling them as a function.
Let's say we have defined an accumulator called ExampleAccumulator1
:
pub accumulator owner.ExampleAccumulator1 = 0
ExampleAccumulator1
can be called as a function to increase, decrease or overwrite its value.
The signature for calling an accumulator is as follows:
owner.ExampleAccumulator1(overwrite?, delta?, revertAfter?, resetAfter?, resetInterval?, showOnLeaderboard?)
owner
(Entity): must refer to the player entity that owns the accumulator. If it is nullish, will do nothing.overwrite
(Number): if specified, will set the accumulator to this value.delta
(Number): if specified, will increase or decrease the accumulator by this amount.revertAfter
(Number): if specified, will revert the delta after this duration. This would normally be specified in minutes, hours or days. For example30m
,4h
,30d
. Reversions are processed once every minute by the server, and so any duration smaller than that will not happen exactly on time.resetAfter
(Number): Schedules the accumulator to be reset to its initial value after this duration. A nullish value means the accumulator will never be reset to its initial value. This replaces any previously-defined scheduled reset. This parameter would normally be specified in minutes, hours or days. For example30m
,4h
,30d
. Resets are processed once every minute by the server, and so any duration smaller than that will not happen exactly on time.resetInterval
(Number): Schedules the accumulator to be reset to its initial value after this duration. If there is already a reset scheduled, this does nothing unless the new interval is shorter. If this parameter is nullish, deletes any previously-defined scheduled reset.showOnLeaderboard
(Boolean or Number): if specified, will include the player in any calls to FetchLeaderboard for this duration. Iftrue
, will show on the leaderboard permanently. If a Number, will show on the leaderboard for that duration.
Leaderboards
When modifying an accumulator by calling it as a function,
there is a showOnLeaderboard
parameter, which determines whether
the player will be included when in the leaderboard for that particular accumulator.
If the showOnLeaderboard
parameter is set to true
or false
, the player will be included or excluded
from the leaderboard permanently until the value is changed.
However, it is also possible to limit the player to be shown on the leaderboard for a particular duration
by passing a duration value to the showOnLeaderboard
parameter.
Players are expired from the leaderboard every minute by the server,
and so durations much smaller than one minute will not happen exactly on time.
// add 5 rating, and show on leaderboard forever
Rating(delta=5, showOnLeaderboard=true)
// add 5 rating, and show on leaderboard for 30 days
Rating(delta=5, showOnLeaderboard=30d)
The FetchLeaderboard function is used to retrieve a list of players sorted by their accumulator values. It takes a list of accumulators to order by. The player must be included in the leaderboard for the first accumulator to be included in the list. The remaining accumulators are only used as tiebreakers. The leaderboard is always sorted from highest to lowest.
FetchLeaderboard
returns an array
of map
s,
where each map contains a PlayerName
and UserId
field,
as well as a field for each accumulator.
let leaderboard = await FetchLeaderboard([&Rating])
for player in leaderboard %%{
P {
%(player.PlayerName + " has " + player.Rating + " rating and " + player.NumLifetimeGames + " games")
}
}
Scoreboards
The Scoreboard function causes the game to display a list of currently online players and their accumulators.
pub game fn World.Main() {
StatusContent {
H3 { "Most Games" }
Scoreboard(&NumLifetimeGames)
}
}