Skip to content

Anti-cheat

Anti-cheat

Every money and stock decision is made on the server. The client draws the pump and reports what happened; it never decides what anything costs or how much went in.

What the server enforces

  • Pump sessions. Opening a pump asks the server for a session token. Paying requires that token, and the litres billed are capped by how long the session was actually open at the configured flow rate. A client claiming more than the pump could physically have delivered is trimmed to what the clock allows.
  • Session expiry. Tokens are single-use, tied to the player who opened them, and thrown away after PumpSessionTimeout. An expired session bills nothing.
  • Distance checks. Buying, refuelling, charging, swapping a battery, filling a can, ordering stock and every dashboard action re-check on the server that the player is really at that station, with DistanceSlack metres of margin for ped position lag.
  • Rate limiting. Every event and callback costs a token from a per-player bucket that refills at PerSecond and never stacks past Burst. A stuck keybind still works; a spam loop hits a wall almost immediately.
  • Value clamping. Prices, wages, orders, withdrawals and deposits are all bounds-checked and type-checked server-side. Nothing above MaxAmount is accepted at all, and prices are held inside Config.Refuel.PriceLimits.
  • Permission checks on every action. Staff permissions are re-verified server-side per request, never trusted from the UI. Hiring, firing and editing anyone who holds the employees permission is owner-only, so an employee cannot promote themselves. Transfer and sell-back are owner-only and require the station name typed back.
  • Stock and bank are server state. A sale only happens if the station actually has the litres and the customer actually has the money; both sides move in the same server-side step.
config.lua
Config.AntiCheat = {
    RateLimit = { Burst = 14, PerSecond = 6 },
    MaxLitresPerPay = 200.0,
    LitreGrace = 3.0,
    PumpSessionTimeout = 900,
    DistanceSlack = 15.0,
    MaxAmount = 100000000,
    MaxWage = 25000,
    JerryPourTimeout = 600,
}
Setting Purpose
RateLimit Burst size and refill rate of the per-player event bucket
MaxLitresPerPay Hard ceiling on a single pump or charger session, whatever the timing says
LitreGrace Slack on the timing check, in litres. Covers a laggy tick
PumpSessionTimeout Seconds a session stays valid
DistanceSlack Extra metres allowed on top of a station's radius
MaxAmount Ceiling on any money value accepted from a client
MaxWage Highest wage an owner can put on an employee
JerryPourTimeout Seconds an unfinished pour is remembered before the leftover can no longer be claimed back

Tuning

The defaults suit a normal server. The two worth touching:

  • LitreGrace — raise it a litre or two if players on bad connections are being short-changed at the pump. Keep it small; it is free fuel.
  • RateLimit.Burst — raise it if a legitimately busy forecourt starts refusing actions. Lower it if you want a tighter leash.

Loosening MaxLitresPerPay or DistanceSlack a long way removes the ceiling those checks exist to provide. Only change them if honest players are visibly being blocked.