refactor(world): separate live lifetime from spatial buckets
Introduce LiveEntityRuntime as the canonical owner of each accepted server-object incarnation, stable local identity, timestamped state, parent relations, runtime components, and exactly-once teardown. Split logical registration from rebucketing so pending landblocks, equipment attachment, pickup re-entry, and GUID replacement reuse the same entity and effect owners. Keep canonical materialized and visible target/radar views distinct, preserve retail leave_world versus exit_world semantics, gate root simulation while cell-less, and track transitional pre-Create F754 owners through delete and session reset. Remove stale-spawn rehydration and make GpuWorldState spatial-only for live objects. Add lifecycle, generation, pending, unload, attachment, event-publication, local-ID, rollback, and effect-cleanup coverage; update architecture, milestones, memory, and the divergence register. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
8a5d77f7f4
commit
8dd996053d
24 changed files with 2449 additions and 631 deletions
97
src/AcDream.App/World/LiveEntityRuntimeViews.cs
Normal file
97
src/AcDream.App/World/LiveEntityRuntimeViews.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
namespace AcDream.App.World;
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed, storage-free view over animation components owned by a
|
||||
/// <see cref="LiveEntityRuntime"/>. This keeps feature loops type-safe without
|
||||
/// introducing a second component dictionary.
|
||||
/// </summary>
|
||||
public sealed class LiveEntityAnimationRuntimeView<TAnimation>
|
||||
: IEnumerable<KeyValuePair<uint, TAnimation>>
|
||||
where TAnimation : class, ILiveEntityAnimationRuntime
|
||||
{
|
||||
private readonly Func<LiveEntityRuntime?> _runtime;
|
||||
|
||||
public LiveEntityAnimationRuntimeView(Func<LiveEntityRuntime?> runtime) =>
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
|
||||
public int Count => _runtime()?.AnimationRuntimes.Count ?? 0;
|
||||
public IEnumerable<uint> Keys =>
|
||||
_runtime()?.AnimationRuntimes.Keys ?? Array.Empty<uint>();
|
||||
|
||||
public TAnimation this[uint localEntityId]
|
||||
{
|
||||
set
|
||||
{
|
||||
LiveEntityRuntime runtime = _runtime()
|
||||
?? throw new InvalidOperationException("Live entity runtime is not initialized.");
|
||||
if (!runtime.TryGetServerGuid(localEntityId, out uint guid))
|
||||
throw new InvalidOperationException($"No live entity owns local id 0x{localEntityId:X8}.");
|
||||
runtime.SetAnimationRuntime(guid, value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue(uint localEntityId, out TAnimation animation)
|
||||
{
|
||||
if (_runtime()?.TryGetAnimationRuntime(localEntityId, out var found) == true
|
||||
&& found is TAnimation typed)
|
||||
{
|
||||
animation = typed;
|
||||
return true;
|
||||
}
|
||||
|
||||
animation = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Remove(uint localEntityId)
|
||||
{
|
||||
LiveEntityRuntime? runtime = _runtime();
|
||||
return runtime is not null
|
||||
&& runtime.TryGetServerGuid(localEntityId, out uint guid)
|
||||
&& runtime.ClearAnimationRuntime(guid);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<uint, TAnimation>> GetEnumerator()
|
||||
{
|
||||
if (_runtime() is not { } runtime)
|
||||
yield break;
|
||||
foreach (var pair in runtime.AnimationRuntimes)
|
||||
if (pair.Value is TAnimation typed)
|
||||
yield return new KeyValuePair<uint, TAnimation>(pair.Key, typed);
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>Storage-free typed view over remote-motion components.</summary>
|
||||
public sealed class LiveEntityRemoteMotionRuntimeView<TRemoteMotion>
|
||||
where TRemoteMotion : class, ILiveEntityRemoteMotionRuntime
|
||||
{
|
||||
private readonly Func<LiveEntityRuntime?> _runtime;
|
||||
|
||||
public LiveEntityRemoteMotionRuntimeView(Func<LiveEntityRuntime?> runtime) =>
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
|
||||
public TRemoteMotion this[uint serverGuid]
|
||||
{
|
||||
set => (_runtime()
|
||||
?? throw new InvalidOperationException("Live entity runtime is not initialized."))
|
||||
.SetRemoteMotionRuntime(serverGuid, value);
|
||||
}
|
||||
|
||||
public bool TryGetValue(uint serverGuid, out TRemoteMotion motion)
|
||||
{
|
||||
if (_runtime()?.TryGetRemoteMotionRuntime(serverGuid, out var found) == true
|
||||
&& found is TRemoteMotion typed)
|
||||
{
|
||||
motion = typed;
|
||||
return true;
|
||||
}
|
||||
|
||||
motion = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Remove(uint serverGuid) =>
|
||||
_runtime()?.ClearRemoteMotionRuntime(serverGuid) == true;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue