Performance Optimization

Asteroid positioning is now multithreaded
Item quality calculation is now allocation free
Various other garbage reductions
This commit is contained in:
Reinier Vens 2021-01-17 23:26:53 +00:00
commit 8d6770ab15
21 changed files with 151 additions and 72 deletions

View file

@ -55,10 +55,10 @@ public class MiningTool : IBehavior
public bool Execute(float delta)
{
Range = Context.Evaluate(_data.Range, Item.EquippableItem, Entity);
var asteroidTransform = Entity.Zone.GetAsteroidTransform(AsteroidBelt, Asteroid);
var belt = Entity.Zone.AsteroidBelts[AsteroidBelt];
if (AsteroidBelt != Guid.Empty &&
Entity.Zone.AsteroidExists(AsteroidBelt, Asteroid) &&
length(Entity.Position.xz - asteroidTransform.xz) - asteroidTransform.w < Range)
length(Entity.Position.xz - belt.Positions[Asteroid].xz) - belt.Scales[Asteroid] < Range)
{
Entity.Zone.MineAsteroid(
Entity,

View file

@ -75,18 +75,21 @@ public class Reactor : IBehavior, IOrderedBehavior
// We have an energy deficit, try to get some energy out of our capacitors first
if (Entity.Energy < 0)
{
Capacitor[] chargedCapacitors;
int chargedCapacitors = 0;
do
{
var chargeToRemove = -Entity.Energy;
chargedCapacitors = _capacitors.Where(x => x.Charge > 0.01f).ToArray();
foreach (var cap in chargedCapacitors)
foreach (var cap in _capacitors)
{
var chargeRemoved = min(chargeToRemove / chargedCapacitors.Length, cap.Charge);
cap.AddCharge(-chargeRemoved);
Entity.Energy += chargeRemoved;
if(cap.Charge > 0.01f)
{
chargedCapacitors++;
var chargeRemoved = min(chargeToRemove / chargedCapacitors, cap.Charge);
cap.AddCharge(-chargeRemoved);
Entity.Energy += chargeRemoved;
}
}
} while (chargedCapacitors.Length > 0 && Entity.Energy < -.01f);
} while (chargedCapacitors > 0 && Entity.Energy < -.01f);
}
// We still have an energy deficit, have to overload the reactor, run at reduced efficiency

View file

@ -74,7 +74,7 @@ public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
{
if(Asteroid > -1 &&
Asteroid < beltData.Asteroids.Length &&
length(Entity.Position.xz - Entity.Zone.GetAsteroidTransform(ScanTarget, Asteroid).xy) < Range)
length(Entity.Position.xz - Entity.Zone.AsteroidBelts[ScanTarget].Positions[Asteroid].xz) < Range)
{
_scanTime += delta;
if (_scanTime > ScanDuration)

View file

@ -118,7 +118,7 @@ public class SurveyController : ControllerBase<Survey>, IBehavior, IPersistentBe
if (planet is AsteroidBeltData)
{
if(asteroid == -1) asteroid = Zone.NearestAsteroid(planet.ID, Entity.Position.xz);
return Zone.GetAsteroidTransform(planet.ID, asteroid).xy;
return Zone.AsteroidBelts[planet.ID].Positions[asteroid].xz;
}
return Zone.GetOrbitPosition(planet.Orbit);
}
@ -128,7 +128,7 @@ public class SurveyController : ControllerBase<Survey>, IBehavior, IPersistentBe
if (planet is AsteroidBeltData)
{
if(asteroid == -1) asteroid = Zone.NearestAsteroid(planet.ID, Entity.Position.xz);
return Zone.GetAsteroidVelocity(planet.ID, asteroid);
return Zone.AsteroidBelts[planet.ID].Velocities[asteroid];
}
return Zone.GetOrbitVelocity(planet.Orbit);
}

View file

@ -28,6 +28,7 @@ public abstract class Entity
public float2 Velocity;
public float[,] Temperature;
public float[,] NewTemperature;
public bool2[,] HullConductivity;
public float[,] ThermalMass;
public float Energy;
@ -122,6 +123,7 @@ public abstract class Entity
Equipment.Add(new EquippedItem(ItemManager, Hull, int2.zero, this));
Mass = hullData.Mass;
Temperature = new float[hullData.Shape.Width, hullData.Shape.Height];
NewTemperature = new float[hullData.Shape.Width, hullData.Shape.Height];
HullConductivity = new bool2[hullData.Shape.Width,hullData.Shape.Height];
ThermalMass = new float[hullData.Shape.Width, hullData.Shape.Height];
Armor = new float[hullData.Shape.Width, hullData.Shape.Height];
@ -511,7 +513,7 @@ public abstract class Entity
public virtual void Update(float delta)
{
var hullData = ItemManager.GetData(Hull) as HullData;
float[,] newTemp = new float[hullData.Shape.Width,hullData.Shape.Height];
//float[,] newTemp = new float[hullData.Shape.Width,hullData.Shape.Height];
var radiation = 0f;
foreach (var v in hullData.Shape.Coordinates)
{
@ -542,23 +544,25 @@ public abstract class Entity
(GearOccupancy[v.x, v.y + 1]?.Conductivity ?? 1) *
(HullConductivity[v.x, v.y].y ? hullData.Conductivity : 1 / hullData.Conductivity);
newTemp[v.x, v.y] = Temperature[v.x, v.y] + heatTransfer * min(ItemManager.GameplaySettings.HeatConductionMultiplier * delta,1) / ThermalMass[v.x,v.y];
NewTemperature[v.x, v.y] = Temperature[v.x, v.y] + heatTransfer * min(ItemManager.GameplaySettings.HeatConductionMultiplier * delta,1) / ThermalMass[v.x,v.y];
// For all cells on the border of the entity, radiate some heat into space, increasing the visibility of the ship
if (Parent==null && !hullData.InteriorCells[v])
{
var rad = pow(newTemp[v.x, v.y], ItemManager.GameplaySettings.HeatRadiationExponent) *
var rad = pow(NewTemperature[v.x, v.y], ItemManager.GameplaySettings.HeatRadiationExponent) *
ItemManager.GameplaySettings.HeatRadiationMultiplier;
newTemp[v.x, v.y] -= rad * delta;
NewTemperature[v.x, v.y] -= rad * delta;
radiation += rad;
}
if(float.IsNaN(newTemp[v.x, v.y]) || newTemp[v.x, v.y] < 0)
if(float.IsNaN(NewTemperature[v.x, v.y]) || NewTemperature[v.x, v.y] < 0)
ItemManager.Log("HOUSTON, WE HAVE A PROBLEM!");
}
VisibilitySources[this] = radiation;
Temperature = newTemp;
var swap = Temperature;
Temperature = NewTemperature;
NewTemperature = swap;
if (Active)
{

View file

@ -221,7 +221,14 @@ public class ItemManager
{
if (StatQuality.ContainsKey((stat, item)))
return StatQuality[(stat, item)];
var quality = CalcQuality(stat, item);
StatQuality[(stat, item)] = quality;
return quality;
}
private float CalcQuality(PerformanceStat stat, EquippableItem item)
{
var itemData = GetData(item);
var blueprint = ItemData.Get<BlueprintData>(item.Blueprint);
var activeEffects = blueprint.StatEffects.Where(x => GetAffectedStat(blueprint, x) == stat).ToArray();
@ -249,7 +256,6 @@ public class ItemManager
quality = sum / ingredients.Length;
}
StatQuality[(stat, item)] = quality;
return quality;
}

View file

@ -6,6 +6,8 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UniRx;
using Unity.Mathematics;
using static Unity.Mathematics.math;
@ -30,6 +32,7 @@ public class Zone
private Random _random;
public ZoneData Data { get; }
private List<Task> BeltUpdates = new List<Task>();
public Zone(PlanetSettings settings, ZonePack pack)
{
@ -84,6 +87,9 @@ public class Zone
{
_time = time;
_updatedOrbits.Clear();
foreach (var t in BeltUpdates)
t.Wait();
BeltUpdates.Clear();
foreach (var orbit in Orbits)
{
orbit.Value.PreviousPosition = orbit.Value.Position;
@ -91,8 +97,14 @@ public class Zone
orbit.Value.Velocity = (orbit.Value.Position - orbit.Value.PreviousPosition) / deltaTime;
}
foreach (var asteroids in AsteroidBelts.Keys)
UpdateAsteroidTransforms(asteroids);
foreach (var belt in AsteroidBelts)
{
Array.Copy(belt.Value.NewPositions, belt.Value.Positions, belt.Value.Positions.Length);
Array.Copy(belt.Value.NewVelocities, belt.Value.Velocities, belt.Value.Velocities.Length);
Array.Copy(belt.Value.NewScales, belt.Value.Scales, belt.Value.Scales.Length);
Array.Copy(belt.Value.NewRotations, belt.Value.Rotations, belt.Value.Rotations.Length);
BeltUpdates.Add(Task.Run(() => UpdateAsteroidTransformsAsync(belt.Key)));
}
foreach (var entity in Entities) entity.Update(deltaTime);
}
@ -144,13 +156,13 @@ public class Zone
{
var beltData = Planets[planetDataID] as AsteroidBeltData;
var asteroidPositions = GetAsteroidTransforms(planetDataID);
var asteroidPositions = AsteroidBelts[planetDataID].Positions;
int nearest = 0;
float nearestDistance = Single.MaxValue;
for (int i = 0; i < beltData.Asteroids.Length; i++)
{
var dist = lengthsq(asteroidPositions[i].xy - position);
var dist = lengthsq(asteroidPositions[i].xz - position);
if (AsteroidExists(planetDataID, i) && dist < nearestDistance)
{
nearest = i;
@ -163,28 +175,11 @@ public class Zone
public bool AsteroidExists(Guid planetDataID, int asteroid) => ((AsteroidBeltData) Planets[planetDataID]).Asteroids.Length > asteroid && asteroid >= 0;
public float2 GetAsteroidVelocity(Guid planetDataID, int asteroid)
{
return (AsteroidBelts[planetDataID].Transforms[asteroid].xy - AsteroidBelts[planetDataID].PreviousTransforms[asteroid].xy);
}
public float4 GetAsteroidTransform(Guid planetDataID, int asteroid)
{
return AsteroidBelts[planetDataID].Transforms[asteroid];
}
public float4[] GetAsteroidTransforms(Guid planetDataID)
{
return AsteroidBelts[planetDataID].Transforms;
}
private void UpdateAsteroidTransforms(Guid planetDataID)
private void UpdateAsteroidTransformsAsync(Guid planetDataID)
{
var beltData = Planets[planetDataID] as AsteroidBeltData;
var belt = AsteroidBelts[planetDataID];
Array.Copy(belt.Transforms, belt.PreviousTransforms, beltData.Asteroids.Length);
var orbitData = Orbits[beltData.Orbit].Data;
var orbitPosition = GetOrbitPosition(orbitData.Parent);
@ -199,11 +194,13 @@ public class Zone
size = Settings.AsteroidSize.Evaluate(damage * beltData.Asteroids[i].Size);
}
else size = Settings.AsteroidSize.Evaluate(beltData.Asteroids[i].Size);
belt.Transforms[i] = float4(
OrbitData.Evaluate((float) frac(_time / Settings.OrbitPeriod.Evaluate(beltData.Asteroids[i].Distance) +
beltData.Asteroids[i].Phase)) * beltData.Asteroids[i].Distance + orbitPosition,
(float) (_time * beltData.Asteroids[i].RotationSpeed % (PI * 2)), size);
belt.NewRotations[i] = _time * beltData.Asteroids[i].RotationSpeed % (PI * 2);
belt.NewScales[i] = size;
var pos = OrbitData.Evaluate(frac(_time / Settings.OrbitPeriod.Evaluate(beltData.Asteroids[i].Distance) +
beltData.Asteroids[i].Phase)) * beltData.Asteroids[i].Distance + orbitPosition;
belt.NewVelocities[i] = pos - belt.Positions[i].xz;
belt.NewPositions[i] = float3(pos.x, GetHeight(pos), pos.y);
}
}
@ -232,7 +229,7 @@ public class Zone
{
var beltData = Planets[asteroidBelt] as AsteroidBeltData;
var belt = AsteroidBelts[asteroidBelt];
var asteroidTransform = belt.Transforms[asteroid];
//var asteroidTransform = belt.Transforms[asteroid];
var size = beltData.Asteroids[asteroid].Size;
var asteroidHitpoints = Settings.AsteroidHitpoints.Evaluate(size);
@ -272,7 +269,7 @@ public class Zone
float result = -PowerPulse(length(position)/(Data.Radius*2), Settings.ZoneDepthExponent) * Settings.ZoneDepth;
foreach (var body in PlanetInstances.Values)
{
var p = (position - body.Orbit.Position); //GetOrbitPosition(body.BodyData.Orbit)
var p = position - body.Orbit.Position; //GetOrbitPosition(body.BodyData.Orbit)
var distSqr = lengthsq(p);
var gravityRadius = body.GravityWellRadius.Value;
if (distSqr < gravityRadius*gravityRadius)
@ -389,8 +386,14 @@ public class GasGiant : Planet
public class AsteroidBelt
{
public AsteroidBeltData Data;
public float4[] Transforms; // x, y, rotation, scale
public float4[] PreviousTransforms; // x, y, rotation, scale
public float3[] Positions; // x, y, rotation, scale
public float3[] NewPositions; // x, y, rotation, scale
public float2[] Velocities;
public float2[] NewVelocities;
public float[] Rotations;
public float[] NewRotations;
public float[] Scales;
public float[] NewScales;
public Dictionary<int, float> RespawnTimers = new Dictionary<int, float>();
public Dictionary<int, float> Damage = new Dictionary<int, float>();
public Dictionary<(Entity, int), float> MiningAccumulator = new Dictionary<(Entity, int), float>();
@ -398,8 +401,14 @@ public class AsteroidBelt
public AsteroidBelt(AsteroidBeltData data)
{
Data = data;
Transforms = new float4[data.Asteroids.Length];
PreviousTransforms = new float4[data.Asteroids.Length];
Positions = new float3[data.Asteroids.Length];
NewPositions = new float3[data.Asteroids.Length];
Velocities = new float2[data.Asteroids.Length];
NewVelocities = new float2[data.Asteroids.Length];
Rotations = new float[data.Asteroids.Length];
NewRotations = new float[data.Asteroids.Length];
Scales = new float[data.Asteroids.Length];
NewScales = new float[data.Asteroids.Length];
}
}