UngodlyLiquidation RTS manual

Before you play online

Playing with these plugins online

Liquidation is a deterministic lockstep game. That single fact decides everything on this page, so it is worth understanding before you queue up with someone.

The short answer: Gore & Graphics is safe and nobody else needs it. AI and Leveling need everyone in the match to run the same version with the same settings.

#What deterministic lockstep means here

Most online games send the world state from a server to each player. Lockstep games do not. Instead, every machine runs the entire simulation itself, and the only thing that travels over the network is the commands players issue. Each machine then computes a checksum of its own simulation every tick and compares it with everyone else's.

The consequence: every machine must compute an identical result from identical inputs, every tick, forever. If two machines ever disagree by a single value, the match has desynced and there is no way to reconcile it.

That is why the answer differs per plugin. A plugin that changes what the simulation computes must be present and identically configured everywhere. A plugin that only changes what your own graphics card draws touches nothing the checksum sees.

PluginOnlineDo others need it?
Ungodly Liquidation AI Everyone must match Yes — same version, same simulation settings
Ungodly Liquidation Gore & Graphics Safe No — it changes only what you see
Ungodly Liquidation Leveling Everyone must match Yes — same version, same simulation settings

#Gore & Graphics is safe online

Other players do not need it installed, and it cannot desync a match. That is not an assurance offered casually — it is the reason the gore system is built the way it is.

Why it does not touch the game's own corpses

The game's corpses are part of the simulation. CorpseService writes every corpse's id, destroyed flag and decayed flag into the per-tick network checksum; corpses register physics bodies; and Legion Scavengers and Corruption Forsaken query live corpses in order to use them. Making those permanent would desync a match instantly and would change what scavenging units can find.

So the plugin leaves them completely alone. The game's corpse still decays on schedule, the checksum is untouched, and scavengers behave exactly as before. The plugin takes a photograph on the way past and leaves the photograph behind. No corpse it creates is a real entity, no blood mark has a physics body or a collider, and nothing it does is ever written into the network checksum.

It carries its own random number generator

It does not use the game's DRandom, whose cursor position is part of the checksum, and it does not use UnityEngine.Random, which is shared with the game's own visual effects. It brings its own, so its randomness cannot perturb anyone else's.

The lockstep namespace is excluded from the coroutine takeover

The entire Shadows.Core.Lockstep namespace is excluded at every adoption scope setting, so the plugin cannot become the cause of a desync even if a future game patch adds coroutines there.

#AI and Leveling: everyone has to match

Both of these change what the simulation computes, so both need to be present, at the same version, with the same simulation-critical settings, on every machine in the match. Mixing a modded and an unmodded player is not possible. That is not a limitation of these particular plugins — it is not fixable by any AI or levelling mod for a lockstep game.

How they stay deterministic in the first place

Getting a plugin to produce identical results on every machine takes deliberate work, and both of these do it the same way:

  • All simulation maths is 16.16 fixed point. No floats anywhere on a simulation path.
  • All iteration happens in sorted simulation-id order, so no result can depend on the order a collection happened to enumerate in.
  • Every work budget is a count per tick, never a millisecond timer. A faster computer must not get more work done per tick than a slower one.
  • Neither calls the game's DRandom, because its call counters are part of the sync checksum.
  • Every A* tie-break resolves by tile index, so two equally good routes always resolve the same way everywhere.

Why Leveling rewrote its curve maths in integers

This one is worth spelling out, because it is the least obvious. The levelling curves were inspired by an asset that computes its formulas with Mathf.Pow, Mathf.Sin, Mathf.Log and Mathf.Sqrt on float.

IEEE single-precision transcendental functions are not guaranteed to return bit-identical results across CPU vendors, across JIT versions, or between x86 and x64 code paths. Folding one of those into a value that feeds unit health would produce a desync that is close to impossible to debug, because it would only show up on some combinations of hardware.

So every formula was rewritten using only + - * / and >> on System.Int64, which ECMA-335 defines exactly. The three functions that genuinely need a transcendental are provided as integer routines: square root by Newton's method, base-2 logarithm by bit scan, and sine from a 91-entry table.

#Before a match

  1. Agree who is running what

    Everyone installs the same plugins at the same versions, or nobody does. There is no middle ground for AI and Leveling. Gore & Graphics is the exception — install it or do not, independently of everyone else.

  2. Compare the settings hash

    Leveling folds its settings into the game's own per-tick checksum and shows a hash at the top of its config window. Share it with the people you are playing against. Identical hashes mean identical behaviour. Cosmetic settings — window size, logging, coroutine scheduling — are excluded from it, because they cannot affect the simulation.

  3. Confirm the AI checksum guard registered

    Open the AI plugin's Diagnostics tab and confirm Checksum guard registered says yes. If it says no, the service failed to rejoin the service map and you should report it rather than play with it.

  4. Turn off the fog-of-war reveal

    It defaults to off. Check it is still off before playing anyone.

#If a match desyncs anyway

The game's own desync detection will tell you. That is deliberate: both plugins fold their state into the game's existing checksum rather than running a check of their own, so a mismatch surfaces immediately instead of the match drifting apart silently over several minutes.

CheckWhat to look for
Plugin versionsIdentical across every player, down to the patch number. 1.0.6 and 1.0.7 are not interchangeable.
Leveling settings hashIdentical for everyone. If it differs, someone changed a simulation-critical setting.
Stale config filesSomeone updated a plugin without deleting the old .cfg. Delete it and relaunch so it is rewritten.
Someone is unmoddedCheck everyone actually has the DLLs in plugins, not just downloaded.

If everything above matches and it still desyncs, that is worth reporting with everyone's BepInEx\LogOutput.log attached.