Copy wrapper
- Copy
samples/unity/Assets/Korvayneinto the Unity project'sAssetsfolder. - Add an empty GameObject to the first scene.
- Attach
KorvayneManager. - Set game ID, environment, provider, and build context in the Inspector or at runtime.
Runtime files
For packaged Windows builds, place these next to the final game executable:
YourUnityGame.exe
anticheat.dll
anticheat.lic
anticheat.ini
Unity native plugin folders can help editor testing, but the license and config location for the shipped game is next to the final executable.
Protected values
Use the provided wrappers instead of guarding ordinary managed fields directly.
private KorvayneProtectedFloat health;
void Start()
{
health = new KorvayneProtectedFloat("player.health", 100f);
}
void ApplyDamage(float damage)
{
health.Set(health.Get() - damage);
}
The Unity/Mono/.NET garbage collector can move managed objects. The wrapper keeps the native SDK interaction stable.
Protected saves
Serialize the save normally, then pass the byte array through the wrapper before writing it to disk. Verify it before deserializing during load.
var context = $"player={playerId};slot=profile;schema=1";
var bytes = Encoding.UTF8.GetBytes(json);
int rc = KorvayneSdk.ProtectSaveFile(path, bytes, context);
if (KorvayneSdk.TryVerifySaveFile(path, context, out var verified, out rc)) {
var loadedJson = Encoding.UTF8.GetString(verified);
}
Use KorvayneSdk.SaveResultName(rc) for logs and reject the load when verification returns a tamper result.
Report shots
Aim behavior reports are optional. The SDK does not read mouse input, target positions, or visibility state by itself. Unity gameplay code should call the wrapper once after the local player's weapon logic has resolved whether the shot hit and whether line of sight was valid.
KorvayneManager.Instance.ReportShot(
aimSpeedPerMs,
reactionMs,
hadLineOfSight,
hit
);
| Value | Where to get it |
|---|---|
aimSpeedPerMs | Store the local camera or aim transform rotation from the previous weapon tick, compare it with the rotation at fire time, then divide by elapsed milliseconds. |
reactionMs | When your visibility, target selection, raycast, or crosshair logic first marks a target as valid, store Time.time. On shot, send the time difference in milliseconds. |
hadLineOfSight | Reuse the same raycast or weapon-validation result your game already uses for visibility. |
hit | Use the final local result after the shot has resolved, not an early prediction. |
Safe fallback: leave ReportShot out until the game can provide real values. Sending placeholders is worse than not sending the optional behavior signal.
- Call it once per local human-player shot, not from
Update(). - Do not report AI, remote players, spectators, or replay playback.
- Keep
behavior_response = reportuntil normal gameplay telemetry has been reviewed.
Those reports can become advisory AimSnap, Triggerbot, or Wallhack evidence in logs or studio telemetry when the supplied shot values cross simple built-in thresholds.
| Evidence | Current condition |
|---|---|
AimSnap | Hit shot with aimSpeedPerMs > 8.0. |
Triggerbot | Three hit shots with reaction time below 60ms; normal reactions above 120ms reset the counter. |
Wallhack | Hit shot while hadLineOfSight is false. |
Telemetry for these events is controlled by [TelemetryEvents] aim_behavior; local action is controlled by [Enforcement] behavior_response. Keep this report-only until real player baselines are reviewed.
Common mistakes
- Putting
anticheat.licinAssetsbut not next to the final executable. - Calling protected values before Korvayne startup has completed.
- Changing protected gameplay fields directly after wrapping them.
- Calling shot reports for bots or replicated remote players.
- Shipping backend secrets in scripts, Resources, ScriptableObjects, or config files.
