fix: Fixes zero height spawners and normalizes spawn bounds before use. (#2301)
This commit is contained in:
parent
723e1a836d
commit
ec287d7691
2 changed files with 23 additions and 8 deletions
|
|
@ -81,6 +81,16 @@ public struct Rectangle3D : IEquatable<Rectangle3D>, ISpanFormattable
|
|||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Depth => _end.Z - _start.Z;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized rectangle where Start contains the minimum coordinates
|
||||
/// and End contains the maximum coordinates in all dimensions.
|
||||
/// Use this when Start/End ordering matters (e.g., Contains checks, Z range calculations).
|
||||
/// </summary>
|
||||
public Rectangle3D Normalized => new(
|
||||
new Point3D(Math.Min(_start.X, _end.X), Math.Min(_start.Y, _end.Y), Math.Min(_start.Z, _end.Z)),
|
||||
new Point3D(Math.Max(_start.X, _end.X), Math.Max(_start.Y, _end.Y), Math.Max(_start.Z, _end.Z))
|
||||
);
|
||||
|
||||
public bool Equals(Rectangle3D other) => _start == other._start && _end == other._end;
|
||||
|
||||
public override bool Equals(object obj) => obj is Rectangle3D other && Equals(other);
|
||||
|
|
|
|||
|
|
@ -568,18 +568,21 @@ public abstract partial class BaseSpawner : Item, ISpawner
|
|||
var maxAttempts = _maxSpawnAttempts > 0 ? _maxSpawnAttempts : DefaultMaxSpawnAttempts;
|
||||
for (var i = 0; i < maxAttempts; i++)
|
||||
{
|
||||
var bounds = GetBoundsForSpawnAttempt();
|
||||
var rawBounds = GetBoundsForSpawnAttempt();
|
||||
|
||||
// No bounds = spawn at spawner location
|
||||
if (bounds == default)
|
||||
if (rawBounds == default)
|
||||
{
|
||||
return Location;
|
||||
}
|
||||
|
||||
// Normalize to ensure Start <= End in all dimensions
|
||||
var bounds = rawBounds.Normalized;
|
||||
|
||||
var x = Utility.RandomMinMax(bounds.Start.X, bounds.End.X - 1);
|
||||
var y = Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y - 1);
|
||||
var minZ = bounds.Start.Z;
|
||||
var maxZ = bounds.End.Z - 1;
|
||||
var maxZ = Math.Max(minZ, bounds.End.Z - 1);
|
||||
|
||||
bool success;
|
||||
int spawnZ;
|
||||
|
|
@ -647,11 +650,12 @@ public abstract partial class BaseSpawner : Item, ISpawner
|
|||
else if (!_spawnPositionState.SpiralComplete)
|
||||
{
|
||||
// Use the first bounds for spiral center/range
|
||||
var primaryBounds = allBounds.Length > 0 ? allBounds[0] : default;
|
||||
if (primaryBounds != default)
|
||||
var rawPrimaryBounds = allBounds.Length > 0 ? allBounds[0] : default;
|
||||
if (rawPrimaryBounds != default)
|
||||
{
|
||||
var primaryBounds = rawPrimaryBounds.Normalized;
|
||||
var minZ = primaryBounds.Start.Z;
|
||||
var maxZ = primaryBounds.End.Z - 1;
|
||||
var maxZ = Math.Max(minZ, primaryBounds.End.Z - 1);
|
||||
|
||||
// Scan more rings initially (3), fewer once cache has positions (1)
|
||||
var ringsPerTick = _spawnPositionState.SpiralRing == 0 ? 3 : 1;
|
||||
|
|
@ -727,8 +731,9 @@ public abstract partial class BaseSpawner : Item, ISpawner
|
|||
}
|
||||
|
||||
// Re-verify in 3D using the bounds that contains this position
|
||||
var minZ = containingBounds.Start.Z;
|
||||
var maxZ = containingBounds.End.Z - 1;
|
||||
var normalizedBounds = containingBounds.Normalized;
|
||||
var minZ = normalizedBounds.Start.Z;
|
||||
var maxZ = Math.Max(minZ, normalizedBounds.End.Z - 1);
|
||||
|
||||
var verified = isMobile
|
||||
? map.CanSpawnMobile(cachedPos.X, cachedPos.Y, minZ, maxZ, canSwim, cantWalk, out var verifiedZ)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue