Repository navigation
v1.0.0
The first release of CheatEngine.Client: high-level, activation-scoped C# APIs for Cheat Engine 7.7 x64 plugins, built
on CheatEngine.SDK 2.0.0. It fixes the public API for the 1.x line, under the versioning rules of the
README and the
public API charter of the CheatEngine.Client.Abstractions README; an API that carries an experimental diagnostic id
(CECLIENT5001 to CECLIENT5004) stays outside that promise until the id is lifted. Changed and Removed
compare this release with the 0.1.0 builds of the repository, which were never published. They summarize by contract
the changes a consumer of those builds meets, not every renamed member: the PublicAPI files of each project list the
exact surface.
Added
- One client per activation.
CheatEngineClientPluginbuilds a new DI provider, scope andICheatEngineClienton
every enable, starts theICheatEngineClientModules in registration order, stops them in reverse order and releases
every Client-owned Cheat Engine resource while the SDK context is still valid.ICheatEngineClientexposes
Dispatcher,Runtime,Processes,Memory,Patterns,Inspection,Tables,Lua,ValueScans,
AllocationsandAssembly;EpochandStoppingidentify the activation. - Capability matrix.
ICheatEngineRuntime.TryGetClientCapabilityreports each of the elevenClientCapabilityIds
with itsEvidence: separate implementation, package, host, live qualification, policy and lifetime gates, and a
typedEffectiveReasonCode; a capability reportsAvailableonly when all six gates are satisfied. Every capability
has an operational adapter. The package gate accepts a loaded CheatEngine.SDK 2.x at or above 2.0.0, and the
qualification gate staysUnknownuntil the Client embeds committed evidence that every live scenario of the
capability succeeded, none waived (Client.UnsafeLuaExecutionhas no scenario, so it staysUnknown). The README
capability tables state the same matrix, and the features Cheat Engine offers without a CheatEngine.SDK primitive are
listed as not offered. - Value scans, allocations, instructions and Auto Assembler patches. Four operational adapters, each assigned an
experimental diagnostic id that keeps its API[Experimental]until the live scenarios of its capability succeed and
the id is lifted; the README capability tables say which of these ids this release carries. While an API carries its
id, suppressing the diagnostic is the opt-in, and the diagnostic links to its section of the Abstractions README
(scope, behavior, known limits and exit criteria):CECLIENT5001, value scans:ICheatEngineClient.ValueScanscreatesIValueScanSessions over CheatEngine.SDK's
ownedMemScanandFoundList, with first and next scans and pages of at most 1024 copied results;
ValueScanValue.FromSingleandFromDoublewrite the value in fixed point with the decimals the caller passes;CECLIENT5002, target allocations:IAllocationClient.Allocatereturns anITargetMemoryLeaseover
CheatEngine.SDK'sAllocatedRegion(AllocationProtection.ReadWriteorExecuteReadWrite), freed only in the
process incarnation that made it;CECLIENT5003, instructions:IAssemblyClientassembles, disassembles and measures one instruction per call,
checked against the target's instruction profile, and never writes target memory;CECLIENT5004, Auto Assembler patches:IAutoAssemblerClientchecks a script, or applies it and returns an
IAutoAssemblerPatchLeasethat owns the disable information Cheat Engine returned; it is registered only by
EnableAutoAssemblerPatches().
- Leases and release outcomes. Every resource the Client creates for the caller is an
ICheatEngineLease:
symbol registrations, Lua modules, value-scan sessions, allocations and Auto Assembler patches.Release()returns a
LeaseReleaseOutcome(aLeaseReleaseKind, the host effect, and exactly one ofIsComplete,IsRetryableand
RequiresManualRecovery),Dispose()never throws,LastReleaseOutcomekeeps the attempt that ended the lease, and
RequiresManualRecoverysays that what the lease owned may remain. OnlyUnknownandCleanupUnavailableare
retryable, as in CheatEngine.SDK; a lease still incomplete at disable is reported in the aggregated deactivation
failure. A target-bound lease exposes theSelectionEpochof the process CheatEngine.SDK bound it to, and
ILuaModuleLease.LastModuleReleaseOutcomekeeps what the module reported. - Failure vocabulary.
CheatEngineFailure.HostEffectsays how far the Cheat Engine primitive got:NotStarted,
Started,Completed,NotApplied,CleanupUnconfirmedorUnknown. New failure kinds:
IndeterminateHostResult(documented causes that cannot be told apart, never absence),TargetChanged,
TargetIdentityUnavailableandRuntimeChanged.CheatEngineFailure.Throw(token)throws a failure's exception and
ToException(token)creates it. - Pattern scans.
IPatternScanner.ScanDetailedreturns aPatternScanOutcome: the classification ofTryScan,
PatternScanMetrics(the route, the host result count, the examined, filtered-out, copied and unread counts, and
Cheat Engine's scan time apart from the copy time), thePatternScanHostOutcomeKind, thePatternScanRouteReason
andTargetIdentityVerified. A module or range scan runs Cheat Engine's bounded MemScan on a qualified local target
and falls back to one globalAOBScanwith managed filters elsewhere, whose addresses are never reported as
identity-verified. Scan options are Client values (ScanProtectionFilter,ScanAlignment) that Core translates the
same way on every route; the default filter is Cheat Engine's empty "find everything" protection text. - Memory.
IMemoryClient.ReadBytesDetailedreturns the confirmed prefix of a partial byte read
(MemoryBytesReadOutcome), andReadPrimitiveBatchDetailedandWritePrimitiveBatchDetailedreport
RequestedCount,CompletedCountand aMemoryBatchWriteEffectState. Pointer-typed operations use
CheatEngine.SDK's width-qualified reads and writes at the observed process width, and codec contexts exposeBitness
and the configured pointer size. - Runtime and target facts.
CheatEngineRuntimeSnapshotgroups the four-part Cheat Engine version, the loaded
CheatEngine.SDK version and whether it is the reviewed package (Version), and the host operating system and
architecture,CheatEngineBitness, theTargetBackend, the target architecture,TargetBitnessand the configured
pointer size (Platform); a fact CheatEngine.SDK could not establish stays unknown.ProcessSnapshotaddsBackend,
StartTimeUtcand the configured pointer size next to itsBitness(ConfiguredPointerSize,
ConfiguredPointerSizeBytes,ConfiguredPointerSizeDiffersFromBitness), andIProcessClient.TryGetLocalProcesses
reads the local process catalog offline, without an activation. - Address List and symbols.
ITableClientcounts records (GetRecordCount), reads one by index (GetRecordAt),
reads the selected record and selects one (GetSelectedRecord,SelectRecord), and loads and saves trusted tables
through CheatEngine.SDK'sCheatTableFiles; a trusted load makes every earlierMemoryRecordIdstale.
IInspectionClient.TryRegisterSymbolregisters through CheatEngine.SDK's owned registration after a collision check,
andTryResolveAddresstakes anAddressResolutionMode. - Lua. Generated Lua modules register through CheatEngine.SDK 2.0.0 registration leases, and the generator reports
the module shape errorsCECLUA1201toCECLUA1204. - Fluent entry points. Each domain has one entry point, an extension method bound to its service when the builder
is created:memory.At(address)andmemory.Batch<T>()on anIMemoryClient, andscanner.Aob(pattern)on an
IPatternScanner. The AOB builder takes typed options (Writable(),WithProtection,AlignedTo,LastDigits,
WithAlignment), and every terminal documents the exceptions it throws. - Hosting.
CheatEnginePluginBuilder.Loggingis theILoggingBuilderof the activation provider, and
PluginDirectoryis the folder of the plugin assembly, the base for the plugin's own files.
builder.Logging.AddCheatEngineHostLog()adds an opt-in logging provider that writes to CheatEngine.SDK's host log.
Event 20 (ActivationIdentified) identifies each activation with the Client version and the consumed and loaded
CheatEngine.SDK, and event 8 (ExternalLuaStateResetDetected) reports a Lua state that Cheat Engine replaced outside
the plugin's control, read from CheatEngine.SDK's flag after the Client resources are released, without a snapshot. - Build diagnostics. The Hosting README catalogs the consumer diagnostics
CECLIENT001toCECLIENT017, and each
diagnostic carries a help link to its entry. - Template.
dotnet new cepluginderives the plugin's display name and its Lua status global (ASCII
lower_snake_case with a_statussuffix) from the project name, creates a folder named after the project, honors
--no-restoreand ships a.gitignore. Different project names can derive the same global, which only one plugin
can own. The generated plugin reads its configuration fromPluginDirectoryand adds no logging provider; its README
documents the opt-inAddCheatEngineHostLog(). - Documentation. Every public member documents its parameters, return value and exceptions, which a test checks.
The packed READMEs are written for plugin authors, and their C# snippets compile against the packed packages. Tests
also tie the READMEs' 1.0 status columns to the experimental APIs, the diagnostic catalog's severities to the
diagnostics and each documentedPackageReferenceversion to the compiled one.
Changed
- Cancellation. A throwing form whose token is observed throws
CheatEngineOperationCanceledException, an
OperationCanceledExceptionwhoseFailure.HostEffectsays whether Cheat Engine work had started. A token is
observed before dispatch and between Client-managed steps, and never interrupts a Cheat Engine call that has started.
A batch write cancelled before dispatch reportsMemoryBatchWriteEffectState.NotStarted. - Exceptions. The exception type depends only on the failure kind:
Cancelledgives
CheatEngineOperationCanceledException,ActivationExpiredCheatEngineActivationExpiredException,InvalidState
CheatEngineInvalidStateException(formerlyCheatEngineClientLifecycleException), and every other kind
CheatEngineOperationException. Every exception keeps the complete failure, and no Client exception has a public
constructor:CheatEngineFailure.Throw(token)andToException(token)create them. - Arguments first. A null argument, a
defaultrequest, an undefined enum value or an out-of-range number throws
anArgumentExceptionfrom theTryform as from the throwing form, before the activation check and before any
Cheat Engine call; it is never returned as a failure. An ended activation then throws
CheatEngineActivationExpiredExceptionand a stopping oneCheatEngineInvalidStateException, under the operation's
own name, before any refusal of the request is returned. - Try forms. No
Tryform lets a CheatEngine.SDK exception escape: an SDK fault raised by Client-internal work
becomes aCheatEngineFailurechosen by exception type and by the SDK's failure category. Exceptions from your own
callbacks, codecs, Lua operations and Lua result mappers are rethrown unchanged. A Lua admission that the Client asks
for and CheatEngine.SDK refuses isActivationExpired,RuntimeChanged,InvalidStateorIndeterminateHostResult
withNotStarted. - Classification.
CheatEngineFailure.Operationis<Service>.<Member>(for exampleMemory.ReadPrimitive, or
Client.Activatefor the activation itself), and thedefaultfailure is safe to read. An outcome or status of
CheatEngine.SDK that the Client does not recognize fails closed asIndeterminateHostResult, never as a success. A
host rollback or release that was not confirmed is reported withCleanupUnconfirmed, under
IndeterminateHostResultor the kind of the failure that caused it. An unavailable Address List or inspection global
isCapabilityUnavailablewithNotStartedin every lookup, and a record activation refused by its callback, script
or record type isOperationRejectedwithStarted. - Leases. A lease no longer throws from
Dispose():Release()returns the outcome, and a repeated release returns
the outcome that ended the lease without calling Cheat Engine.RequiresManualRecoverybecomestrueonce a release
attempt leaves the resource behind;IAutoAssemblerPatchLease.CanDisableis the earlier signal. Core and Hosting
attempt every cleanup in reverse order and report every failure: one failure is rethrown as the same instance,
several are aggregated, and Hosting logs each failed stage. A failed Address List record creation destroys the
partial record once and reportsCleanupUnconfirmedwhen that rollback is not confirmed. - Target selection.
IProcessClient.Attachgoes through CheatEngine.SDK'sSelectAndObserveand reads the
selected process again before it reports success; a file opened as a process isTargetIdentityUnavailable. A
target-bound lease ends when the Client observes that Cheat Engine selected another process, and that release is
refused (RefusedTargetChanged) without freeing anything: release target-bound leases before selecting another
process. - AOB scans. One scope rule applies on every route: a match lies wholly inside the module and starts inside the
range. Every route copies at most 65,535 addresses, andMaximumResults,Take,FirstOrNoneandRequireSingle
bound only that copy, never Cheat Engine's scan. A global scan for which Cheat Engine returns no result list fails
withIndeterminateHostResultinstead ofOperationRejected: the global route calls CheatEngine.SDK's
AobScanner.TryScanOutcome, and on Cheat Engine 7.7AOBScanreturnsnilfor zero matches and for some host
failures alike, so it is never reported asnullorNotFound. A result list or MemScan session is released exactly
once on every path; when that release is not confirmed, the copy is discarded and the scan fails with
IndeterminateHostResult, or the kind of the failure that caused it, andCleanupUnconfirmed.IsTruncatedmeans
that the copy is not proven complete, andRequireSinglereports a single match that is not proven unique as
IndeterminateHostResult, notAmbiguousMatch. - Memory.
IMemoryClientnever resolves a codec: pass theIMemoryCodec<T>in aMemoryReadRequest<T>or
MemoryWriteRequest<T>. Primitives takewhere T : unmanagedand support the 8- to 64-bit integers,float,
doubleandAddress; any otherTisOperationRejectedwithNotStarted, without a Cheat Engine call. Pointers
follow the observed process width, never the configured size: an unknown or mismatched width is refused before any
access, and nothing is truncated on a 32-bit target. String requests carry an explicitMemoryStringEncoding. - Implementable interfaces.
IMemoryCodec<T>.TryReadandTryWritereport anout CheatEngineFailure failure,
and their contexts report the same onTryReadBytesandTryWriteBytes.ILuaModulecarries itsDescriptor, and
Unregister()returns aLuaModuleReleaseOutcome. These interfaces are frozen for 1.x. - Operations renamed or reshaped.
ICheatEngineClient.ScansisValueScans;IProcessClient.GetCurrentis
GetCurrentProcess;ITableClient.GetRecord(int)isGetRecordAt,GetSelectedisGetSelectedRecord,
TrySelectisTrySelectRecordandUpdate(update)isUpdate(id, update);IAssemblyClient.GetInstructionSize
isGetInstructionLengthandGetPreviousInstructionisGetPreviousInstructionAddress, andApplyPatchmoved to
IAutoAssemblerClient;TargetAllocationRequestisAllocationRequestandTargetAllocationAccessis
AllocationProtection. Value-scan sessions takeValueScanFirstRequestandValueScanNextRequest(TryFirstScan,
TryNextScan), andTryResolveAddressanAddressResolutionMode, instead of CheatEngine.SDK request and option
types.ICheatEngineDispatcherhas explicit overloads instead of an optional token, andILuaClientone
TryExecute<TOperation, TResult>(in TOperation ...)design. - Facts renamed or regrouped.
CheatEngineRuntimePlatformInfo.SystemArchitectureisHostArchitectureand
TargetPointerSizeisTargetBitness;ProcessSnapshot.TargetArchitectureisArchitectureand
TargetPointerSizeisBitness;IMemoryReadContext.PointerSizegives way toBitnessand the configured pointer
size. The runtime snapshot groups its facts inVersionandPlatform, and itsClientCapabilitiesis
Capabilities;CheatEngineRuntimeVersionInfo.ObservedCheatEngineVersion, adouble?, is the four-part
CheatEngineVersion.MemoryRecordSnapshotkeeps a record's facts only inContentandState, without their
top-level copies. The batch outcomes reportRequestedCount,IsSuccess,FailureandValuesinstead of
AttemptedCount,Succeeded,CauseandReadPrefix, andMemoryBatchLimits.MaximumOperationsis
MaximumOperationCount. The local process catalog types areLocalProcessEnumerationRequest,
LocalProcessEnumerationResultandLocalProcessSnapshot, formerlyProcessEnumerationRequest,
ProcessEnumerationResultandProcessInfoSnapshot. - Enum values. Every public enum is an
intenum with explicit values, and every outcome enum hasUnknown = 0.
This shifts the values ofClientCapabilityEvidenceReasonCode,MemoryBatchWriteEffectState(whoseCompleteis
Completed) andValueScanSessionState(whoseDisposedisClosed). - Capabilities that were contracts. Value scans, target allocations and instructions, which always reported
CapabilityUnavailablebefore 1.0.0, are operational adapters; Added gives their experimental ids. - Lua. A Lua module or export name that the activation already reserved is refused with
OperationRejected, and
a generated module whose registration is refused throws the exception of its failure's kind. - Composition.
CheatEngineClientOptions.AllowedTableRootsis anIList<string>andMemoryResourceLimitsis
nevernull; neither has a setter. Configure the plugin's own files againstbuilder.PluginDirectory, not
AppContext.BaseDirectory, which is the folder of the .NET host inside Cheat Engine. - Fluent. The builders are plain
readonly structs without equality, each bound once to the service that created
it. - Template. The Lua status global of a generated plugin is derived from its project name instead of the fixed
cheatengine_client_plugin_status.
Removed
- Domains that no CheatEngine.SDK primitive backs: timers, hotkeys, the debugger and breakpoints, the speed hack,
target-memory and file hashing, DBVM, remote execution and DLL injection, with the event streams they used: the
Timers,Hotkeys,Debugger,Speed,Hashing,Dbvm,RemoteExecutionandEventsnamespaces, their
ICheatEngineClientproperties and their capability ids. None of them had an implementation: each always reported
CapabilityUnavailable.IProcessClient.Pause,ResumeExecution,GetPauseState,Createand
AttachForeground, andIAssemblyClient.GetComment, are removed for the same reason. The
ROADMAP lists what each one waits for. - Companion interfaces and shims:
IMemoryBatchClient(merged intoIMemoryClient),IDescribedLuaModule(merged
intoILuaModule),ILocalProcessDiagnostics(replaced byIProcessClient.TryGetLocalProcesses),
CheatEngineClientBuilder.AddMemoryCodecand the implicit codec resolution,ITableClient.GetCurrent(use
GetSnapshot),ICheatEngineRuntime.GetSdkCapabilityandCheatEngineRuntimeSnapshot.SdkCapabilities,
ClientCapabilityEvidence.IsExecutable(readAvailabilityState),ILuaModuleLease.Epoch, theILuaClient
overloads that took anILuaOperation<TResult>interface, and theMemoryStringReadRequest.Createand
MemoryStringWriteRequest.CreateBoundedfactories with theirWideCharacterflag. - Public constructors that bypassed the contracts: those of every Client exception, of the options validators
(CheatEngineClientOptionsSemanticValidator,ValidateCheatEngineClientOptions, now internal), and the constructor
andBuildServiceProviderofCheatEnginePluginBuilder. - Fluent helpers: the static
Memoryentry class,Using(memory)and the overloads that took anIMemoryClient,
ReadUtf8,ReadUtf16,WriteUtf8andWriteUtf16(useReadStringandWriteStringwith a
MemoryStringEncoding),ReadableExecutable(),WithProtectionFlags(string)and the CheatEngine.SDK
AobScanOptionsofAobScanBuilder.Options.
Security
- Opt-ins.
IUnsafeLuaClientexists only afterEnableUnsafeLuaExecution(), andIAutoAssemblerClientonly
afterEnableAutoAssemblerPatches(): without its opt-in, each capability reportsUnavailableand every call is
refused withCapabilityUnavailableandNotStartedbefore any Cheat Engine call (scenario Q44). Table files need an
allowed root: without one they areCapabilityUnavailable, and a path outside everyAllowedTableRootsentry is
OperationRejected. - Registrations.
IInspectionClient.TryRegisterSymbolrefuses a name that already resolves (a registered symbol,
a module or an address expression) withOperationRejectedandNotStarted, and a symbol or Lua module release
never removes a name that another owner replaced. - SDK range. A plugin that references
CheatEngine.SDK3.0 or later directly next to this Client fails to build
withCECLIENT017.CheatEngineClientAllowUnsupportedSdk=trueturns the error into a warning; such a plugin is
unsupported and is expected to break at run time. A direct reference below 2.0.0 fails the restore withNU1605. - Log redaction (Q46). No Client logging event carries an address, value, expression, path, script, message,
exception or failure object, and a test rejects any event whose parameters could.CheatEngineFailure.ToString()
returns only the kind, the operation and the host effect, andLeaseReleaseOutcome.ToString()only the kind and the
effect. The host log provider writes an entry's message template and exception type name, never its placeholder
values or exception message, unlessIncludeFormattedMessagesis set. A message built by string interpolation, such
aslogger.LogInformation($"Read {address}"), is its own template and carries its values: log constant structured
templates orLoggerMessagemethods. Theceplugintemplate logs a failure's kind, operation and host effect only.
Deployment
- CheatEngine.SDK 2.0.0. The Client consumes exactly
CheatEngine.SDK2.0.0 and declares[2.0.0, 3.0.0). The
pin has a single source,eng/CheatEngineSdk.props, and the build refuses a pin outside 2.x or a prerelease pin
(CHEATENGINECLIENT9016). The loaded CheatEngine.SDK passes the package gate when it has the same major at or above
the pin. Core embeds the consumed package's version, source commit and content hash at build time and fails a build
that cannot (CHEATENGINECLIENT9050). No experimental CheatEngine.SDK API is used. - CheatEngine.SDK values in the public API.
Address,PointerSize,ModuleInfoand the other descriptive
CheatEngine.SDK 2.x values the charter lists appear in public signatures, so a CheatEngine.SDK 3.x means a Client 2.0,
never a 1.x release. - Seven packages in lockstep. The seven packages ship with one version, and each depends on the Client packages it
builds on at exactly that version ([X.Y.Z],CHEATENGINECLIENT9019).CheatEngine.Client.Corehas no public API
and is published only as a dependency ofCheatEngine.Client.Extensions.DependencyInjection. - Versioning. Every package is versioned by MinVer from
v*tags: untagged builds are1.0.0-alpha.0.<height>,
and the assembly version carries the major number only (1.0.0.0). - Package contents. Every package embeds an SPDX 2.2 software bill of materials at
_manifest/spdx_2.2/manifest.spdx.json, has its own description, and links the project, the license and this
changelog; Source Link comes from the .NET SDK. The libraries are trim- and AOT-compatible and verify every
referenced assembly, and a Native AOT probe publishes the whole Client graph and calls every Fluent member. Cheat
Engine still loads the framework-dependent managed plugin folder. - Template. The
ceplugintemplate references the exactCheatEngine.Clientversion it was packed with and the
pinnedCheatEngine.SDK, is validated when it is built, and its instances restore with a lock file. The lock also
records theMicrosoft.NET.ILLink.Tasksversion that the .NET SDK bundles, so pin the .NET SDK or regenerate the
lock after an SDK update. - Release chain.
release.ymlreleases the seven packages from av*tag: it verifies the tag and takes the
release notes from this file, builds and tests the tag commit, stages the SBOMs andSHA256SUMS, attests the build
provenance and the SBOMs, drafts the GitHub release, publishes to nuget.org through trusted publishing from the
nugetenvironment after checking every package againstSHA256SUMS, verifies the publication and only then
publishes the GitHub release. A manual dispatch is a dry run. - Continuous integration. CI builds and tests every change in Debug and Release with exactly .NET SDK 10.0.401 and
locked restores, tests the packages that its Release leg packs (and that a release publishes) instead of packing
them again, and requires the lock-file guard, the NuGet audit policy (high and critical advisories fail every
build), formatting and the workflow security checks to pass beforeCI / Gatedoes.
Packages
- CheatEngine.Client 1.0.0
- CheatEngine.Client.Abstractions 1.0.0
- CheatEngine.Client.Core 1.0.0
- CheatEngine.Client.Extensions.DependencyInjection 1.0.0
- CheatEngine.Client.Fluent 1.0.0
- CheatEngine.Client.Hosting 1.0.0
- CheatEngine.Client.Templates 1.0.0
The release assets include SHA256SUMS, the SPDX SBOM of each package and their sigstore attestation bundles. RELEASING.md explains how to verify them.