feat: Add spawn position caching and spiral scan optimization (#2295)

### Summary

Adds spawn position caching and optimization for constrained spawners (e.g., those near houses, water, or blocked terrain).

### Key features:
- Sector-based bitmap cache (32 bytes per 16x16 sector) stores valid spawn positions
- Spiral scan progressively discovers positions from spawner center outward
- Automatic mode detects constrained spawners after 5+ non-transient failures
- Prevents mob spawning inside private houses (allows public AoS buildings)
- Deduplicates sector lookups for multi-bounds spawners (RegionSpawner)
- Cache invalidation on house placement/demolition
- Moves SpawnBounds to Spawner

### New spawner properties:
- SpawnPositionMode: Automatic (default), Enabled, Disabled, Abandoned
- MaxSpawnAttempts: Configurable attempts before optimization engages (default: 5)
This commit is contained in:
Kamron Batman 2025-12-28 02:40:21 -08:00 • committed by GitHub
parent 6d51b33cf8
commit 3e8d548f38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 1938 additions and 153 deletions

View file

@ -31,6 +31,38 @@ public abstract partial class BaseSpawner
}
_spawnLocationIsHome = false;
// New v12 fields default to automatic/default
_spawnPositionMode = SpawnPositionMode.Automatic;
_maxSpawnAttempts = DefaultMaxSpawnAttempts;
}
private void MigrateFrom(V11Content content)
{
_guid = content.Guid;
_returnOnDeactivate = content.ReturnOnDeactivate;
_entries = content.Entries;
_walkingRange = content.WalkingRange;
_wayPoint = content.WayPoint;
_group = content.Group;
_minDelay = content.MinDelay;
_maxDelay = content.MaxDelay;
_count = content.Count;
_team = content.Team;
// Moved to Spawner
if (this is Spawner spawner)
{
spawner.SpawnBounds = content.SpawnBounds;
}
_running = content.Running;
_spawnLocationIsHome = content.SpawnLocationIsHome;
_end = _running ? content.End : Core.Now;
// New v12 fields default to automatic/default
_spawnPositionMode = SpawnPositionMode.Automatic;
_maxSpawnAttempts = DefaultMaxSpawnAttempts;
}
private void Deserialize(IGenericReader reader, int version)