Files
IC.Rebuild/Core/RuntimeSnapshots.cs
T

65 lines
3.1 KiB
C#

using System.Collections.Frozen;
using System.Diagnostics;
namespace ICRebuild.Core;
public sealed record GameFrame(bool Ready, nint LocalAddress, bool IsPvP, bool IsSlowed, DungeonSnapshot Dungeon,nint ActionManagerAddress = 0,nint TargetAddress = 0,uint TargetEntityId = 0,
nint LocalStatusManagerAddress = 0, uint LocalEntityId = 0, bool IsReplay = false)
{
public static readonly GameFrame Empty = new(false,0,false,false,DungeonSnapshot.Empty);
}
// Producers sample thread-affine services only on Framework.Update. Native workers read values only.
public sealed class FrameStore(Func<long>? clock = null, long? maximumAge = null)
{
private sealed record Published(GameFrame Frame,long Time);
private readonly Func<long> now = clock ?? Stopwatch.GetTimestamp;
private readonly long ttl = maximumAge ?? Stopwatch.Frequency / 2;
private Published? current;
public void Publish(GameFrame frame) => Volatile.Write(ref current,new(frame,now()));
public void Clear() => Volatile.Write(ref current,null);
public GameFrame Read()
{
var value=Volatile.Read(ref current);
if(value==null) return GameFrame.Empty;
var age=now()-value.Time;
return age<0 || age>ttl ? GameFrame.Empty : value.Frame;
}
}
public sealed class SettingsSnapshot
{
private readonly float[] values=new float[44];
public FrozenSet<uint> Timelines { get; }
public bool BlockListed { get; }
public DashFilterMode DashMode { get; }
public float KnockSeconds { get; }
public FrozenSet<uint> BlockedStatuses { get; }
public SettingsSnapshot(IReadOnlyDictionary<int,float> source,IEnumerable<uint> timelines,bool blockListed,float knockSeconds,DashFilterMode dashMode = DashFilterMode.BlockListed,
IEnumerable<uint>? blockedStatuses = null)
{
foreach(var f in Features.All) values[f.Id]=Policies.FiniteClamp(source.GetValueOrDefault(f.Id,f.Default),f.Min,f.Max,f.Default);
Timelines=timelines.Where(x=>x>0).ToFrozenSet();
BlockListed=blockListed; KnockSeconds=Policies.FiniteClamp(knockSeconds,0,5);
DashMode=dashMode;
BlockedStatuses=(blockedStatuses ?? []).Where(StatusCatalog.AuditedBlockCandidates.Contains).ToFrozenSet();
}
public float Value(int id) => (uint)id<(uint)values.Length ? values[id] : 0;
}
public static class AccelerationPolicy
{
// Audited in 2026.09.15 and 2026.10.06 executables: native routine consumes and updates +0x44.
// The returned state belongs to the game and MUST NOT be restored to the value before the call.
public const string AuditedVersion="2026.10.06.0000.0000";
public const string BaselineVersion="2026.09.15.0000.0000";
public static bool IsAuditedVersion(string? version) => version is AuditedVersion or BaselineVersion;
public static bool ShouldPrime(GameFrame frame,nint owner,bool moving,float current) =>
frame.Ready && !frame.IsSlowed && frame.LocalAddress!=0 && owner==frame.LocalAddress && moving && float.IsFinite(current);
public static void Run(ref float state,bool prime,Action original)
{
if(prime) state=100;
original();
}
}