refactor(camera): extract the update frame
Move fly/chase publication, combat target tracking, and local player projection behind typed runtime owners. Preserve the inbound-created projection/reconcile barrier while removing GameWindow callbacks and duplicate shadow helpers.
This commit is contained in:
parent
eeb0f6b45c
commit
947c61d2d7
19 changed files with 988 additions and 356 deletions
|
|
@ -0,0 +1,69 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Combat;
|
||||
using AcDream.App.Interaction;
|
||||
using AcDream.Core.Combat;
|
||||
using AcDream.Core.Selection;
|
||||
|
||||
namespace AcDream.App.Tests.Combat;
|
||||
|
||||
public sealed class CombatCameraTargetSourceTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetTrackedTargetPoint_RequiresOptionTargetedModeAndSelection()
|
||||
{
|
||||
const uint target = 0x70000001u;
|
||||
Vector3 point = new(10f, 20f, 30f);
|
||||
var settings = new GameplaySettingsState();
|
||||
var combat = new CombatState();
|
||||
var selection = new SelectionState();
|
||||
var world = new TargetQuery(point);
|
||||
var source = new CombatCameraTargetSource(
|
||||
settings,
|
||||
combat,
|
||||
selection,
|
||||
world);
|
||||
|
||||
Assert.Null(source.GetTrackedTargetPoint());
|
||||
|
||||
settings.Value = settings.Value with { ViewCombatTarget = true };
|
||||
combat.SetCombatMode(CombatMode.Melee);
|
||||
selection.Select(target, SelectionChangeSource.World);
|
||||
|
||||
Assert.Equal(point, source.GetTrackedTargetPoint());
|
||||
Assert.Equal(target, world.LastGuid);
|
||||
|
||||
combat.SetCombatMode(CombatMode.Magic);
|
||||
Assert.Null(source.GetTrackedTargetPoint());
|
||||
}
|
||||
|
||||
private sealed class TargetQuery(Vector3 point) : IWorldSelectionQuery
|
||||
{
|
||||
public uint LastGuid { get; private set; }
|
||||
public Vector3? GetCombatCameraTargetPoint(uint serverGuid)
|
||||
{
|
||||
LastGuid = serverGuid;
|
||||
return point;
|
||||
}
|
||||
|
||||
public uint? PickAtCursor(bool includeSelf) => null;
|
||||
public uint? PickAt(float mouseX, float mouseY, bool includeSelf) => null;
|
||||
public void BeginLightingPulse(uint serverGuid) { }
|
||||
public bool TryCaptureIdentity(uint serverGuid, out uint localEntityId)
|
||||
{
|
||||
localEntityId = 0;
|
||||
return false;
|
||||
}
|
||||
public bool IsCurrent(uint serverGuid, uint localEntityId) => false;
|
||||
public string Describe(uint serverGuid) => string.Empty;
|
||||
public bool IsCreature(uint serverGuid) => false;
|
||||
public bool IsHostileMonster(uint serverGuid) => false;
|
||||
public ClosestCombatTarget? FindClosestHostileMonster() => null;
|
||||
public bool IsUseable(uint serverGuid) => false;
|
||||
public bool IsPickupable(uint serverGuid) => false;
|
||||
public bool TryGetApproach(uint serverGuid, out InteractionApproach approach)
|
||||
{
|
||||
approach = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -120,6 +120,7 @@ public sealed class LiveCombatAttackOperationsTests
|
|||
{
|
||||
public bool AutoTarget { get; set; }
|
||||
public bool AutoRepeatAttack { get; set; }
|
||||
public bool ViewCombatTarget { get; set; }
|
||||
}
|
||||
|
||||
private sealed class FakeLiveSource : ILiveInWorldSource, ILiveWorldSessionSource
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue