Item/statuseffect optimization:

- PowerTransfer components cache power connections instead of rechecking them every frame
- items store connections in a dictionary with the name of the connection as a key (-> finding the correct connection when sending a signal is more efficient)
- storing item tags & StatusEffect targetNames in HashSets
This commit is contained in:
Regalis
2016-11-08 21:14:29 +02:00
parent 1dc08b3019
commit 1617cd8f7a
4 changed files with 120 additions and 69 deletions
+10 -10
View File
@@ -16,7 +16,7 @@ namespace Barotrauma
} }
private TargetType targetTypes; private TargetType targetTypes;
private string[] targetNames; private HashSet<string> targetNames;
private List<RelatedItem> requiredItems; private List<RelatedItem> requiredItems;
@@ -26,8 +26,8 @@ namespace Barotrauma
private bool setValue; private bool setValue;
private bool disableDeltaTime; private bool disableDeltaTime;
private string[] onContainingNames; private HashSet<string> onContainingNames;
private readonly float duration; private readonly float duration;
@@ -48,12 +48,12 @@ namespace Barotrauma
get { return targetTypes; } get { return targetTypes; }
} }
public string[] TargetNames public HashSet<string> TargetNames
{ {
get { return targetNames; } get { return targetNames; }
} }
public string[] OnContainingNames public HashSet<string> OnContainingNames
{ {
get { return onContainingNames; } get { return onContainingNames; }
} }
@@ -92,10 +92,10 @@ namespace Barotrauma
type = (ActionType)Enum.Parse(typeof(ActionType), split[0], true); type = (ActionType)Enum.Parse(typeof(ActionType), split[0], true);
string[] containingNames = split[1].Split(','); string[] containingNames = split[1].Split(',');
onContainingNames = new string[containingNames.Length]; onContainingNames = new HashSet<string>();
for (int i =0; i < containingNames.Length; i++) for (int i = 0; i < containingNames.Length; i++)
{ {
onContainingNames[i] = containingNames[i].Trim(); onContainingNames.Add(containingNames[i].Trim());
} }
} }
@@ -116,10 +116,10 @@ namespace Barotrauma
break; break;
case "targetnames": case "targetnames":
string[] names = attribute.Value.Split(','); string[] names = attribute.Value.Split(',');
targetNames = new string[names.Length]; targetNames = new HashSet<string>();
for (int i=0; i < names.Length; i++ ) for (int i=0; i < names.Length; i++ )
{ {
targetNames[i] = names[i].Trim(); targetNames.Add(names[i].Trim());
} }
break; break;
case "sound": case "sound":
@@ -374,7 +374,7 @@ namespace Barotrauma.Items.Components
return; return;
} }
List<ItemSound> matchingSounds = null; List<ItemSound> matchingSounds;
if (!sounds.TryGetValue(type, out matchingSounds)) return; if (!sounds.TryGetValue(type, out matchingSounds)) return;
ItemSound itemSound = null; ItemSound itemSound = null;
@@ -22,7 +22,9 @@ namespace Barotrauma.Items.Components
//affects how fast changes in power/load are carried over the grid //affects how fast changes in power/load are carried over the grid
static float inertia = 5.0f; static float inertia = 5.0f;
static List<Powered> connectedList = new List<Powered>(); static HashSet<Powered> connectedList = new HashSet<Powered>();
private List<Connection> powerConnections;
private float powerLoad; private float powerLoad;
@@ -35,24 +37,27 @@ namespace Barotrauma.Items.Components
: base(item, element) : base(item, element)
{ {
IsActive = true; IsActive = true;
powerConnections = new List<Connection>();
} }
public override void Update(float deltaTime, Camera cam) public override void Update(float deltaTime, Camera cam)
{ {
//reset and recalculate the power generated/consumed
//by the constructions connected to the grid
fullPower = 0.0f;
fullLoad = 0.0f;
connectedList.Clear();
if (updateTimer > 0) if (updateTimer > 0)
{ {
//this junction box has already been updated this frame
updateTimer--; updateTimer--;
return; return;
} }
//reset and recalculate the power generated/consumed
//by the constructions connected to the grid
fullPower = 0.0f;
fullLoad = 0.0f;
updateTimer = 0;
connectedList.Clear();
CheckJunctions(deltaTime); CheckJunctions(deltaTime);
updateTimer = 0;
foreach (Powered p in connectedList) foreach (Powered p in connectedList)
{ {
@@ -68,8 +73,7 @@ namespace Barotrauma.Items.Components
//(except if running as a client) //(except if running as a client)
if (GameMain.Client != null) continue; if (GameMain.Client != null) continue;
if (-pt.currPowerConsumption < Math.Max(pt.powerLoad * Rand.Range(1.9f,2.1f), 200.0f)) continue; if (-pt.currPowerConsumption < Math.Max(pt.powerLoad * Rand.Range(1.9f,2.1f), 200.0f)) continue;
float prevCondition = pt.item.Condition; float prevCondition = pt.item.Condition;
pt.item.Condition -= deltaTime * 10.0f; pt.item.Condition -= deltaTime * 10.0f;
@@ -109,37 +113,31 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, null); ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
List<Connection> connections = item.Connections; foreach (Connection c in powerConnections)
if (connections == null) return;
foreach (Connection c in connections)
{ {
if (!c.IsPower) continue;
var recipients = c.Recipients; var recipients = c.Recipients;
foreach (Connection recipient in recipients) foreach (Connection recipient in recipients)
{ {
if (recipient == null || !c.IsPower) continue; if (recipient == null) continue;
Item it = recipient.Item; Item it = recipient.Item;
if (it == null) continue; if (it == null) continue;
//if (it.Updated) continue;
Powered powered = it.GetComponent<Powered>(); Powered powered = it.GetComponent<Powered>();
if (powered == null || !powered.IsActive) continue; if (powered == null || !powered.IsActive) continue;
if (connectedList.Contains(powered)) continue; if (connectedList.Contains(powered)) continue;
PowerTransfer powerTransfer = powered as PowerTransfer; PowerTransfer powerTransfer = powered as PowerTransfer;
PowerContainer powerContainer = powered as PowerContainer;
if (powerTransfer != null) if (powerTransfer != null)
{ {
//if (powerTransfer.updateTimer>0) continue;
powerTransfer.CheckJunctions(deltaTime); powerTransfer.CheckJunctions(deltaTime);
continue;
} }
else if (powerContainer != null)
PowerContainer powerContainer = powered as PowerContainer;
if (powerContainer != null)
{ {
if (recipient.Name == "power_in") if (recipient.Name == "power_in")
{ {
@@ -187,6 +185,19 @@ namespace Barotrauma.Items.Components
GuiFrame.Update(1.0f / 60.0f); GuiFrame.Update(1.0f / 60.0f);
} }
public override void OnMapLoaded()
{
var connections = item.Connections;
if (connections == null)
{
IsActive = false;
return;
}
powerConnections = connections.FindAll(c => c.IsPower);
if (powerConnections.Count == 0) IsActive = false;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item sender, float power) public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item sender, float power)
{ {
base.ReceiveSignal(stepsTaken, signal, connection, sender, power); base.ReceiveSignal(stepsTaken, signal, connection, sender, power);
+75 -35
View File
@@ -36,7 +36,7 @@ namespace Barotrauma
public static bool ShowLinks = true; public static bool ShowLinks = true;
private List<string> tags; private HashSet<string> tags;
public Hull CurrentHull; public Hull CurrentHull;
@@ -55,6 +55,9 @@ namespace Barotrauma
private bool inWater; private bool inWater;
private Inventory parentInventory; private Inventory parentInventory;
private Inventory ownInventory;
private Dictionary<string, Connection> connections;
//a dictionary containing lists of the status effects in all the components of the item //a dictionary containing lists of the status effects in all the components of the item
private Dictionary<ActionType, List<StatusEffect>> statusEffectLists; private Dictionary<ActionType, List<StatusEffect>> statusEffectLists;
@@ -275,8 +278,7 @@ namespace Barotrauma
{ {
get get
{ {
ItemContainer c = GetComponent<ItemContainer>(); return (ownInventory == null) ? null : Array.FindAll(ownInventory.Items, i => i != null);
return (c == null) ? null : Array.FindAll(c.Inventory.Items, i=>i!=null);
} }
} }
@@ -326,7 +328,7 @@ namespace Barotrauma
components = new List<ItemComponent>(); components = new List<ItemComponent>();
drawableComponents = new List<IDrawableComponent>(); drawableComponents = new List<IDrawableComponent>();
FixRequirements = new List<FixRequirement>(); FixRequirements = new List<FixRequirement>();
tags = new List<string>(); tags = new HashSet<string>();
rect = newRect; rect = newRect;
@@ -401,6 +403,12 @@ namespace Barotrauma
if (body != null) body.FarseerBody.OnCollision += OnCollision; if (body != null) body.FarseerBody.OnCollision += OnCollision;
} }
var itemContainer = GetComponent<ItemContainer>();
if (itemContainer!=null)
{
ownInventory = itemContainer.Inventory;
}
InsertToList(); InsertToList();
ItemList.Add(this); ItemList.Add(this);
} }
@@ -428,15 +436,16 @@ namespace Barotrauma
public void RemoveContained(Item contained) public void RemoveContained(Item contained)
{ {
ItemContainer c = GetComponent<ItemContainer>(); if (ownInventory != null)
if (c == null) return; {
ownInventory.RemoveItem(contained);
c.RemoveContained(contained); }
contained.Container = null; contained.Container = null;
} }
public void SetTransform(Vector2 simPosition, float rotation) public void SetTransform(Vector2 simPosition, float rotation, bool findNewHull = true)
{ {
if (body != null) if (body != null)
{ {
@@ -457,7 +466,7 @@ namespace Barotrauma
rect.X = (int)(displayPos.X - rect.Width / 2.0f); rect.X = (int)(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f); rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
FindHull(); if (findNewHull) FindHull();
} }
public override void Move(Vector2 amount) public override void Move(Vector2 amount)
@@ -544,7 +553,34 @@ namespace Barotrauma
return rootContainer; return rootContainer;
} }
public void SetContainedItemPositions()
{
if (ownInventory == null) return;
Vector2 simPos = SimPosition;
Vector2 displayPos = Position;
foreach (Item contained in ownInventory.Items)
{
if (contained == null) continue;
if (contained.body != null)
{
contained.body.FarseerBody.SetTransformIgnoreContacts(ref simPos, 0.0f);
}
contained.Rect =
new Rectangle(
(int)(displayPos.X - contained.Rect.Width / 2.0f),
(int)(displayPos.Y + contained.Rect.Height / 2.0f),
contained.Rect.Width, contained.Rect.Height);
contained.Submarine = Submarine;
contained.CurrentHull = CurrentHull;
}
}
public void AddTag(string tag) public void AddTag(string tag)
{ {
if (tags.Contains(tag)) return; if (tags.Contains(tag)) return;
@@ -580,16 +616,15 @@ namespace Barotrauma
bool hasTargets = (effect.TargetNames == null); bool hasTargets = (effect.TargetNames == null);
Item[] containedItems = ContainedItems; Item[] containedItems = ContainedItems;
if (effect.OnContainingNames!=null) if (effect.OnContainingNames != null)
{ {
foreach (string s in effect.OnContainingNames) foreach (string s in effect.OnContainingNames)
{ {
if (containedItems.FirstOrDefault(x => x!=null && x.Name==s && x.Condition>0.0f) == null) return; if (!containedItems.Any(x => x!=null && x.Name==s && x.Condition > 0.0f)) return;
} }
} }
List<IPropertyObject> targets = new List<IPropertyObject>(); List<IPropertyObject> targets = new List<IPropertyObject>();
if (containedItems != null) if (containedItems != null)
{ {
if (effect.Targets.HasFlag(StatusEffect.TargetType.Contained)) if (effect.Targets.HasFlag(StatusEffect.TargetType.Contained))
@@ -691,8 +726,7 @@ namespace Barotrauma
{ {
ic.Update(deltaTime, cam); ic.Update(deltaTime, cam);
if (ic.IsActive) ic.PlaySound(ActionType.OnActive, WorldPosition); if (ic.IsActive) ic.PlaySound(ActionType.OnActive, WorldPosition);
//ic.ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
} }
else else
{ {
@@ -1154,25 +1188,23 @@ namespace Barotrauma
public void SendSignal(int stepsTaken, string signal, string connectionName, float power = 0.0f) public void SendSignal(int stepsTaken, string signal, string connectionName, float power = 0.0f)
{ {
if (connections == null) return;
stepsTaken++; stepsTaken++;
ConnectionPanel panel = GetComponent<ConnectionPanel>(); Connection c = null;
if (panel == null) return; if (!connections.TryGetValue(connectionName, out c)) return;
foreach (Connection c in panel.Connections)
if (stepsTaken > 10)
{ {
if (c.Name != connectionName) continue; //use a coroutine to prevent infinite loops by creating a one
//frame delay if the "signal chain" gets too long
if (stepsTaken > 10) CoroutineManager.StartCoroutine(SendSignal(signal, c, power));
{
//use a coroutine to prevent infinite loops by creating a one
//frame delay if the "signal chain" gets too long
CoroutineManager.StartCoroutine(SendSignal(signal, c, power));
}
else
{
c.SendSignal(stepsTaken, signal, this, power);
}
} }
else
{
c.SendSignal(stepsTaken, signal, this, power);
}
} }
private IEnumerable<object> SendSignal(string signal, Connection connection, float power = 0.0f) private IEnumerable<object> SendSignal(string signal, Connection connection, float power = 0.0f)
@@ -1180,9 +1212,6 @@ namespace Barotrauma
//wait one frame //wait one frame
yield return CoroutineStatus.Running; yield return CoroutineStatus.Running;
ConnectionPanel panel = GetComponent<ConnectionPanel>();
if (panel == null) yield return CoroutineStatus.Success;
connection.SendSignal(0, signal, this, power); connection.SendSignal(0, signal, this, power);
yield return CoroutineStatus.Success; yield return CoroutineStatus.Success;
@@ -1654,7 +1683,18 @@ namespace Barotrauma
foreach (ItemComponent ic in components) foreach (ItemComponent ic in components)
{ {
ic.OnMapLoaded(); ic.OnMapLoaded();
} }
//cache connections into a dictionary for faster lookups
var connectionPanel = GetComponent<ConnectionPanel>();
connections = new Dictionary<string, Connection>();
if (connectionPanel == null) return;
foreach (Connection c in connectionPanel.Connections)
{
if (!connections.ContainsKey(c.Name))
connections.Add(c.Name, c);
}
} }