Eliminate repeated behavior graph rebuilds
This commit is contained in:
parent
289051f71a
commit
bd89cb4c85
6 changed files with 143 additions and 7 deletions
|
|
@ -37,7 +37,17 @@ namespace GameCult.Aetheria.State.Verse
|
|||
int targetEquipmentIndex,
|
||||
AetheriaRuntimeBehaviorPayload targetBehavior,
|
||||
int targetFieldKey,
|
||||
double baseline)
|
||||
double baseline) =>
|
||||
Apply(entity, catalog, targetEquipmentIndex, targetBehavior, targetFieldKey, baseline, null);
|
||||
|
||||
internal static double Apply(
|
||||
AetheriaRuntimeEntitySnapshotCommit entity,
|
||||
AetheriaRuntimeCatalogSnapshot catalog,
|
||||
int targetEquipmentIndex,
|
||||
AetheriaRuntimeBehaviorPayload targetBehavior,
|
||||
int targetFieldKey,
|
||||
double baseline,
|
||||
IReadOnlyList<AetheriaRuntimeEquippedBehavior>? equippedModifiers)
|
||||
{
|
||||
var targetStatName = StatName(targetBehavior?.Kind, targetFieldKey);
|
||||
if (entity == null || catalog == null || targetEquipmentIndex < 0 ||
|
||||
|
|
@ -46,7 +56,7 @@ namespace GameCult.Aetheria.State.Verse
|
|||
|
||||
double multiplier = 1;
|
||||
double constant = 0;
|
||||
foreach (var modifier in ActiveEquippedModifiers(entity, catalog)
|
||||
foreach (var modifier in ActiveEquippedModifiers(entity, catalog, equippedModifiers)
|
||||
.Concat(ActiveConsumableModifiers(entity, catalog)))
|
||||
{
|
||||
if (!Targets(modifier.Payload, entity, catalog, targetEquipmentIndex, targetBehavior, targetStatName))
|
||||
|
|
@ -360,9 +370,11 @@ namespace GameCult.Aetheria.State.Verse
|
|||
|
||||
private static IEnumerable<ModifierValue> ActiveEquippedModifiers(
|
||||
AetheriaRuntimeEntitySnapshotCommit entity,
|
||||
AetheriaRuntimeCatalogSnapshot catalog)
|
||||
AetheriaRuntimeCatalogSnapshot catalog,
|
||||
IReadOnlyList<AetheriaRuntimeEquippedBehavior>? equippedModifiers = null)
|
||||
{
|
||||
foreach (var behavior in AetheriaRuntimeEquippedBehaviorQueries.FindOperational(entity, catalog, "StatModifier"))
|
||||
foreach (var behavior in equippedModifiers ??
|
||||
AetheriaRuntimeEquippedBehaviorQueries.FindOperational(entity, catalog, "StatModifier"))
|
||||
{
|
||||
if (!behavior.State.StatModifierApplied)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ namespace GameCult.Aetheria.State.Verse
|
|||
return;
|
||||
|
||||
var existing = entity.BehaviorStates ?? Array.Empty<AetheriaRuntimeBehaviorStateCommit>();
|
||||
if (EquipmentBehaviorStatesMatch(existing, entity.Equipment, catalog))
|
||||
return;
|
||||
var projected = CreateEquipmentBehaviorStates(entity.Equipment, catalog);
|
||||
if (projected.Length == 0)
|
||||
{
|
||||
|
|
@ -95,5 +97,37 @@ namespace GameCult.Aetheria.State.Verse
|
|||
state.BehaviorIndex.ToString(System.Globalization.CultureInfo.InvariantCulture),
|
||||
state.BehaviorKind ?? "");
|
||||
}
|
||||
|
||||
private static bool EquipmentBehaviorStatesMatch(
|
||||
IReadOnlyList<AetheriaRuntimeBehaviorStateCommit> existing,
|
||||
IReadOnlyList<AetheriaRuntimeLoadoutItemSlotCommit>? equipment,
|
||||
AetheriaRuntimeCatalogSnapshot? catalog)
|
||||
{
|
||||
catalog ??= new AetheriaRuntimeCatalogSnapshot();
|
||||
var matched = 0;
|
||||
var slots = equipment ?? Array.Empty<AetheriaRuntimeLoadoutItemSlotCommit>();
|
||||
for (var equipmentIndex = 0; equipmentIndex < slots.Count; equipmentIndex++)
|
||||
{
|
||||
var item = slots[equipmentIndex]?.Item;
|
||||
var payloads = catalog.FindItem(item?.ItemKey ?? "")?.BehaviorPayloads ??
|
||||
Array.Empty<AetheriaRuntimeBehaviorPayload>();
|
||||
for (var behaviorIndex = 0; behaviorIndex < payloads.Count; behaviorIndex++)
|
||||
{
|
||||
var payload = payloads[behaviorIndex];
|
||||
if (payload == null || string.IsNullOrWhiteSpace(payload.Kind))
|
||||
continue;
|
||||
matched++;
|
||||
if (!existing.Any(state => state != null &&
|
||||
string.Equals(state.OwnerKind, EquipmentOwnerKind, StringComparison.Ordinal) &&
|
||||
state.OwnerIndex == equipmentIndex &&
|
||||
state.BehaviorIndex == behaviorIndex &&
|
||||
string.Equals(state.BehaviorKind, payload.Kind, StringComparison.Ordinal)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return existing.Count(state => state != null &&
|
||||
string.Equals(state.OwnerKind, EquipmentOwnerKind, StringComparison.Ordinal)) == matched;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,15 @@ namespace GameCult.Aetheria.State.Verse
|
|||
Environment.GetEnvironmentVariable("AETHERIA_TRACE_SIMULATION_PHASES"),
|
||||
"1",
|
||||
StringComparison.Ordinal);
|
||||
var traceSimulationPhaseThreshold = int.TryParse(
|
||||
Environment.GetEnvironmentVariable("AETHERIA_TRACE_SIMULATION_PHASE_THRESHOLD_MS"),
|
||||
out var configuredTraceThreshold)
|
||||
? Math.Max(0, configuredTraceThreshold)
|
||||
: 20;
|
||||
var phase = Stopwatch.StartNew();
|
||||
void TracePhase(string name)
|
||||
{
|
||||
if (traceSimulationPhases && phase.ElapsedMilliseconds >= 20)
|
||||
if (traceSimulationPhases && phase.ElapsedMilliseconds >= traceSimulationPhaseThreshold)
|
||||
Console.WriteLine($"Aetheria simulation phase {name} took {phase.ElapsedMilliseconds}ms.");
|
||||
phase.Restart();
|
||||
}
|
||||
|
|
@ -597,9 +602,13 @@ namespace GameCult.Aetheria.State.Verse
|
|||
RefreshShieldProjection(entity, catalog);
|
||||
foreach (var attacker in combatEntities)
|
||||
{
|
||||
var requestedWeapons = ResolveWeaponTriggers(zone, attacker, entities, intents, catalog);
|
||||
var operationalBehaviors = AetheriaRuntimeEquippedBehaviorQueries
|
||||
.FindAllOperational(attacker, catalog);
|
||||
if (!operationalBehaviors.Any(behavior =>
|
||||
AetheriaRuntimeBehaviorMetadataCatalog.IsKindOrDescendant(
|
||||
behavior.Payload.Kind, "Weapon")))
|
||||
continue;
|
||||
var requestedWeapons = ResolveWeaponTriggers(zone, attacker, entities, intents, catalog);
|
||||
StepDeployableWeapons(run, zone, attacker, operationalBehaviors, requestedWeapons,
|
||||
deltaSeconds, settings, catalog, frameId);
|
||||
StepChargedWeapons(run, zone, attacker, byIndex, requestedWeapons, deltaSeconds,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ namespace GameCult.Aetheria.State.Verse
|
|||
|
||||
public sealed class AetheriaRuntimeEquippedBehavior
|
||||
{
|
||||
private IReadOnlyList<AetheriaRuntimeEquippedBehavior>? modifierBehaviors;
|
||||
|
||||
public AetheriaRuntimeEquippedBehavior(
|
||||
AetheriaRuntimeEntitySnapshotCommit entity,
|
||||
AetheriaRuntimeCatalogSnapshot catalog,
|
||||
|
|
@ -61,6 +63,9 @@ namespace GameCult.Aetheria.State.Verse
|
|||
public AetheriaRuntimeBehaviorPayload Payload { get; }
|
||||
public AetheriaRuntimeBehaviorStateCommit State { get; }
|
||||
|
||||
internal void BindModifierBehaviors(IReadOnlyList<AetheriaRuntimeEquippedBehavior> value) =>
|
||||
modifierBehaviors = value ?? Array.Empty<AetheriaRuntimeEquippedBehavior>();
|
||||
|
||||
public double EvaluateStat(int fieldKey, double thermalPerformance = 1.0)
|
||||
{
|
||||
var field = (Payload.Fields ?? Array.Empty<AetheriaRuntimeBehaviorField>())
|
||||
|
|
@ -70,7 +75,7 @@ namespace GameCult.Aetheria.State.Verse
|
|||
Item,
|
||||
Math.Max(0, Math.Min(1, thermalPerformance)));
|
||||
return AetheriaRuntimeBehaviorSimulation.Apply(
|
||||
Entity, Catalog, EquipmentIndex, Payload, fieldKey, baseline);
|
||||
Entity, Catalog, EquipmentIndex, Payload, fieldKey, baseline, modifierBehaviors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +136,18 @@ namespace GameCult.Aetheria.State.Verse
|
|||
state));
|
||||
}
|
||||
}
|
||||
|
||||
var equipmentStates = (entity.EquipmentStates ?? Array.Empty<AetheriaRuntimeEquipmentStateCommit>())
|
||||
.Where(state => state != null)
|
||||
.ToDictionary(state => state.EquipmentIndex);
|
||||
var modifierBehaviors = found
|
||||
.Where(value => AetheriaRuntimeBehaviorMetadataCatalog.IsKindOrDescendant(
|
||||
value.Payload.Kind, "StatModifier"))
|
||||
.Where(value => value.Item.Enabled && value.Item.Durability > 0.01 &&
|
||||
(!equipmentStates.TryGetValue(value.EquipmentIndex, out var state) || state.Online))
|
||||
.ToArray();
|
||||
foreach (var behavior in found)
|
||||
behavior.BindModifierBehaviors(modifierBehaviors);
|
||||
return found;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue