From d7448c497db8648774219631ec61b6b034abd8cb Mon Sep 17 00:00:00 2001 From: Mike McGhen Date: Tue, 21 Jul 2026 18:28:35 -0400 Subject: [PATCH] Grid-scope the food-gift and trade-partner searches Route the two remaining full-population scans (a hungry villager seeking someone with food; a trader seeking a partner) through the NPC spatial grid with a 60-cell reach instead of scanning all ~80 villagers. Realistic reach, cheaper at scale. (A resource-node spatial index was also tried and reverted: benchmarked ~13% slower - at ~1,260 nodes the linear array scan is cache-friendly and beats a dictionary-of-lists ring search. The node scan was never the bottleneck; profile before optimizing next time.) Co-Authored-By: Claude Fable 5 --- scripts/NPC.cs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/scripts/NPC.cs b/scripts/NPC.cs index ef4d70f..650d163 100644 --- a/scripts/NPC.cs +++ b/scripts/NPC.cs @@ -453,15 +453,17 @@ public class Npc // this keeps gifts meaningful instead of a food-swapping loop. if (Nourishment >= 0.55f) { Enter(NpcState.Socializing); return; } float bestScore = float.MinValue; - foreach (var other in gm.Npcs) + Npc? giftFound = null; + gm.Grid.ForEachNear(Position, 60f, other => { - if (other == this) continue; + if (other == this) return; float warmth = GetWarmth(other.Name); - if (warmth < -0.3f) continue; - if (!other.Inventory.TryGetValue(MaterialKind.Food, out float f) || f <= 3f) continue; + if (warmth < -0.3f) return; + if (!other.Inventory.TryGetValue(MaterialKind.Food, out float f) || f <= 3f) return; float score = warmth * 40f - Position.DistanceTo(other.Position); - if (score > bestScore) { bestScore = score; _giftSource = other; } - } + if (score > bestScore) { bestScore = score; giftFound = other; } + }); + _giftSource = giftFound; if (_giftSource != null) return; } @@ -503,13 +505,15 @@ public class Npc if (_targetNpc == null) { float bestDist = float.MaxValue; - foreach (var other in gm.Npcs) + Npc? partner = null; + gm.Grid.ForEachNear(Position, 60f, other => { - if (other == this) continue; - if (!TradeSystem.CanTrade(this, other, out _)) continue; + if (other == this) return; + if (!TradeSystem.CanTrade(this, other, out _)) return; float d = Position.DistanceSquaredTo(other.Position); - if (d < bestDist) { bestDist = d; _targetNpc = other; } - } + if (d < bestDist) { bestDist = d; partner = other; } + }); + _targetNpc = partner; if (_targetNpc == null) { Enter(NpcState.Building); return; } }