Pow3r goes brrr with generational IDs.
This commit is contained in:
@@ -19,7 +19,6 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
private readonly HashSet<PowerNet> _powerNetReconnectQueue = new();
|
private readonly HashSet<PowerNet> _powerNetReconnectQueue = new();
|
||||||
private readonly HashSet<ApcNet> _apcNetReconnectQueue = new();
|
private readonly HashSet<ApcNet> _apcNetReconnectQueue = new();
|
||||||
|
|
||||||
private int _nextId = 1;
|
|
||||||
private readonly BatteryRampPegSolver _solver = new();
|
private readonly BatteryRampPegSolver _solver = new();
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -50,7 +49,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
private void ApcPowerReceiverShutdown(EntityUid uid, ApcPowerReceiverComponent component,
|
private void ApcPowerReceiverShutdown(EntityUid uid, ApcPowerReceiverComponent component,
|
||||||
ComponentShutdown args)
|
ComponentShutdown args)
|
||||||
{
|
{
|
||||||
_powerState.Loads.Remove(component.NetworkLoad.Id);
|
_powerState.Loads.Free(component.NetworkLoad.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ApcPowerReceiverPaused(
|
private static void ApcPowerReceiverPaused(
|
||||||
@@ -68,7 +67,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
|
|
||||||
private void BatteryShutdown(EntityUid uid, PowerNetworkBatteryComponent component, ComponentShutdown args)
|
private void BatteryShutdown(EntityUid uid, PowerNetworkBatteryComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
_powerState.Batteries.Remove(component.NetworkBattery.Id);
|
_powerState.Batteries.Free(component.NetworkBattery.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BatteryPaused(EntityUid uid, PowerNetworkBatteryComponent component, EntityPausedEvent args)
|
private static void BatteryPaused(EntityUid uid, PowerNetworkBatteryComponent component, EntityPausedEvent args)
|
||||||
@@ -83,7 +82,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
|
|
||||||
private void PowerConsumerShutdown(EntityUid uid, PowerConsumerComponent component, ComponentShutdown args)
|
private void PowerConsumerShutdown(EntityUid uid, PowerConsumerComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
_powerState.Loads.Remove(component.NetworkLoad.Id);
|
_powerState.Loads.Free(component.NetworkLoad.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PowerConsumerPaused(EntityUid uid, PowerConsumerComponent component, EntityPausedEvent args)
|
private static void PowerConsumerPaused(EntityUid uid, PowerConsumerComponent component, EntityPausedEvent args)
|
||||||
@@ -98,7 +97,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
|
|
||||||
private void PowerSupplierShutdown(EntityUid uid, PowerSupplierComponent component, ComponentShutdown args)
|
private void PowerSupplierShutdown(EntityUid uid, PowerSupplierComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
_powerState.Supplies.Remove(component.NetworkSupply.Id);
|
_powerState.Supplies.Free(component.NetworkSupply.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PowerSupplierPaused(EntityUid uid, PowerSupplierComponent component, EntityPausedEvent args)
|
private static void PowerSupplierPaused(EntityUid uid, PowerSupplierComponent component, EntityPausedEvent args)
|
||||||
@@ -113,7 +112,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
|
|
||||||
public void DestroyPowerNet(PowerNet powerNet)
|
public void DestroyPowerNet(PowerNet powerNet)
|
||||||
{
|
{
|
||||||
_powerState.Networks.Remove(powerNet.NetworkNode.Id);
|
_powerState.Networks.Free(powerNet.NetworkNode.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueReconnectPowerNet(PowerNet powerNet)
|
public void QueueReconnectPowerNet(PowerNet powerNet)
|
||||||
@@ -128,7 +127,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
|
|
||||||
public void DestroyApcNet(ApcNet apcNet)
|
public void DestroyApcNet(ApcNet apcNet)
|
||||||
{
|
{
|
||||||
_powerState.Networks.Remove(apcNet.NetworkNode.Id);
|
_powerState.Networks.Free(apcNet.NetworkNode.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueReconnectApcNet(ApcNet apcNet)
|
public void QueueReconnectApcNet(ApcNet apcNet)
|
||||||
@@ -213,26 +212,22 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
|
|
||||||
private void AllocLoad(PowerState.Load load)
|
private void AllocLoad(PowerState.Load load)
|
||||||
{
|
{
|
||||||
load.Id = AllocId();
|
_powerState.Loads.Allocate(out load.Id) = load;
|
||||||
_powerState.Loads.Add(load.Id, load);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AllocSupply(PowerState.Supply supply)
|
private void AllocSupply(PowerState.Supply supply)
|
||||||
{
|
{
|
||||||
supply.Id = AllocId();
|
_powerState.Supplies.Allocate(out supply.Id) = supply;
|
||||||
_powerState.Supplies.Add(supply.Id, supply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AllocBattery(PowerState.Battery battery)
|
private void AllocBattery(PowerState.Battery battery)
|
||||||
{
|
{
|
||||||
battery.Id = AllocId();
|
_powerState.Batteries.Allocate(out battery.Id) = battery;
|
||||||
_powerState.Batteries.Add(battery.Id, battery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AllocNetwork(PowerState.Network network)
|
private void AllocNetwork(PowerState.Network network)
|
||||||
{
|
{
|
||||||
network.Id = AllocId();
|
_powerState.Networks.Allocate(out network.Id) = network;
|
||||||
_powerState.Networks.Add(network.Id, network);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DoReconnectApcNet(ApcNet net)
|
private static void DoReconnectApcNet(ApcNet net)
|
||||||
@@ -296,11 +291,6 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
battery.NetworkBattery.LinkedNetworkDischarging = netNode.Id;
|
battery.NetworkBattery.LinkedNetworkDischarging = netNode.Id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PowerState.NodeId AllocId()
|
|
||||||
{
|
|
||||||
return new(_nextId++);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,40 +1,51 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Numerics;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Server.Power.Pow3r
|
namespace Content.Server.Power.Pow3r
|
||||||
{
|
{
|
||||||
public sealed class PowerState
|
public sealed class PowerState
|
||||||
{
|
{
|
||||||
public const int MaxTickData = 180;
|
|
||||||
|
|
||||||
public static readonly JsonSerializerOptions SerializerOptions = new()
|
public static readonly JsonSerializerOptions SerializerOptions = new()
|
||||||
{
|
{
|
||||||
IncludeFields = true,
|
IncludeFields = true,
|
||||||
Converters = {new NodeIdJsonConverter()}
|
Converters = {new NodeIdJsonConverter()}
|
||||||
};
|
};
|
||||||
|
|
||||||
public Dictionary<NodeId, Supply> Supplies = new();
|
public GenIdStorage<Supply> Supplies = new();
|
||||||
public Dictionary<NodeId, Network> Networks = new();
|
public GenIdStorage<Network> Networks = new();
|
||||||
public Dictionary<NodeId, Load> Loads = new();
|
public GenIdStorage<Load> Loads = new();
|
||||||
public Dictionary<NodeId, Battery> Batteries = new();
|
public GenIdStorage<Battery> Batteries = new();
|
||||||
|
|
||||||
public readonly struct NodeId : IEquatable<NodeId>
|
public readonly struct NodeId : IEquatable<NodeId>
|
||||||
{
|
{
|
||||||
public readonly int Id;
|
public readonly int Index;
|
||||||
|
public readonly int Generation;
|
||||||
|
|
||||||
public NodeId(int id)
|
public long Combined => (uint) Index | ((long) Generation << 32);
|
||||||
|
|
||||||
|
public NodeId(int index, int generation)
|
||||||
{
|
{
|
||||||
Id = id;
|
Index = index;
|
||||||
|
Generation = generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeId(long combined)
|
||||||
|
{
|
||||||
|
Index = (int) combined;
|
||||||
|
Generation = (int) (combined >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(NodeId other)
|
public bool Equals(NodeId other)
|
||||||
{
|
{
|
||||||
return Id == other.Id;
|
return Index == other.Index && Generation == other.Generation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
@@ -44,7 +55,7 @@ namespace Content.Server.Power.Pow3r
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return Id;
|
return HashCode.Combine(Index, Generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(NodeId left, NodeId right)
|
public static bool operator ==(NodeId left, NodeId right)
|
||||||
@@ -59,7 +70,261 @@ namespace Content.Server.Power.Pow3r
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return Id.ToString();
|
return $"{Index} (G{Generation})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GenIdStorage
|
||||||
|
{
|
||||||
|
public static GenIdStorage<T> FromEnumerable<T>(IEnumerable<(NodeId, T)> enumerable)
|
||||||
|
{
|
||||||
|
return GenIdStorage<T>.FromEnumerable(enumerable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class GenIdStorage<T>
|
||||||
|
{
|
||||||
|
// This is an implementation of "generational index" storage.
|
||||||
|
//
|
||||||
|
// The advantage of this storage method is extremely fast, O(1) lookup (way faster than Dictionary).
|
||||||
|
// Resolving a value in the storage is a single array load and generation compare. Extremely fast.
|
||||||
|
// Indices can also be cached into temporary
|
||||||
|
// Disadvantages are that storage cannot be shrunk, and sparse storage is inefficient space wise.
|
||||||
|
// Also this implementation does not have optimizations necessary to make sparse iteration efficient.
|
||||||
|
//
|
||||||
|
// The idea here is that the index type (NodeId in this case) has both an index and a generation.
|
||||||
|
// The index is an integer index into the storage array, the generation is used to avoid use-after-free.
|
||||||
|
//
|
||||||
|
// Empty slots in the array form a linked list of free slots.
|
||||||
|
// When we allocate a new slot, we pop one link off this linked list and hand out its index + generation.
|
||||||
|
//
|
||||||
|
// When we free a node, we bump the generation of the slot and make it the head of the linked list.
|
||||||
|
// The generation being bumped means that any IDs to this slot will fail to resolve (generation mismatch).
|
||||||
|
//
|
||||||
|
|
||||||
|
// Index of the next free slot to use when allocating a new one.
|
||||||
|
// If this is int.MaxValue,
|
||||||
|
// it basically means "no slot available" and the next allocation call should resize the array storage.
|
||||||
|
private int _nextFree = int.MaxValue;
|
||||||
|
private Slot[] _storage;
|
||||||
|
|
||||||
|
public int Count { get; private set; }
|
||||||
|
|
||||||
|
public ref T this[NodeId id]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ref var slot = ref _storage[id.Index];
|
||||||
|
if (slot.Generation != id.Generation)
|
||||||
|
ThrowKeyNotFound();
|
||||||
|
|
||||||
|
return ref slot.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenIdStorage()
|
||||||
|
{
|
||||||
|
_storage = Array.Empty<Slot>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GenIdStorage<T> FromEnumerable(IEnumerable<(NodeId, T)> enumerable)
|
||||||
|
{
|
||||||
|
var storage = new GenIdStorage<T>();
|
||||||
|
|
||||||
|
// Cache enumerable to array to do double enumeration.
|
||||||
|
var cache = enumerable.ToArray();
|
||||||
|
|
||||||
|
if (cache.Length == 0)
|
||||||
|
return storage;
|
||||||
|
|
||||||
|
// Figure out max size necessary and set storage size to that.
|
||||||
|
var maxSize = cache.Max(tup => tup.Item1.Index) + 1;
|
||||||
|
storage._storage = new Slot[maxSize];
|
||||||
|
|
||||||
|
// Fill in slots.
|
||||||
|
foreach (var (id, value) in cache)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(id.Generation != 0, "Generation cannot be 0");
|
||||||
|
|
||||||
|
ref var slot = ref storage._storage[id.Index];
|
||||||
|
DebugTools.Assert(slot.Generation == 0, "Duplicate key index!");
|
||||||
|
|
||||||
|
slot.Generation = id.Generation;
|
||||||
|
slot.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through empty slots and build the free chain.
|
||||||
|
var nextFree = int.MaxValue;
|
||||||
|
for (var i = 0; i < storage._storage.Length; i++)
|
||||||
|
{
|
||||||
|
ref var slot = ref storage._storage[i];
|
||||||
|
|
||||||
|
if (slot.Generation != 0)
|
||||||
|
// Slot in use.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
slot.NextSlot = nextFree;
|
||||||
|
nextFree = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
storage.Count = cache.Length;
|
||||||
|
storage._nextFree = nextFree;
|
||||||
|
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref T Allocate(out NodeId id)
|
||||||
|
{
|
||||||
|
if (_nextFree == int.MaxValue)
|
||||||
|
ReAllocate();
|
||||||
|
|
||||||
|
var idx = _nextFree;
|
||||||
|
ref var slot = ref _storage[idx];
|
||||||
|
|
||||||
|
Count += 1;
|
||||||
|
_nextFree = slot.NextSlot;
|
||||||
|
// NextSlot = -1 indicates filled.
|
||||||
|
slot.NextSlot = -1;
|
||||||
|
|
||||||
|
id = new NodeId(idx, slot.Generation);
|
||||||
|
return ref slot.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free(NodeId id)
|
||||||
|
{
|
||||||
|
var idx = id.Index;
|
||||||
|
ref var slot = ref _storage[idx];
|
||||||
|
if (slot.Generation != id.Generation)
|
||||||
|
ThrowKeyNotFound();
|
||||||
|
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
slot.Value = default!;
|
||||||
|
|
||||||
|
Count -= 1;
|
||||||
|
slot.Generation += 1;
|
||||||
|
slot.NextSlot = _nextFree;
|
||||||
|
_nextFree = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private void ReAllocate()
|
||||||
|
{
|
||||||
|
var oldLength = _storage.Length;
|
||||||
|
var newLength = Math.Max(oldLength, 2) * 2;
|
||||||
|
|
||||||
|
ReAllocateTo(newLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReAllocateTo(int newSize)
|
||||||
|
{
|
||||||
|
var oldLength = _storage.Length;
|
||||||
|
DebugTools.Assert(newSize >= oldLength, "Cannot shrink GenIdStorage");
|
||||||
|
|
||||||
|
Array.Resize(ref _storage, newSize);
|
||||||
|
|
||||||
|
for (var i = oldLength; i < newSize - 1; i++)
|
||||||
|
{
|
||||||
|
// Build linked list chain for newly allocated segment.
|
||||||
|
ref var slot = ref _storage[i];
|
||||||
|
slot.NextSlot = i + 1;
|
||||||
|
// Every slot starts at generation 1.
|
||||||
|
slot.Generation = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_storage[^1].NextSlot = _nextFree;
|
||||||
|
|
||||||
|
_nextFree = oldLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValuesCollection Values => new(this);
|
||||||
|
|
||||||
|
private struct Slot
|
||||||
|
{
|
||||||
|
// Next link on the free list. if int.MaxValue then this is the tail.
|
||||||
|
// If negative, this slot is occupied.
|
||||||
|
public int NextSlot;
|
||||||
|
// Generation of this slot.
|
||||||
|
public int Generation;
|
||||||
|
public T Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private static void ThrowKeyNotFound()
|
||||||
|
{
|
||||||
|
throw new KeyNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct ValuesCollection : IReadOnlyCollection<T>
|
||||||
|
{
|
||||||
|
private readonly GenIdStorage<T> _owner;
|
||||||
|
|
||||||
|
public ValuesCollection(GenIdStorage<T> owner)
|
||||||
|
{
|
||||||
|
_owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(_owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count => _owner.Count;
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Enumerator : IEnumerator<T>
|
||||||
|
{
|
||||||
|
// Save the array in the enumerator here to avoid a few pointer dereferences.
|
||||||
|
private readonly Slot[] _owner;
|
||||||
|
private int _index;
|
||||||
|
|
||||||
|
public Enumerator(GenIdStorage<T> owner)
|
||||||
|
{
|
||||||
|
_owner = owner._storage;
|
||||||
|
Current = default!;
|
||||||
|
_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
_index += 1;
|
||||||
|
if (_index >= _owner.Length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ref var slot = ref _owner[_index];
|
||||||
|
|
||||||
|
if (slot.NextSlot < 0)
|
||||||
|
{
|
||||||
|
Current = slot.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
object IEnumerator.Current => Current!;
|
||||||
|
|
||||||
|
public T Current { get; private set; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,12 +332,12 @@ namespace Content.Server.Power.Pow3r
|
|||||||
{
|
{
|
||||||
public override NodeId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override NodeId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
return new(reader.GetInt32());
|
return new NodeId(reader.GetInt64());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, NodeId value, JsonSerializerOptions options)
|
public override void Write(Utf8JsonWriter writer, NodeId value, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
writer.WriteNumberValue(value.Id);
|
writer.WriteNumberValue(value.Combined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,22 +451,8 @@ namespace Content.Server.Power.Pow3r
|
|||||||
// "Supplying" means the network is connected to the OUTPUT port of the battery.
|
// "Supplying" means the network is connected to the OUTPUT port of the battery.
|
||||||
[ViewVariables] public List<NodeId> BatteriesDischarging = new();
|
[ViewVariables] public List<NodeId> BatteriesDischarging = new();
|
||||||
|
|
||||||
// Calculation parameters used by GraphWalkSolver.
|
|
||||||
// Unused by BatteryRampPegSolver.
|
|
||||||
[JsonIgnore] public float LocalDemandTotal;
|
|
||||||
[JsonIgnore] public float LocalDemandMet;
|
|
||||||
[JsonIgnore] public float GroupDemandTotal;
|
|
||||||
[JsonIgnore] public float GroupDemandMet;
|
|
||||||
|
|
||||||
[ViewVariables] [JsonIgnore] public int Height;
|
[ViewVariables] [JsonIgnore] public int Height;
|
||||||
[JsonIgnore] public bool HeightTouched;
|
[JsonIgnore] public bool HeightTouched;
|
||||||
|
|
||||||
// Supply available this tick.
|
|
||||||
[JsonIgnore] public float AvailableSupplyTotal;
|
|
||||||
|
|
||||||
// Max theoretical supply assuming max ramp.
|
|
||||||
[JsonIgnore] public float TheoreticalSupplyTotal;
|
|
||||||
public float RemainingDemand => LocalDemandTotal - LocalDemandMet;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,15 +20,14 @@ namespace Pow3r
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_paused = dat.Paused;
|
_paused = dat.Paused;
|
||||||
_nextId = dat.NextId;
|
|
||||||
_currentSolver = dat.Solver;
|
_currentSolver = dat.Solver;
|
||||||
|
|
||||||
_state = new PowerState
|
_state = new PowerState
|
||||||
{
|
{
|
||||||
Networks = dat.Networks.ToDictionary(n => n.Id, n => n),
|
Networks = GenIdStorage.FromEnumerable(dat.Networks.Select(n => (n.Id, n))),
|
||||||
Supplies = dat.Supplies.ToDictionary(s => s.Id, s => s),
|
Supplies = GenIdStorage.FromEnumerable(dat.Supplies.Select(s => (s.Id, s))),
|
||||||
Loads = dat.Loads.ToDictionary(l => l.Id, l => l),
|
Loads = GenIdStorage.FromEnumerable(dat.Loads.Select(l => (l.Id, l))),
|
||||||
Batteries = dat.Batteries.ToDictionary(b => b.Id, b => b)
|
Batteries = GenIdStorage.FromEnumerable(dat.Batteries.Select(b => (b.Id, b)))
|
||||||
};
|
};
|
||||||
|
|
||||||
_displayLoads = dat.Loads.ToDictionary(n => n.Id, _ => new DisplayLoad());
|
_displayLoads = dat.Loads.ToDictionary(n => n.Id, _ => new DisplayLoad());
|
||||||
@@ -44,7 +43,6 @@ namespace Pow3r
|
|||||||
var data = new DiskDat
|
var data = new DiskDat
|
||||||
{
|
{
|
||||||
Paused = _paused,
|
Paused = _paused,
|
||||||
NextId = _nextId,
|
|
||||||
Solver = _currentSolver,
|
Solver = _currentSolver,
|
||||||
|
|
||||||
Loads = _state.Loads.Values.ToList(),
|
Loads = _state.Loads.Values.ToList(),
|
||||||
@@ -59,7 +57,6 @@ namespace Pow3r
|
|||||||
private sealed class DiskDat
|
private sealed class DiskDat
|
||||||
{
|
{
|
||||||
public bool Paused;
|
public bool Paused;
|
||||||
public int NextId;
|
|
||||||
public int Solver;
|
public int Solver;
|
||||||
|
|
||||||
public List<Load> Loads;
|
public List<Load> Loads;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ namespace Pow3r
|
|||||||
{
|
{
|
||||||
private const int MaxTickData = 180;
|
private const int MaxTickData = 180;
|
||||||
|
|
||||||
private int _nextId = 1;
|
|
||||||
private PowerState _state = new();
|
private PowerState _state = new();
|
||||||
private Network _linking;
|
private Network _linking;
|
||||||
private int _tickDataIdx;
|
private int _tickDataIdx;
|
||||||
@@ -33,11 +32,6 @@ namespace Pow3r
|
|||||||
private readonly Queue<object> _remQueue = new();
|
private readonly Queue<object> _remQueue = new();
|
||||||
private readonly Stopwatch _simStopwatch = new Stopwatch();
|
private readonly Stopwatch _simStopwatch = new Stopwatch();
|
||||||
|
|
||||||
private NodeId AllocId()
|
|
||||||
{
|
|
||||||
return new(_nextId++);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Tick(float frameTime)
|
private void Tick(float frameTime)
|
||||||
{
|
{
|
||||||
if (_paused)
|
if (_paused)
|
||||||
|
|||||||
@@ -36,30 +36,30 @@ namespace Pow3r
|
|||||||
|
|
||||||
if (Button("Generator"))
|
if (Button("Generator"))
|
||||||
{
|
{
|
||||||
var id = AllocId();
|
var supply = new Supply();
|
||||||
_state.Supplies.Add(id, new Supply { Id = id });
|
_state.Supplies.Allocate(out supply.Id) = supply;
|
||||||
_displaySupplies.Add(id, new DisplaySupply());
|
_displaySupplies.Add(supply.Id, new DisplaySupply());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Button("Load"))
|
if (Button("Load"))
|
||||||
{
|
{
|
||||||
var id = AllocId();
|
var load = new Load();
|
||||||
_state.Loads.Add(id, new Load { Id = id });
|
_state.Loads.Allocate(out load.Id) = load;
|
||||||
_displayLoads.Add(id, new DisplayLoad());
|
_displayLoads.Add(load.Id, new DisplayLoad());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Button("Network"))
|
if (Button("Network"))
|
||||||
{
|
{
|
||||||
var id = AllocId();
|
var network = new Network();
|
||||||
_state.Networks.Add(id, new Network { Id = id });
|
_state.Networks.Allocate(out network.Id) = network;
|
||||||
_displayNetworks.Add(id, new DisplayNetwork());
|
_displayNetworks.Add(network.Id, new DisplayNetwork());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Button("Battery"))
|
if (Button("Battery"))
|
||||||
{
|
{
|
||||||
var id = AllocId();
|
var battery = new Battery();
|
||||||
_state.Batteries.Add(id, new Battery { Id = id });
|
_state.Batteries.Allocate(out battery.Id) = battery;
|
||||||
_displayBatteries.Add(id, new DisplayBattery());
|
_displayBatteries.Add(battery.Id, new DisplayBattery());
|
||||||
}
|
}
|
||||||
|
|
||||||
Checkbox("Paused", ref _paused);
|
Checkbox("Paused", ref _paused);
|
||||||
@@ -355,25 +355,25 @@ namespace Pow3r
|
|||||||
switch (item)
|
switch (item)
|
||||||
{
|
{
|
||||||
case Network n:
|
case Network n:
|
||||||
_state.Networks.Remove(n.Id);
|
_state.Networks.Free(n.Id);
|
||||||
_displayNetworks.Remove(n.Id);
|
_displayNetworks.Remove(n.Id);
|
||||||
reLink = true;
|
reLink = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Supply s:
|
case Supply s:
|
||||||
_state.Supplies.Remove(s.Id);
|
_state.Supplies.Free(s.Id);
|
||||||
_state.Networks.Values.ForEach(n => n.Supplies.Remove(s.Id));
|
_state.Networks.Values.ForEach(n => n.Supplies.Remove(s.Id));
|
||||||
_displaySupplies.Remove(s.Id);
|
_displaySupplies.Remove(s.Id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Load l:
|
case Load l:
|
||||||
_state.Loads.Remove(l.Id);
|
_state.Loads.Free(l.Id);
|
||||||
_state.Networks.Values.ForEach(n => n.Loads.Remove(l.Id));
|
_state.Networks.Values.ForEach(n => n.Loads.Remove(l.Id));
|
||||||
_displayLoads.Remove(l.Id);
|
_displayLoads.Remove(l.Id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Battery b:
|
case Battery b:
|
||||||
_state.Batteries.Remove(b.Id);
|
_state.Batteries.Free(b.Id);
|
||||||
_state.Networks.Values.ForEach(n => n.BatteriesCharging.Remove(b.Id));
|
_state.Networks.Values.ForEach(n => n.BatteriesCharging.Remove(b.Id));
|
||||||
_state.Networks.Values.ForEach(n => n.BatteriesDischarging.Remove(b.Id));
|
_state.Networks.Values.ForEach(n => n.BatteriesDischarging.Remove(b.Id));
|
||||||
_displayBatteries.Remove(b.Id);
|
_displayBatteries.Remove(b.Id);
|
||||||
|
|||||||
Reference in New Issue
Block a user