Stops memory editors from changing your gold, health, ammo and score — and tells you when someone tried.
Every number on this page comes from a test you can run yourself: the headless gates in the source, or the attack suite described under Under attack.
In plain words, before any of the technical detail.
A player downloads a memory editor, scans for the number on their HUD, finds the address, types a bigger number, and your economy is gone. It takes about two minutes and there are thousands of videos explaining it.
AdrenalineGuard makes that workflow stop working. A protected value is never stored as a plain number; its encrypted form keeps changing on a timer even when the value itself does not; and the value moves to a new address while the game runs. A scan finds nothing to keep, a saved address goes stale, a pointer path breaks, and a frozen address is detected.
It also leaves a decoy: a plain copy of the number that no game code ever reads. A scanner will find it, because that is what it is for. The moment someone writes to it, you know — there is no innocent path to that write.
Three layers, one score:
Two minutes. Works on a C++ project, and on a Blueprint project that is allowed to compile a plugin.
Unzip into your project's Plugins folder, so you end up with
YourProject/Plugins/AdrenalineGuard/. If there is no Plugins folder,
make one with exactly that name.
Unreal offers to build the plugin. Say yes. Nothing is added to your level, your settings or your content: this plugin ships no assets at all.
In BeginPlay, call Make Protected Int with a minimum, a maximum and a label
such as Gold. Keep the handle it gives you.
Replace Gold = Gold + 50 with Add Protected Int and a reason code
of your own — 1 for loot, 2 for a sale. Replace reads with Get Protected Int.
The reason code shows up in the report next to anything that goes wrong.
Do this once, on your own project, before you trust anything on this page.
Place an AdrenalineGuard Demo actor in an empty level and press Play. It shows a protected value, the address it currently lives at, the decoy, and the live suspicion score. It is built from code alone: no meshes, no materials, nothing to migrate.
Open your memory editor of choice and scan for the number on screen. You will find the decoy and the copies your HUD uses — and then watch what happens when you write to them. The number comes straight back, and the panel reports the attempt.
The panel prints the address of the protected value as it migrates. That is what breaks a saved address and a pointer scan: by the time a path is built, it points at nothing.
AG.Status prints the report, AG.Verify forces a full check of
every protected value.
What happened when we ran the memory editor workflow against a live process.
The protection is tested by attacking a running game, not by reading the code. The attacker reproduces the whole workflow: scan for an exact value; scan for an unknown initial value and narrow it with changed and unchanged passes; write to each candidate and undo when nothing happens; freeze an address from another thread; pointer scan; and finally set a hardware breakpoint through DR0–DR3, which is what "find out what accesses this address" does.
| Attack | Plain int | Protected value |
|---|---|---|
| Full scan workflow | found — 671 candidates narrowed to 2 | never points at the store |
| Write to the found address | gold becomes 999999 | unchanged |
| Freeze the address | frozen at 424242 | nothing left to freeze |
| Write into the store directly | — | reported, suspicion 99.6 |
| Touch the decoy | — | reported, suspicion 198.9 |
| Hardware breakpoint | — | reported, suspicion 199.0 |
Alongside that, the headless gates run 100 000 random operations against an independent model of what the values should be, and 100 000 steps of randomised honest movement — variable frame rate, hitches down to 10 fps, pauses, 695 jumps — with zero reports.
The defaults are chosen so that an honest player is never accused. Two checks are deliberately off.
| Setting | Default | What it means |
|---|---|---|
| Rotate Interval | 0.35 s | How often a value gets a new key. Shorter defeats "unchanged" scans and costs a little more CPU. |
| Migrate Interval | 2.0 s | How often a value moves to a new address. |
| Suspicion Threshold | 100 | Where your callback fires. A touched decoy alone is 100; a single teleport is 20. |
| Use Ledger | off | Turn on for economy values: the value must match the sum of recorded transactions, which catches a cheat that knows every key. |
| Max Acceleration | off | Off on purpose: for characters, going from run to sprint in one frame reads as 9000 cm/s², so it would report anyone pressing Shift. Enable it for vehicles. |
| Check Clock | off | Off on purpose: Unreal clamps world time to 2000 fps, so a faster game drifts on its own. See Limits. |
The plugin never punishes anyone. This is the part you have to write, and the part worth thinking about before you ship.
Two events are raised on the guard subsystem, which you get with Get Guard:
| Event | Gives you | When |
|---|---|---|
| On Violation | FAGViolationEvent | Every single violation, as it happens. |
| On Suspicion Threshold | the score as a float | Once the score crosses your threshold, default 100. |
The event carries Violation, Certainty, the Label you gave the value, Observed, Expected, At Time and Suspicion After. The one to branch on is Certainty:
| Certainty | Meaning | Reasonable response |
|---|---|---|
| Hint | Could be an unusual mechanic of yours, or lag. | Count it. Do nothing visible. |
| Strong | Hard to explain innocently, but not impossible. | Log it, flag the session, tell your server. |
| Proof | No legal path exists: a touched decoy, a forged handle, a memory breakpoint. | Act. This did not happen by accident. |
Is Proof answers that in one node, and Get Violation Text gives you a
readable sentence for a log or a report.
For a HUD or a support report, Get Report returns running totals: suspicion, total
violations, Proof Violations (above zero means it really happened), protected values, key
rotations, address migrations and clamped writes. AG.Status prints the same thing in
the console.
Add AG Motion Guard to a Character or Pawn. Four settings and one function matter.
Set Max Speed to your real maximum in cm/s, including sprint. Speed Tolerance is the headroom on top (1.35 by default, for slopes and buffs). Teleport Distance must be larger than your speed times your longest frame, or a hitching game reports itself.
Call Allow Next Movement immediately before a respawn, a lift, a cutscene
teleport, entering a vehicle or loading a save. That one step is skipped and the reference
point moves with the pawn. Without it, every scripted teleport in your game is a report.
After a level change or anything that moves the pawn behind your back, call
Reset Tracking.
If your game lets players fly, build, or possess a spectator, set Allow Flight. Otherwise Max Air Time (6 s) and Max Fall Speed apply. An empty test level has no floor, so a pawn there is permanently airborne: that is a property of the level, not a cheat.
On Motion Violation gives you the violation, what was observed and what was allowed. It also goes into the shared score, so movement and memory add up: two teleports are lag, two teleports and a touched decoy are not.
Closing memory is pointless if the save opens in Notepad.
Set the key once, at startup, with Set Save Key — or type it into Project Settings,
knowing what that means (see Limits). To tie a save to one account, add
Set Save Binding with a player id: the binding is never written to the file, only
mixed into the signature, so a save copied to another account fails to open.
| Function | Use |
|---|---|
Sign Save Data | Takes your bytes (for example from Save Game To Memory) and returns signed bytes. |
Open Save Data | Verifies and gives back the original bytes. Returns a status. |
Sign Save To File | Signs and writes the file in one call. |
Load Signed Save From File | Reads and verifies in one call. |
Load Signed Save And Report | Same, and reports a tampered file into the suspicion score. |
The status tells you why a file was refused: Ok, Too Short, Bad Magic (not our file), Bad Version, Length Mismatch, or Bad Signature (edited, or a different key or binding).
Everything here has actually happened, most of it to us.
| What you see | What it is |
|---|---|
| Get returns the right number but bTrusted is false | Verification failed and the value was restored from the last known good one. That is the design: your game keeps running. Read the event to find out what happened. |
| Get returns 0 and the handle looks fine | The handle is from a previous level or a previous store. Handles carry a serial for exactly this reason. Create protected values after the world exists, not in a constructor. |
| Flight reported in an empty test level | No floor, so the pawn is airborne the whole time. Set Allow Flight for that level, or test on a level with ground. |
| A scripted teleport is reported | Allow Next Movement was not called before moving the pawn, or was called a
frame too early. |
| Clamped Writes keeps climbing | Not a cheat. Your game writes past its own limits all the time, usually regenerating at full health. Harmless, but it often means Max Value is wrong. |
| Nothing is ever detected | Usually correct: nobody touched the protected memory. To check detection really works, edit the decoy in a memory editor — the demo actor prints its address. |
| A clock mismatch at a very high frame rate | Unreal clamps world time to 2000 fps, so the game clock legitimately runs ahead. Check Clock is off by default for this reason; see Limits. |
| Assertion about the game thread | A protected value was used from another thread. The store is deliberately single threaded; call it from the game thread. |
Everything the plugin exposes. The same names in Blueprint and C++.
| Protected values | |
|---|---|
Make Protected Int / Make Protected Float | Create a value from a policy and a label. |
Get Protected Int / Float | Read it. Also returns whether it is trusted. |
Set Protected Int / Float | Write it outright. Prefer Add when the policy uses a ledger. |
Add Protected Int / Float | Change it by a delta, with a reason code of your own. |
Release Protected Int | Free the slot when the value is gone for good. |
| Guard subsystem | |
|---|---|
Get Guard | The subsystem for this world. |
On Violation, On Suspicion Threshold | The two events. |
Get Report | Running totals for a HUD or a support report. |
Verify Now | Check every protected value immediately, for example before writing a save. |
Reset Suspicion | Clear the score, for example on a new game. |
Report Save Tampered, Report Motion Violation | Feed your own findings into the same score. |
| Policy fields | |
|---|---|
| Min Value, Max Value | What is legal. Writes outside are clamped silently. |
| Max Increase Per Second, Burst Seconds | Rate limit as a token bucket, with an allowance for one legitimate jump. |
| Use Ledger | The value must equal the sum of its transactions. For economy values. |
| Use Decoy | Keep a decoy copy. On by default. |
| Rotate Interval | Per value override of the key rotation period. |
Console: AG.Status, AG.Verify, and on the demo actor
AG.Demo.Earn, AG.Demo.Save, AG.Demo.Load.
What this plugin does not do. We would rather write it here than have you find out.
Something not working, or a number on this page that does not match what you see in your project? Tell us — a report that contradicts our measurements is the most useful mail we can get.
Please include your engine version and the output of AG.Status.