(6f231d0fc) Add generic methods for getting linked map entities. TODO: memory-optimized overload for hulls.

This commit is contained in:
Joonas Rikkonen
2019-05-16 06:43:33 +03:00
parent 3d7b229385
commit 3153771cc7
32 changed files with 439 additions and 271 deletions
@@ -111,7 +111,6 @@ namespace Barotrauma
: base (MapEntityPrefab.Find(null, "gap"), submarine)
{
rect = newRect;
linkedTo = new ObservableCollection<MapEntity>();
flowForce = Vector2.Zero;
+22 -8
View File
@@ -78,8 +78,27 @@ namespace Barotrauma
private float[] leftDelta;
private float[] rightDelta;
public List<Gap> ConnectedGaps;
public readonly List<Gap> ConnectedGaps = new List<Gap>();
private string roomName;
[Editable, Serialize("", true, translationTextTag: "RoomName.")]
public string RoomName
{
get { return roomName; }
set
{
if (roomName == value) { return; }
roomName = value;
DisplayName = TextManager.Get(roomName, returnNull: true) ?? roomName;
}
}
public string DisplayName
{
get;
private set;
}
private string roomName;
[Editable, Serialize("", true, translationTextTag: "RoomName.")]
@@ -475,9 +494,6 @@ namespace Barotrauma
OxygenPercentage = 100.0f;
FireSources = new List<FireSource>();
linkedTo = new System.Collections.ObjectModel.ObservableCollection<MapEntity>();
properties = SerializableProperty.GetProperties(this);
@@ -494,8 +510,6 @@ namespace Barotrauma
hullList.Add(this);
ConnectedGaps = new List<Gap>();
if (submarine == null || !submarine.Loading)
{
Item.UpdateHulls();
@@ -844,7 +858,7 @@ namespace Barotrauma
FireSources.Remove(fire);
}
public IEnumerable<Hull> GetConnectedHulls(int? searchDepth)
public IEnumerable<Hull> GetConnectedHulls(int? searchDepth = null)
{
return GetAdjacentHulls(new HashSet<Hull>(), 0, searchDepth);
}
@@ -54,7 +54,6 @@ namespace Barotrauma
public LinkedSubmarine(Submarine submarine)
: base(null, submarine)
{
linkedTo = new System.Collections.ObjectModel.ObservableCollection<MapEntity>();
linkedToID = new List<ushort>();
InsertToList();
@@ -20,14 +20,14 @@ namespace Barotrauma
protected List<ushort> linkedToID;
//observable collection because some entities may need to be notified when the collection is modified
public ObservableCollection<MapEntity> linkedTo;
public readonly ObservableCollection<MapEntity> linkedTo = new ObservableCollection<MapEntity>();
private bool flippedX, flippedY;
public bool FlippedX { get { return flippedX; } }
public bool FlippedY { get { return flippedY; } }
public bool ShouldBeSaved = true;
//the position and dimensions of the entity
protected Rectangle rect;
@@ -41,21 +41,21 @@ namespace Barotrauma
get { return isHighlighted || ExternalHighlight; }
set { isHighlighted = value; }
}
public virtual Rectangle Rect
{
get { return rect; }
set { rect = value; }
}
public Rectangle WorldRect
{
get { return Submarine == null ? rect : new Rectangle((int)(Submarine.Position.X + rect.X), (int)(Submarine.Position.Y + rect.Y), rect.Width, rect.Height); }
}
public virtual Sprite Sprite
public virtual Sprite Sprite
{
get { return null; }
get { return null; }
}
public virtual bool DrawBelowWater
@@ -81,7 +81,7 @@ namespace Barotrauma
return false;
}
}
public virtual bool Linkable
{
get { return false; }
@@ -129,7 +129,7 @@ namespace Barotrauma
set
{
if (aiTarget == null) return;
aiTarget.SoundRange = value;
aiTarget.SoundRange = value;
}
}
@@ -161,13 +161,13 @@ namespace Barotrauma
// Quick undo/redo for size and movement only. TODO: Remove if we do a more general implementation.
private Memento<Rectangle> rectMemento;
public MapEntity(MapEntityPrefab prefab, Submarine submarine) : base(submarine)
public MapEntity(MapEntityPrefab prefab, Submarine submarine) : base(submarine)
{
this.prefab = prefab;
Scale = prefab != null ? prefab.Scale : 1;
}
public virtual void Move(Vector2 amount)
public virtual void Move(Vector2 amount)
{
rect.X += (int)amount.X;
rect.Y += (int)amount.Y;
@@ -205,7 +205,7 @@ namespace Barotrauma
Debug.Assert(clones.Count == entitiesToClone.Count);
//clone links between the entities
for (int i = 0; i < clones.Count; i++)
for (int i = 0; i < clones.Count; i++)
{
if (entitiesToClone[i].linkedTo == null) continue;
foreach (MapEntity linked in entitiesToClone[i].linkedTo)
@@ -265,22 +265,22 @@ namespace Barotrauma
return clones;
}
protected void InsertToList()
{
int i = 0;
if (Sprite==null)
if (Sprite == null)
{
mapEntityList.Add(this);
return;
}
while (i<mapEntityList.Count)
while (i < mapEntityList.Count)
{
i++;
Sprite existingSprite = mapEntityList[i-1].Sprite;
Sprite existingSprite = mapEntityList[i - 1].Sprite;
if (existingSprite == null) continue;
#if CLIENT
if (existingSprite.Texture == this.Sprite.Texture) break;
@@ -289,7 +289,7 @@ namespace Barotrauma
mapEntityList.Insert(i, this);
}
/// <summary>
/// Remove the entity from the entity list without removing links to other entities
/// </summary>
@@ -319,14 +319,14 @@ namespace Barotrauma
if (linkedTo != null)
{
for (int i = linkedTo.Count - 1; i >= 0; i-- )
for (int i = linkedTo.Count - 1; i >= 0; i--)
{
linkedTo[i].RemoveLinked(this);
}
linkedTo.Clear();
}
}
/// <summary>
/// Call Update() on every object in Entity.list
/// </summary>
@@ -409,7 +409,7 @@ namespace Barotrauma
try
{
MethodInfo loadMethod = t.GetMethod("Load", new [] { typeof(XElement), typeof(Submarine) });
MethodInfo loadMethod = t.GetMethod("Load", new[] { typeof(XElement), typeof(Submarine) });
if (loadMethod == null)
{
DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + ".");
@@ -484,7 +484,7 @@ namespace Barotrauma
linkedSub.OnMapLoaded();
}
}
public virtual void OnMapLoaded() { }
public virtual XElement Save(XElement parentElement)
@@ -499,6 +499,37 @@ namespace Barotrauma
if (linkedTo.Contains(e)) linkedTo.Remove(e);
}
/// <summary>
/// Gets all linked entities of specific type.
/// </summary>
public HashSet<T> GetLinkedEntities<T>(HashSet<T> list = null, int? maxDepth = null) where T : MapEntity
{
list = list ?? new HashSet<T>();
int startDepth = 0;
GetLinkedEntitiesRecursive<T>(this, list, ref startDepth, maxDepth);
return list;
}
/// <summary>
/// Gets all linked entities of specific type.
/// </summary>
private static void GetLinkedEntitiesRecursive<T>(MapEntity mapEntity, HashSet<T> linkedTargets, ref int depth, int? maxDepth = null) where T : MapEntity
{
if (depth > maxDepth) { return; }
foreach (var linkedEntity in mapEntity.linkedTo)
{
if (linkedEntity is T linkedTarget)
{
if (!linkedTargets.Contains(linkedTarget))
{
linkedTargets.Add(linkedTarget);
depth++;
GetLinkedEntitiesRecursive(linkedEntity, linkedTargets, ref depth, maxDepth);
}
}
}
}
#region Serialized properties
// We could use NaN or nullables, but in this case the first is not preferable, because it needs to be checked every time the value is used.
// Nullable on the other requires boxing that we don't want to do too often, since it generates garbage.
@@ -115,7 +115,6 @@ namespace Barotrauma
Linkable = true
};
ep.AllowedLinks.Add("hull");
ep.Aliases = new HashSet<string> { "hull" };
List.Add(ep);
ep = new MapEntityPrefab
@@ -225,6 +225,12 @@ namespace Barotrauma
string nonTranslatedName = element.GetAttributeString("name", null) ?? element.Name.ToString();
sp.Aliases.Add(nonTranslatedName.ToLowerInvariant());
SerializableProperty.DeserializeProperties(sp, element);
if (sp.Body)
{
sp.Tags.Add("wall");
}
SerializableProperty.DeserializeProperties(sp, element);
if (sp.Body)
{
@@ -111,7 +111,6 @@ namespace Barotrauma
: base (prefab, submarine)
{
rect = newRect;
linkedTo = new ObservableCollection<MapEntity>();
idCardTags = new string[0];
#if CLIENT