fix: Cleans up doors and house placement (#1560)

This commit is contained in:
Kamron Batman 2023-10-21 14:20:16 -07:00 committed by GitHub
parent 6239b418a8
commit 68f3e15e5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 136 additions and 73 deletions

View file

@ -21,7 +21,7 @@ namespace Server;
public partial class Map
{
private int _iteratingItems;
private List<(MapAction, Point3D, Item)> _delayedItemActions = new();
private readonly List<(MapAction, Point3D, Item)> _delayedItemActions = new();
public bool IsIteratingItems
{
@ -29,15 +29,58 @@ public partial class Map
get => _iteratingItems > 0;
}
public ItemEnumerable<Item> GetItemsInRange(Point3D p) => GetItemsInRange(p, Core.GlobalMaxUpdateRange);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<Item> GetItemsAt(Point3D p) => GetItemsInRange(p, 0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsAt<T>(Point3D p) where T : Item => GetItemsInRange<T>(p, 0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<Item> GetItemsInRange(Point3D p) => GetItemsInRange<Item>(p);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<Item> GetItemsInRange(Point3D p, int range) => GetItemsInRange<Item>(p, range);
public ItemEnumerable<T> GetItemsInRange<T>(Point3D p, int range) where T : Item =>
GetItemsInBounds<T>(new Rectangle2D(p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsInRange<T>(Point3D p) where T : Item => GetItemsInRange<T>(p, Core.GlobalMaxUpdateRange);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsInRange<T>(Point3D p, int range) where T : Item =>
GetItemsInRange<T>(p.m_X, p.m_Y, range);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<Item> GetItemsAt(Point2D p) => GetItemsInRange(p, 0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsAt<T>(Point2D p) where T : Item => GetItemsInRange<T>(p, 0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<Item> GetItemsInRange(Point2D p) => GetItemsInRange<Item>(p);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<Item> GetItemsInRange(Point2D p, int range) => GetItemsInRange<Item>(p, range);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsInRange<T>(Point2D p) where T : Item => GetItemsInRange<T>(p, Core.GlobalMaxUpdateRange);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsInRange<T>(Point2D p, int range) where T : Item =>
GetItemsInRange<T>(p.m_X, p.m_Y, range);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<Item> GetItemsAt(int x, int y) => GetItemsAt<Item>(x, y);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsAt<T>(int x, int y) where T : Item => GetItemsInRange<T>(x, y, 0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsInRange<T>(int x, int y, int range) where T : Item =>
GetItemsInBounds<T>(new Rectangle2D(x - range, y - range, range * 2 + 1, range * 2 + 1));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<Item> GetItemsInBounds(Rectangle2D bounds) => GetItemsInBounds<Item>(bounds);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ItemEnumerable<T> GetItemsInBounds<T>(Rectangle2D bounds, bool makeBoundsInclusive = false) where T : Item =>
new(this, bounds, makeBoundsInclusive);

View file

@ -535,6 +535,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
return new Point2D(x, y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CalculateSectors(
Rectangle2D bounds,
out int sectorStartX, out int sectorStartY,

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using ModernUO.Serialization;
using Server.Targeting;
@ -226,12 +227,13 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
private static void EventSink_OpenDoorMacroUsed(Mobile m)
{
if (m.Map == null)
if (m.Map == null || !m.CheckAlive())
{
return;
}
int x = m.X, y = m.Y;
int x = m.X;
int y = m.Y;
switch (m.Direction & Direction.Mask)
{
@ -281,18 +283,13 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
}
}
var sector = m.Map.GetSector(x, y);
foreach (var item in sector.Items)
foreach (var item in m.Map.GetItemsAt(x, y))
{
if (item.Location.X == x && item.Location.Y == y && item.Z + item.ItemData.Height > m.Z &&
if (item.Z + item.ItemData.Height > m.Z &&
m.Z + 16 > item.Z && item is BaseDoor && m.CanSee(item) && m.InLOS(item))
{
if (m.CheckAlive())
{
m.SendLocalizedMessage(500024); // Opening door...
item.OnDoubleClick(m);
}
m.SendLocalizedMessage(500024); // Opening door...
item.OnDoubleClick(m);
break;
}
@ -320,7 +317,7 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
return CheckFit(map, p, 16);
}
private bool CheckFit(Map map, Point3D p, int height)
private static bool CheckFit(Map map, Point3D p, int height)
{
if (map == Map.Internal)
{
@ -331,13 +328,9 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
var y = p.Y;
var z = p.Z;
var sector = map.GetSector(x, y);
var mobs = sector.Mobiles;
foreach (var item in sector.Items)
foreach (var item in map.GetItemsAt(x, y))
{
if (item is not BaseMulti && item.ItemID <= TileData.MaxItemValue && item.AtWorldPoint(x, y) &&
item is not BaseDoor)
if (item.ItemID <= TileData.MaxItemValue && item is not (BaseMulti or BaseDoor))
{
var id = item.ItemData;
var surface = id.Surface;
@ -350,6 +343,8 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
}
}
var mobs = map.GetSector(x, y).Mobiles;
for (var i = 0; i < mobs.Count; ++i)
{
var m = mobs[i];
@ -376,19 +371,7 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
return true;
}
public List<BaseDoor> GetChain()
{
var list = new List<BaseDoor>();
var c = this;
do
{
list.Add(c);
c = c.Link;
} while (c?.Deleted == false && !list.Contains(c));
return list;
}
public ChainEnumerable GetChain() => new(this);
public bool IsFreeToClose()
{
@ -397,16 +380,15 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
return CanClose();
}
var list = GetChain();
var freeToClose = true;
for (var i = 0; freeToClose && i < list.Count; ++i)
foreach (var link in GetChain())
{
freeToClose = list[i].CanClose();
if (!link.CanClose())
{
return false;
}
}
return freeToClose;
return true;
}
public virtual bool IsInside(Mobile from) => false;
@ -419,28 +401,18 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
{
if (from.AccessLevel >= AccessLevel.GameMaster)
{
from.LocalOverheadMessage(
MessageType.Regular,
0x3B2,
502502
); // That is locked, but you open it with your godly powers.
// from.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x3B2, 3, 502502, "", "" ) ); // That is locked, but you open it with your godly powers.
// That is locked, but you open it with your godly powers.
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502502);
}
else if (Key.ContainsKey(from.Backpack, KeyValue))
{
from.LocalOverheadMessage(
MessageType.Regular,
0x3B2,
501282
); // You quickly unlock, open, and relock the door
// You quickly unlock, open, and relock the door
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501282);
}
else if (IsInside(from))
{
from.LocalOverheadMessage(
MessageType.Regular,
0x3B2,
501280
); // That is locked, but is usable from the inside.
// That is locked, but is usable from the inside.
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501280);
}
else
{
@ -475,11 +447,9 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
{
var open = !_open;
var list = GetChain();
for (var i = 0; i < list.Count; ++i)
foreach (var link in GetChain())
{
list[i].Open = open;
link.Open = open;
}
}
else
@ -540,4 +510,58 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
}
}
}
public ref struct ChainEnumerable
{
private readonly BaseDoor _door;
public ChainEnumerable(BaseDoor door) => _door = door;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ChainEnumerator GetEnumerator() => new(_door);
}
public ref struct ChainEnumerator
{
private BaseDoor _door;
private BaseDoor _current;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ChainEnumerator(BaseDoor door)
{
_door = door;
_current = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
bool valid;
if (_current == null)
{
_current = _door;
valid = _current != null;
}
else
{
_current = _current.Link;
valid = _current?.Deleted == false && _current != _door;
}
if (!valid)
{
_door = null;
_current = null;
}
return valid;
}
public BaseDoor Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _current;
}
}
}

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Server.Collections;
using Server.Regions;
using Server.Spells;
@ -80,7 +81,7 @@ namespace Server.Multis
var start = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Min.Y, center.Z);
// These are storage lists. They hold items and mobiles found in the map for further processing
var items = new List<Item>();
using var items = PooledRefList<Item>.Create();
var mobiles = new List<Mobile>();
// These are also storage lists. They hold location values indicating the yard and border locations.
@ -138,11 +139,9 @@ namespace Server.Multis
var oldTiles = map.Tiles.GetStaticTiles(tileX, tileY, true);
var sector = map.GetSector(tileX, tileY);
items.Clear();
foreach (var item in sector.Items)
foreach (var item in map.GetItemsAt(tileX, tileY))
{
if (item.Visible && item.X == tileX && item.Y == tileY)
{
@ -152,6 +151,8 @@ namespace Server.Multis
mobiles.Clear();
var sector = map.GetSector(tileX, tileY);
for (var i = 0; i < sector.Mobiles.Count; ++i)
{
var m = sector.Mobiles[i];
@ -220,9 +221,8 @@ namespace Server.Multis
hasSurface = true;*/
}
for (var j = 0; j < items.Count; ++j)
foreach (var item in items)
{
var item = items[j];
var id = item.ItemData;
if (addTileTop > item.Z && item.Z + id.CalcHeight > addTileZ)
@ -236,11 +236,6 @@ namespace Server.Multis
return HousePlacementResult.BadItem; // Broke rule #2
}
}
/*else if (isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (item.Z + id.CalcHeight) == center.Z)
{
hasSurface = true;
}*/
}
if (isFoundation && !hasSurface)