ModernUO/Projects/UOContent/Engines/Spawners/SpawnPositionState.cs
Kamron Batman 3e8d548f38
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)
2025-12-28 02:40:21 -08:00

80 lines
3.3 KiB
C#

/*************************************************************************
* ModernUO *
* Copyright 2019-2025 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: SpawnPositionState.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
namespace Server.Engines.Spawners;
/// <summary>
/// Runtime state for spawn position optimization.
/// Not serialized - resets on server restart.
/// </summary>
public sealed class SpawnPositionState
{
// Tunable thresholds for auto-detection
private const int FailureThreshold = 5;
private const int AbandonThreshold = 25;
// Failure tracking for auto-detection
private int _nonTransientFailures;
// Abandon tracking - counts consecutive cache misses or Location-only results
private int _consecutiveUselessResults;
// Spiral scan state
public int SpiralRing;
public int SpiralRingPosition;
public bool SpiralComplete;
/// <summary>
/// Resets all state. Called when spawner moves or bounds change.
/// </summary>
public void Reset()
{
_nonTransientFailures = 0;
_consecutiveUselessResults = 0;
SpiralRing = 0;
SpiralRingPosition = 0;
SpiralComplete = false;
}
/// <summary>
/// Records a useful cache hit (position other than spawner's own location).
/// Resets the abandon counter.
/// </summary>
public void RecordUsefulCacheHit() => _consecutiveUselessResults = 0;
/// <summary>
/// Records a useless result (cache miss or cache returned spawner's location).
/// Counts toward abandonment threshold.
/// </summary>
public void RecordUselessResult() => _consecutiveUselessResults++;
/// <summary>
/// Records a non-transient spawn failure for auto-detection.
/// </summary>
public void RecordNonTransientFailure() => _nonTransientFailures++;
/// <summary>
/// Returns true if the spawner should cache successful positions.
/// </summary>
public bool ShouldCachePositions(SpawnPositionMode mode) =>
mode == SpawnPositionMode.Enabled || mode == SpawnPositionMode.Automatic && _nonTransientFailures > FailureThreshold;
/// <summary>
/// Returns true if the spawner should be marked as abandoned.
/// Triggers after spiral completes, and we get consecutive useless results
/// (cache misses or cache only returning spawner's own location).
/// </summary>
public bool ShouldAbandon() => SpiralComplete && _consecutiveUselessResults >= AbandonThreshold;
}