Pin the mount aim's resolved reads, the record's isolation and its Deactivate clear; delete two dead guards

Forecast and Fire drop a mount aim whose gate closed (destroyed, unidentified); a record for one Bay never hides another's mount; Deactivate clears the record. Deleted: the located-or-booked guard in RecordSeenDestroyed and the Entity == subject check in ResolvedAim (the record is read only for layout mounts; a Target change already clears the slot). Comments name AimedAt. Not built or run yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-15 07:14:35 +02:00
commit a54e2f53df
5 changed files with 81 additions and 9 deletions

View file

@ -459,7 +459,7 @@ public abstract class Entity
var subject = Target.Value.Entity;
var aim = AimedAt;
if (subject == null) return AimTarget.None;
if (aim.Item != null) return aim.Item.Entity == subject && FireControl.IsRevealed(this, aim.Item) ? aim : AimTarget.None;
if (aim.Item != null) return FireControl.IsRevealed(this, aim.Item) ? aim : AimTarget.None;
return MountAimable(subject, aim.Mount) ? aim : AimTarget.None;
}
}
@ -1055,17 +1055,16 @@ public abstract class Entity
if (subject.Parent == null && !Zone.Entities.Contains(subject) && !_reveals.ContainsKey(subject)) _iffOverrides.Remove(subject);
}
// This observer perceives `subject`'s gear (ContactOf's Identified gate): each of its destroyed items on a mount of the
// hull this ship believes it to be (LayoutOf, by reference) or in the book leaves its mount in the seen-destroyed
// record. The same PerceivesDestroyed Sense ends reveals by, applied to located mounts.
// This observer perceives `subject`'s gear (ContactOf's Identified gate): each of its destroyed items leaves its mount
// in the seen-destroyed record. The same PerceivesDestroyed Sense ends reveals by, applied to mounts. The record is read
// only for mounts of LayoutOf (MountAimable, AimCycle), so a true mount outside the believed layout is never asked for.
private void RecordSeenDestroyed(Entity subject)
{
// Indexed, and the layout read only for an item actually perceived destroyed: Sense runs for every pair of ships every tick.
// Indexed: Sense runs for every pair of ships every tick.
for (var i = 0; i < subject.Equipment.Count; i++)
{
var item = subject.Equipment[i];
if (item.Hardpoint == null || !PerceivesDestroyed(subject, item)) continue;
if (!LayoutOf(subject).Contains(item.Hardpoint) && !(_reveals.TryGetValue(subject, out var book) && book.ContainsKey(item))) continue;
if (!_seenDestroyed.TryGetValue(subject, out var seen)) _seenDestroyed[subject] = seen = new HashSet<HardpointData>();
seen.Add(item.Hardpoint);
}

View file

@ -321,8 +321,8 @@ public static class FireControl
// GetBehavior<TargetingSystem> calls (Accuracy, Resolution via PSensor, Precision), at ~40 B each -- each
// one walks Entity.Equipment, a ReactiveCollection<T> whose enumerator is heap-allocated per foreach. It is
// NOT `Behaviors` (the earlier wording here was wrong): EquippedItem.Behaviors is a plain array, allocates
// nothing to enumerate. With an item aimed at, ResolveAimPoint -> CellsOf also allocates (a List, then
// ToArray) -- about 944 B per HitProbability, on top of the three GetBehavior calls. None of this is
// nothing to enumerate. With an item or a mount aimed at, ResolveAimPoint also allocates: CellsOf (a List, then
// ToArray) about 944 B per HitProbability, measured; MountCells (a LINQ Select, then ToArray) not measured. Both are on top of the three GetBehavior calls. None of this is
// Silhouette's or this pooling's cost; it predates Cut 12.2 and belongs to Entity's own collection choice
// and to CellsOf, out of this cut's scope. Cut 10's own guard is what actually matters
// operationally: HitProbability and CommitProbability both bail before Forecast is ever called for the

View file

@ -122,7 +122,7 @@ public readonly struct Reveal
}
}
// What an observer aims at on its target (Entity.Aim): exactly one of a revealed item or a mount of the hull the observer
// What an observer aims at on its target (Entity.AimedAt): exactly one of a revealed item or a mount of the hull the observer
// believes the target to be (Entity.LayoutOf), or nothing. A mount is a believed position, never the true item on it.
public readonly struct AimTarget
{