← Okami Persistent Rank Decay · All mods

Okami Persistent Rank Decay

Persist Conflict-style ranks to disk, with optional decay when a scenario ends or over real time.

Okami Squadron emblem

Overview

Okami Persistant Rank Decay saves each player’s campaign rank to the server profile and restores it after authentication. It can also lower stored ranks when a match ends (scenario-end decay) and/or on a timer based on how long it has been since the last anchor time (time decay).

Typical uses: keep XP/rank progression across sessions on a dedicated Conflict-style server, soften rank inflation with per-round or idle decay, or both.

Use this page as the canonical reference for settings.json, profile paths, and behavior.

Requirements

  • Arma Reforger 1.6+
  • Rank / time decay (save, audit restore, timed decay): the server game mode must expose the usual XP + rank pipeline: SCR_XPHandlerComponent on the game mode entity and a faction manager (used for rank XP thresholds). The mod initializes from SCR_BaseGameMode so any derived mode that has that pipeline can use persistence and time decay — not only campaign.
  • Scenario-end decay (when a round/match ends): only runs on SCR_GameModeCampaign, because the match-finished RPC used for that path exists there.
  • Server-side load; rank files and settings live under the server profile ($profile:)

Server initialization (hooks and timing)

The mod registers OnRankChanged, starts the optional time-decay loop, and wires audit restore only after the XP/rank pipeline exists. Init is driven from two places:

SourceBehavior
SCR_BaseGameMode (mod)On EOnInit, schedules the first InitServer call after 2 seconds. That delay gives campaign and replicated sessions time to attach SCR_XPHandlerComponent and a faction manager. Non-campaign modes that never use campaign still rely on this path.
SCR_GameModeCampaign (mod)On EOnInit, after super, calls ResetAndInit(): clears all mod static state (including the “hooks already registered” flag, profile priming, retry counters, and time-decay tick bookkeeping), then runs InitServer() immediately. This fixes Workbench → Reload Game, where script static variables can survive between reloads and previously blocked registration.

Pipeline wait: if the pipeline is not ready yet, InitServer retries every 500 ms, up to 240 attempts (about 2 minutes), then logs an error and stops trying for rank save / restore / time decay (scenario-end decay can still run).

Logging: every call to InitServer prints one line with authority, hook-registration flag, retry count, and whether HasXpRankPipeline() is true. If hooks are already registered (e.g. a second scheduled call), it logs that and returns. You do not need debugLogging for these init lines.

Rank hook: the mod uses Remove(OnRankChanged) then Insert(OnRankChanged) on SCR_CharacterRankComponent.s_OnRankChanged so Workbench reloads do not stack duplicate handlers.

What gets saved

When a player’s rank changes (non-silent updates), the mod writes:

  1. Current SCR_ECharacterRank as text (enum name)
  2. A Unix anchor timestamp on the second line (used for time decay and migrations)

Profile layout

PathPurpose
Profile/OkamiPersistantRankDecay/settings.jsonTunables (created on first load if missing)
Profile/OkamiPersistantRankDecay/<aa>/<bb>/<identity>Per-player rank file; <aa> / <bb> are the first two and next two characters of the identity id

Configuration

Edit Profile/OkamiPersistantRankDecay/settings.json while the server is stopped (or reload behavior by restarting), then restart so changes apply.

Default config

{
  "scenarioEndDecayEnabled": true,
  "scenarioEndDecayLevels": 3,
  "timeDecayEnabled": false,
  "timeDecayIntervalMinutes": 4320,
  "timeDecayLevelsPerInterval": 1,
  "timeDecayCheckIntervalMinutes": 5,
  "resetTimeDecayClockOnRankUp": true,
  "syncOnlinePlayersAfterTimeDecay": true,
  "debugLogging": false
}

Set debugLogging to true while testing time decay; the server console will print each scan, per-file “no change” reasons (anchor age vs interval), and pipeline/file-count warnings.

Settings

scenarioEndDecayEnabled

  • If true, when the match ends (RPC_DoEndMatch), the mod scans all stored rank files and lowers ranks by scenarioEndDecayLevels (floored so rank index does not go below 1).
  • If false, scenario-end decay does not run.

scenarioEndDecayLevels

  • How many rank steps to subtract per player at scenario end (integer ≥ 0 in practice; 0 means no effective change).

timeDecayEnabled

  • If true, a repeating server timer runs (see timeDecayCheckIntervalMinutes) and applies time decay to every stored rank file.
  • If false, only scenario-end decay (if enabled) and normal save/load apply.

timeDecayIntervalMinutes

  • Wall-clock length of one decay period in minutes (float). Examples: 30 (half an hour), 60 (one hour), 1440 (one day), 4320 (three days).
  • Converted to seconds for the decay math; values below 1 minute still produce at least 1 second between anchor steps so the loop behaves sensibly.

timeDecayLevelsPerInterval

  • How many rank steps to remove each time a full interval elapses since the anchor (minimum treated as 1 if misconfigured lower).

timeDecayCheckIntervalMinutes

  • How often the server re-evaluates stored ranks for time decay (separate from timeDecayIntervalMinutes, which defines how long one decay period lasts). The timer enforces a minimum of 10 seconds between scans (very low values are clamped). Set the check interval your decay interval so decay does not sit idle for too long (e.g. 5‑minute checks with a 30‑minute decay interval is fine).

resetTimeDecayClockOnRankUp

  • true: when saving a new rank after a promotion (or any rank change), the anchor is set to now (fresh clock for time decay).
  • false: on rank-up save, the previous anchor from the file is kept, so time decay timing does not reset when someone ranks up.

syncOnlinePlayersAfterTimeDecay

  • If true, after scenario-end decay or a time-decay tick, the mod reapplies stored ranks to currently connected players (via the XP handler) so in-session rank matches profile without requiring reconnect.

debugLogging

  • If true, logs every time-decay tick summary and detailed per-rank-file messages (including why no decay happened), and prints component-level reasons while waiting for the XP pipeline during InitServer retries. If false, the first few time-decay ticks still log a short summary so you can confirm the timer is running without flooding the log. Server init (InitServer / ResetAndInit) always emits its standard lines regardless of this flag.

Gameplay notes

  • Join / restore: after player audit success, the mod logs pipeline and hook state. If the XP pipeline is not ready yet, it queues one retry in 5 s (OnPlayerAuditSuccessRetry); if the pipeline still is not ready, it gives up rank restore for that session with an error log. When the pipeline is ready, it loads the stored rank (if any) and, after 5 seconds, awards XP so the live rank matches the file.
  • Scenario-end decay processes all rank files under OkamiPersistantRankDecay when the winning faction is resolved and the match-end RPC runs.
  • Time decay advances the anchor in steps while “catching up” if the server was down across multiple intervals (intervals are applied in a loop until the anchor is within one interval of now).
  • Rank index is never reduced below 1 by decay logic in this mod (as implemented).
  • With resetTimeDecayClockOnRankUp: true, any rank change that triggers a save (including applying a lower rank after decay sync) sets the profile anchor to now, so the next decay step is a full timeDecayIntervalMinutes after that save — not from the previous anchor. Use debugLogging: true to see anchor ages in the log.

Troubleshooting

IssueThings to check
Ranks not persistingMod loaded on the server; game mode has SCR_XPHandlerComponent + faction manager (see server log for the “no XP/rank pipeline” warning).
No settings.jsonRun once with the mod enabled; the folder and defaults are created under Profile/OkamiPersistantRankDecay/.
Time decay never movesEnable timeDecayEnabled; ensure timeDecayIntervalMinutes and timeDecayCheckIntervalMinutes are sane; remember the 10s minimum tick.
No rank file / rankFilesSeen=0No one has a stored rank file yet — earn a rank so OnRankChanged writes under Profile/OkamiPersistantRankDecay/....
“no XP/rank pipeline” on every tickGame mode has no SCR_XPHandlerComponent or no faction manager — time decay is skipped until that exists (see init warning).
“no change | anchorAge …”Normal until anchor age ≥ interval (e.g. 60s for a 1‑minute interval). If you just ranked or synced, resetTimeDecayClockOnRankUp may have reset the anchor — wait another full interval.
Still rank 1 / no visible dropAt minimum rank there is nothing lower to decay; logs will say so when overdue.
Stale hooks or no rank save after Workbench ReloadSCR_GameModeCampaign.ResetAndInit clears static state (including the hooks flag). For non-campaign previews, restart the session if statics ever get stuck.
Scenario decay not firingConfirm scenarioEndDecayEnabled and scenarioEndDecayLevels > 0; decay runs on match end, not mid-round.
Wrong rank after reconnectIdentity must resolve; rank file path depends on backend identity id.
JSON errorsStrict JSON (no comments/trailing commas).

Credits

Created by TinyTank800.

Compatibility

  • Persistence + time decay: any SCR_BaseGameMode-based mode that wires XP + ranks like Conflict (presence of SCR_XPHandlerComponent and faction manager). Init uses a 2 s deferred first attempt plus pipeline retries.
  • Campaign / Workbench: SCR_GameModeCampaign additionally runs ResetAndInit so editor reloads do not leave stale hook flags.
  • Scenario-end decay: SCR_GameModeCampaign only (match-end RPC_DoEndMatch).
  • Server profile storage; not a substitute for full persistence mods that track broader player state