Reapply "OBT1.1.0 Merge branch 'dev_pte' into dev"
This reverts commit 046483b9da.
This commit is contained in:
@@ -10,12 +10,71 @@ using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.PerkBehaviors;
|
||||
using Voronoi2;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
/// <summary>
|
||||
/// Thread-safe wrapper for Submarine list operations.
|
||||
/// Uses copy-on-write pattern for lock-free reads.
|
||||
/// </summary>
|
||||
internal class ThreadSafeSubmarineList : IEnumerable<Submarine>
|
||||
{
|
||||
private volatile List<Submarine> _list = new List<Submarine>();
|
||||
private readonly object _writeLock = new object();
|
||||
|
||||
public int Count => _list.Count;
|
||||
|
||||
public void Add(Submarine submarine)
|
||||
{
|
||||
lock (_writeLock)
|
||||
{
|
||||
var newList = new List<Submarine>(_list) { submarine };
|
||||
Interlocked.Exchange(ref _list, newList);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(Submarine submarine)
|
||||
{
|
||||
lock (_writeLock)
|
||||
{
|
||||
var newList = new List<Submarine>(_list);
|
||||
bool removed = newList.Remove(submarine);
|
||||
if (removed)
|
||||
{
|
||||
Interlocked.Exchange(ref _list, newList);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Interlocked.Exchange(ref _list, new List<Submarine>());
|
||||
}
|
||||
|
||||
public bool Contains(Submarine submarine) => _list.Contains(submarine);
|
||||
|
||||
public Submarine this[int index] => _list[index];
|
||||
|
||||
public IEnumerator<Submarine> GetEnumerator() => _list.GetEnumerator();
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
// LINQ-friendly methods
|
||||
public List<Submarine> ToList() => new List<Submarine>(_list);
|
||||
public Submarine FirstOrDefault(Func<Submarine, bool> predicate) => _list.FirstOrDefault(predicate);
|
||||
public Submarine Find(Predicate<Submarine> predicate) => _list.Find(predicate);
|
||||
public List<Submarine> FindAll(Predicate<Submarine> predicate) => _list.FindAll(predicate);
|
||||
public IEnumerable<Submarine> Where(Func<Submarine, bool> predicate) => _list.Where(predicate);
|
||||
public bool Any() => _list.Any();
|
||||
public bool Any(Func<Submarine, bool> predicate) => _list.Any(predicate);
|
||||
public float Sum(Func<Submarine, float> selector) => _list.Sum(selector);
|
||||
public IEnumerable<TResult> Select<TResult>(Func<Submarine, TResult> selector) => _list.Select(selector);
|
||||
}
|
||||
|
||||
public enum Direction : byte
|
||||
{
|
||||
None = 0, Left = 1, Right = 2
|
||||
@@ -71,7 +130,7 @@ namespace Barotrauma
|
||||
get { return MainSubs[0]; }
|
||||
set { MainSubs[0] = value; }
|
||||
}
|
||||
private static readonly List<Submarine> loaded = new List<Submarine>();
|
||||
private static readonly ThreadSafeSubmarineList loaded = new ThreadSafeSubmarineList();
|
||||
|
||||
private readonly Identifier upgradeEventIdentifier;
|
||||
|
||||
@@ -96,10 +155,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector2 lastPickedPosition;
|
||||
private static float lastPickedFraction;
|
||||
private static Fixture lastPickedFixture;
|
||||
private static Vector2 lastPickedNormal;
|
||||
// ThreadLocal for thread-safe ray casting results
|
||||
private static readonly ThreadLocal<Vector2> lastPickedPositionLocal = new ThreadLocal<Vector2>();
|
||||
private static readonly ThreadLocal<float> lastPickedFractionLocal = new ThreadLocal<float>();
|
||||
private static readonly ThreadLocal<Fixture> lastPickedFixtureLocal = new ThreadLocal<Fixture>();
|
||||
private static readonly ThreadLocal<Vector2> lastPickedNormalLocal = new ThreadLocal<Vector2>();
|
||||
|
||||
private Vector2 prevPosition;
|
||||
|
||||
@@ -113,22 +173,22 @@ namespace Barotrauma
|
||||
|
||||
public static Vector2 LastPickedPosition
|
||||
{
|
||||
get { return lastPickedPosition; }
|
||||
get { return lastPickedPositionLocal.Value; }
|
||||
}
|
||||
|
||||
public static float LastPickedFraction
|
||||
{
|
||||
get { return lastPickedFraction; }
|
||||
get { return lastPickedFractionLocal.Value; }
|
||||
}
|
||||
|
||||
public static Fixture LastPickedFixture
|
||||
{
|
||||
get { return lastPickedFixture; }
|
||||
get { return lastPickedFixtureLocal.Value; }
|
||||
}
|
||||
|
||||
public static Vector2 LastPickedNormal
|
||||
{
|
||||
get { return lastPickedNormal; }
|
||||
get { return lastPickedNormalLocal.Value; }
|
||||
}
|
||||
|
||||
public bool Loading
|
||||
@@ -145,7 +205,7 @@ namespace Barotrauma
|
||||
|
||||
public List<WayPoint> ForcedOutpostModuleWayPoints = new List<WayPoint>();
|
||||
|
||||
public static List<Submarine> Loaded
|
||||
public static ThreadSafeSubmarineList Loaded
|
||||
{
|
||||
get { return loaded; }
|
||||
}
|
||||
@@ -854,10 +914,10 @@ namespace Barotrauma
|
||||
}, ref aabb);
|
||||
if (closestFraction <= 0.0f)
|
||||
{
|
||||
lastPickedPosition = rayStart;
|
||||
lastPickedFraction = closestFraction;
|
||||
lastPickedFixture = closestFixture;
|
||||
lastPickedNormal = closestNormal;
|
||||
lastPickedPositionLocal.Value = rayStart;
|
||||
lastPickedFractionLocal.Value = closestFraction;
|
||||
lastPickedFixtureLocal.Value = closestFixture;
|
||||
lastPickedNormalLocal.Value = closestNormal;
|
||||
return closestBody;
|
||||
}
|
||||
}
|
||||
@@ -876,16 +936,22 @@ namespace Barotrauma
|
||||
return fraction;
|
||||
}, rayStart, rayEnd, collisionCategory ?? Category.All);
|
||||
|
||||
lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction;
|
||||
lastPickedFraction = closestFraction;
|
||||
lastPickedFixture = closestFixture;
|
||||
lastPickedNormal = closestNormal;
|
||||
lastPickedPositionLocal.Value = rayStart + (rayEnd - rayStart) * closestFraction;
|
||||
lastPickedFractionLocal.Value = closestFraction;
|
||||
lastPickedFixtureLocal.Value = closestFixture;
|
||||
lastPickedNormalLocal.Value = closestNormal;
|
||||
|
||||
return closestBody;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Body, float> bodyDist = new Dictionary<Body, float>();
|
||||
private static readonly List<Body> bodies = new List<Body>();
|
||||
// ThreadLocal for thread-safe body picking
|
||||
private static readonly ThreadLocal<Dictionary<Body, float>> bodyDistLocal =
|
||||
new ThreadLocal<Dictionary<Body, float>>(() => new Dictionary<Body, float>());
|
||||
private static readonly ThreadLocal<List<Body>> bodiesLocal =
|
||||
new ThreadLocal<List<Body>>(() => new List<Body>());
|
||||
|
||||
private static Dictionary<Body, float> bodyDist => bodyDistLocal.Value;
|
||||
private static List<Body> bodies => bodiesLocal.Value;
|
||||
|
||||
public static float LastPickedBodyDist(Body body)
|
||||
{
|
||||
@@ -919,10 +985,10 @@ namespace Barotrauma
|
||||
}
|
||||
if (fraction < closestFraction)
|
||||
{
|
||||
lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction;
|
||||
lastPickedFraction = fraction;
|
||||
lastPickedNormal = normal;
|
||||
lastPickedFixture = fixture;
|
||||
lastPickedPositionLocal.Value = rayStart + (rayEnd - rayStart) * fraction;
|
||||
lastPickedFractionLocal.Value = fraction;
|
||||
lastPickedNormalLocal.Value = normal;
|
||||
lastPickedFixtureLocal.Value = fixture;
|
||||
}
|
||||
//continue
|
||||
return -1;
|
||||
@@ -940,10 +1006,10 @@ namespace Barotrauma
|
||||
if (!fixture.Shape.TestPoint(ref transform, ref rayStart)) { return true; }
|
||||
|
||||
closestFraction = 0.0f;
|
||||
lastPickedPosition = rayStart;
|
||||
lastPickedFraction = 0.0f;
|
||||
lastPickedNormal = Vector2.Normalize(rayEnd - rayStart);
|
||||
lastPickedFixture = fixture;
|
||||
lastPickedPositionLocal.Value = rayStart;
|
||||
lastPickedFractionLocal.Value = 0.0f;
|
||||
lastPickedNormalLocal.Value = Vector2.Normalize(rayEnd - rayStart);
|
||||
lastPickedFixtureLocal.Value = fixture;
|
||||
bodies.Add(fixture.Body);
|
||||
bodyDist[fixture.Body] = 0.0f;
|
||||
return false;
|
||||
@@ -1011,7 +1077,7 @@ namespace Barotrauma
|
||||
|
||||
if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.01f)
|
||||
{
|
||||
lastPickedPosition = rayEnd;
|
||||
lastPickedPositionLocal.Value = rayEnd;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1053,10 +1119,10 @@ namespace Barotrauma
|
||||
, rayStart, rayEnd);
|
||||
|
||||
|
||||
lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction;
|
||||
lastPickedFraction = closestFraction;
|
||||
lastPickedFixture = closestFixture;
|
||||
lastPickedNormal = closestNormal;
|
||||
lastPickedPositionLocal.Value = rayStart + (rayEnd - rayStart) * closestFraction;
|
||||
lastPickedFractionLocal.Value = closestFraction;
|
||||
lastPickedFixtureLocal.Value = closestFixture;
|
||||
lastPickedNormalLocal.Value = closestNormal;
|
||||
return closestBody;
|
||||
}
|
||||
|
||||
@@ -1077,7 +1143,7 @@ namespace Barotrauma
|
||||
|
||||
Item.UpdateHulls();
|
||||
|
||||
List<Item> bodyItems = Item.ItemList.FindAll(it => it.Submarine == this && it.body != null);
|
||||
List<Item> bodyItems = Item.ItemList.Where(it => it.Submarine == this && it.body != null).ToList();
|
||||
List<MapEntity> subEntities = MapEntity.MapEntityList.FindAll(me => me.Submarine == this);
|
||||
|
||||
foreach (MapEntity e in subEntities)
|
||||
@@ -1511,9 +1577,9 @@ namespace Barotrauma
|
||||
public List<WayPoint> GetWaypoints(bool alsoFromConnectedSubs) => GetEntities(alsoFromConnectedSubs, WayPoint.WayPointList);
|
||||
public List<Structure> GetWalls(bool alsoFromConnectedSubs) => GetEntities(alsoFromConnectedSubs, Structure.WallList);
|
||||
|
||||
public List<T> GetEntities<T>(bool includingConnectedSubs, List<T> list) where T : MapEntity
|
||||
public List<T> GetEntities<T>(bool includingConnectedSubs, IEnumerable<T> list) where T : MapEntity
|
||||
{
|
||||
return list.FindAll(e => IsEntityFoundOnThisSub(e, includingConnectedSubs));
|
||||
return list.Where(e => IsEntityFoundOnThisSub(e, includingConnectedSubs)).ToList();
|
||||
}
|
||||
|
||||
public List<(ItemContainer container, int freeSlots)> GetCargoContainers()
|
||||
@@ -1538,11 +1604,6 @@ namespace Barotrauma
|
||||
return containers;
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetEntities<T>(bool includingConnectedSubs, IEnumerable<T> list) where T : MapEntity
|
||||
{
|
||||
return list.Where(e => IsEntityFoundOnThisSub(e, includingConnectedSubs));
|
||||
}
|
||||
|
||||
public bool IsEntityFoundOnThisSub(MapEntity entity, bool includingConnectedSubs, bool allowDifferentTeam = false, bool allowDifferentType = false)
|
||||
{
|
||||
if (entity == null) { return false; }
|
||||
@@ -1665,9 +1726,8 @@ namespace Barotrauma
|
||||
HiddenSubPosition += Vector2.UnitY * GameMain.GameSession.LevelData.Size.Y;
|
||||
}
|
||||
|
||||
for (int i = 0; i < loaded.Count; i++)
|
||||
foreach (Submarine sub in loaded)
|
||||
{
|
||||
Submarine sub = loaded[i];
|
||||
HiddenSubPosition =
|
||||
new Vector2(
|
||||
//1st sub on the left side, 2nd on the right, etc
|
||||
@@ -1799,10 +1859,9 @@ namespace Barotrauma
|
||||
}
|
||||
entityGrid = Hull.GenerateEntityGrid(this);
|
||||
|
||||
for (int i = 0; i < MapEntity.MapEntityList.Count; i++)
|
||||
foreach (MapEntity me in MapEntity.MapEntityList.Where(e => e.Submarine == this))
|
||||
{
|
||||
if (MapEntity.MapEntityList[i].Submarine != this) { continue; }
|
||||
MapEntity.MapEntityList[i].Move(HiddenSubPosition, ignoreContacts: true);
|
||||
me.Move(HiddenSubPosition, ignoreContacts: true);
|
||||
}
|
||||
|
||||
Loading = false;
|
||||
@@ -2147,7 +2206,7 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Error while removing \"" + item.Name + "\"!", e);
|
||||
}
|
||||
}
|
||||
Item.ItemList.Clear();
|
||||
Item.ClearAllItemCollections();
|
||||
}
|
||||
|
||||
Ragdoll.RemoveAll();
|
||||
@@ -2156,7 +2215,7 @@ namespace Barotrauma
|
||||
GameMain.World = null;
|
||||
|
||||
Powered.Grids.Clear();
|
||||
Powered.ChangedConnections.Clear();
|
||||
Powered.ClearChangedConnections();
|
||||
|
||||
GC.Collect();
|
||||
|
||||
@@ -2196,7 +2255,7 @@ namespace Barotrauma
|
||||
|
||||
ConnectedDockingPorts?.Clear();
|
||||
|
||||
Powered.ChangedConnections.Clear();
|
||||
Powered.ClearChangedConnections();
|
||||
Powered.Grids.Clear();
|
||||
|
||||
loaded.Remove(this);
|
||||
|
||||
Reference in New Issue
Block a user