Skip to content

OnPlayerProgressViolation

The server found progress it cannot explain and is about to put it back - return false to vouch for it.

A player’s game reported XP, a level, perk points or a perk that nothing the server knows of explains: not what the game awarded, not what the mode gave, not a potion or a perk, not the points their levels pay. With [audit] mode = "enforce" the server is about to put it back; with observe it only logs that it would, and asks all the same for XP and levels. Nothing reaches the player’s game before this returns. It is asked once for each excess, after the server has seen it a second time (about a second and a half later), and not again when it repeats. kind says what:

  • "xp" - a stat’s or skill’s XP, "level" - a level that rose with it (an XP or a level the game could never hold is one of these too);
  • "points" - perk points the levels do not pay for (asked only where the rule acts: under enforce);
  • "perk" - a perk bought without a point to pay for it, or below the level it needs (this version does not judge these yet, so it is not asked);
  • "baseline" - a game that joined with more than a fresh character holds. It is asked in both audit modes, but this version puts nothing back for it; a false makes the server take the reported value as the player’s own.

name is the lower-case stat, skill or perk name (for a perk below its level, the perk’s GUID). reported is what the player’s game says and allowed what the server can explain: for "xp" and "level" the XP counted over all the levels together, for "points" the number of points.

Return false to vouch: the server takes the reported value as the player’s progress, and nothing is put back. That is the way for progress the server cannot see being earned - a teacher or trainer the mode runs, an event’s reward, and above all quest XP on a server with story quests on, where the story’s quests, lessons and scripts hand out XP and levels the server never sees. Without a vouch it is put back like any other excess once the check acts under enforce. Return nothing (or true) to let it be put back. Under enforce, a vouch is announced like progress the player’s game earned: a level that rose reaches OnPlayerLevelUp and the change reaches OnPlayerProgressChange with levels true. At most 8 calls come in a burst and 30 a minute for one player; past that the excess is put back without asking, so answer from memory, never from a database query.

Where the check acts, the record - GetPlayerStat, GetPlayerProgress and the rest - holds the figure the server explains, so a mode that saves characters never saves the forged value, and OnPlayerLevelUp never announces a level that was put back.

function OnPlayerProgressViolation(pid, kind, name, reported, allowed)
-- ...
end
Parameter Type
pid number the player
kind string "xp", "level", "points", "perk" or "baseline"
name string the stat’s, skill’s or perk’s lower-case name
reported number what the player’s game says (the XP over all levels together, the number of points)
allowed number what the server can explain, in the same unit

false vouches for it - the server takes the reported value; nothing or true lets it be put back

-- the apothecary's lessons give XP the server does not see: vouch for them while one runs; nothing else is vouched for
function OnPlayerProgressViolation(pid, kind, name, reported, allowed)
Log(string.format("progress: %s %s %s says %.0f, explained %.0f", GetPlayerName(pid), kind, name, reported, allowed))
if kind == "xp" and name == "alchemy" and GetPlayerData(pid, "in_lesson") then return false end
end

OnPlayerCheatDetected · GetPlayerProgressAudit · OnPlayerProgressChange · SetPlayerProgress · SetStoryQuests · the Stats, skills, XP and perks group of the index