diff --git a/TLM/TLM/Lifecycle/AssetDataExtension.cs b/TLM/TLM/Lifecycle/AssetDataExtension.cs
index 22e14021b..4be144187 100644
--- a/TLM/TLM/Lifecycle/AssetDataExtension.cs
+++ b/TLM/TLM/Lifecycle/AssetDataExtension.cs
@@ -43,7 +43,7 @@ public static void OnAssetSavedImpl(string name, object asset, out Dictionary
+
diff --git a/TLM/TLM/Util/Extensions/EnumerableExtensions.cs b/TLM/TLM/Util/Extensions/EnumerableExtensions.cs
new file mode 100644
index 000000000..ac7f2733f
--- /dev/null
+++ b/TLM/TLM/Util/Extensions/EnumerableExtensions.cs
@@ -0,0 +1,11 @@
+namespace TrafficManager.Util.Extensions {
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ internal static class EnumerableExtensions {
+ internal static IEnumerable EmptyIfNull(this IEnumerable e) => e ?? Enumerable.Empty();
+ }
+}
diff --git a/TLM/TLM/Util/Record/IRecordable.cs b/TLM/TLM/Util/Record/IRecordable.cs
index b08ef1551..86a31d642 100644
--- a/TLM/TLM/Util/Record/IRecordable.cs
+++ b/TLM/TLM/Util/Record/IRecordable.cs
@@ -1,4 +1,4 @@
-using System;
+using System.Linq;
using System.Collections.Generic;
namespace TrafficManager.Util.Record {
@@ -19,6 +19,18 @@ public interface IRecordable {
/// maps old Instance IDs to new Instance IDs
void Transfer(Dictionary map);
+ ///
+ /// Detects if record is empty to help releasing empty records from memory.
+ ///
+ /// true if record stores only default values. false if record stores any useful information.
+ bool IsDefault();
+
byte[] Serialize();
}
+
+ public static class RecordExtensions {
+ public static bool AreDefault(this IEnumerable records)
+ where T : IRecordable =>
+ records == null || records.All(record => record == null || record.IsDefault());
+ }
}
diff --git a/TLM/TLM/Util/Record/LaneArrowsRecord.cs b/TLM/TLM/Util/Record/LaneArrowsRecord.cs
index c43369d7e..1df6e92bc 100644
--- a/TLM/TLM/Util/Record/LaneArrowsRecord.cs
+++ b/TLM/TLM/Util/Record/LaneArrowsRecord.cs
@@ -17,6 +17,8 @@ public void Record() {
arrows_ = Flags.GetLaneArrowFlags(LaneId);
}
+ public bool IsDefault() => arrows_ == null;
+
public void Restore() => Transfer(LaneId);
public void Transfer(Dictionary map) =>
diff --git a/TLM/TLM/Util/Record/LaneConnectionRecord.cs b/TLM/TLM/Util/Record/LaneConnectionRecord.cs
index c993b1dfb..01c2c6afb 100644
--- a/TLM/TLM/Util/Record/LaneConnectionRecord.cs
+++ b/TLM/TLM/Util/Record/LaneConnectionRecord.cs
@@ -48,6 +48,11 @@ private void RestoreImpl(LaneConnectionSubManager man, uint[] connections) {
}
}
+ public bool IsDefault() =>
+ connections_.IsNullOrEmpty() &&
+ roadConnections_.IsNullOrEmpty() &&
+ trackConnections_.IsNullOrEmpty();
+
public void Restore() {
if (connections_ != null) {
// legacy
diff --git a/TLM/TLM/Util/Record/NodeRecord.cs b/TLM/TLM/Util/Record/NodeRecord.cs
index 89ee3ebaa..344a5ad26 100644
--- a/TLM/TLM/Util/Record/NodeRecord.cs
+++ b/TLM/TLM/Util/Record/NodeRecord.cs
@@ -1,8 +1,8 @@
namespace TrafficManager.Util.Record {
using System;
using System.Collections.Generic;
+ using System.Linq;
using TrafficManager.Manager.Impl;
- using static TrafficManager.Util.Shortcuts;
using TrafficManager.State;
using TrafficManager.Util.Extensions;
@@ -13,45 +13,32 @@ public class NodeRecord : IRecordable {
public ushort NodeId { get; private set; }
InstanceID InstanceID => new InstanceID { NetNode = NodeId};
- private bool trafficLight_;
+ private bool? trafficLight_;
private List lanes_;
private static TrafficLightManager tlMan => TrafficLightManager.Instance;
public void Record() {
- trafficLight_ = tlMan.HasTrafficLight(NodeId, ref NodeId.ToNode());
+ trafficLight_ = tlMan.GetHasTrafficLight(NodeId);
lanes_ = LaneConnectionRecord.GetLanes(NodeId);
- foreach (LaneConnectionRecord sourceLane in lanes_) {
- sourceLane.Record();
+ foreach (LaneConnectionRecord sourceLane in lanes_.EmptyIfNull()) {
+ sourceLane?.Record();
}
}
+ public bool IsDefault() =>
+ trafficLight_ == null && lanes_.AreDefault();
+
public void Restore() {
- SetTrafficLight(NodeId, trafficLight_);
- foreach (LaneConnectionRecord sourceLane in lanes_) {
- sourceLane.Restore();
+ tlMan.SetHasTrafficLight(NodeId, trafficLight_);
+ foreach (LaneConnectionRecord sourceLane in lanes_.EmptyIfNull()) {
+ sourceLane?.Restore();
}
}
public void Transfer(Dictionary map) {
- SetTrafficLight(map[InstanceID].NetNode, trafficLight_);
- foreach (LaneConnectionRecord sourceLane in lanes_)
- sourceLane.Transfer(map);
- }
-
- private static bool SetTrafficLight(ushort nodeId, bool flag) {
- // TODO move code to manager.
- bool currentValue = tlMan.HasTrafficLight(nodeId, ref nodeId.ToNode());
- if (currentValue == flag)
- return true;
- bool canChangeValue = tlMan.CanToggleTrafficLight(
- nodeId,
- flag,
- ref nodeId.ToNode(),
- out _);
- if (!canChangeValue) {
- return false;
- }
- return tlMan.SetTrafficLight(nodeId, flag, ref nodeId.ToNode());
+ tlMan.SetHasTrafficLight(map[InstanceID].NetNode, trafficLight_);
+ foreach (LaneConnectionRecord sourceLane in lanes_.EmptyIfNull())
+ sourceLane?.Transfer(map);
}
public byte[] Serialize() => SerializationUtil.Serialize(this);
diff --git a/TLM/TLM/Util/Record/SegmentEndRecord.cs b/TLM/TLM/Util/Record/SegmentEndRecord.cs
index 596d6b234..1e62e0df9 100644
--- a/TLM/TLM/Util/Record/SegmentEndRecord.cs
+++ b/TLM/TLM/Util/Record/SegmentEndRecord.cs
@@ -6,9 +6,10 @@ namespace TrafficManager.Util.Record {
using TrafficManager.API.Traffic.Enums;
using TrafficManager.Manager.Impl;
using TrafficManager.State;
+ using TrafficManager.Util.Extensions;
[Serializable]
- class SegmentEndRecord : IRecordable {
+ public class SegmentEndRecord : IRecordable {
public SegmentEndRecord(int segmentEndIndex) {
SegmentEndManager.Instance.
GetSegmentAndNodeFromIndex(segmentEndIndex, out ushort segmentId, out bool startNode);
@@ -23,7 +24,7 @@ public SegmentEndRecord(ushort segmentId, bool startNode) {
public ushort SegmentId { get; private set; }
public bool StartNode { get; private set; }
- InstanceID InstanceID => new InstanceID { NetSegment = SegmentId };
+ private InstanceID InstanceID => new InstanceID { NetSegment = SegmentId };
private TernaryBool uturnAllowed_;
private TernaryBool nearTurnOnRedAllowed_;
@@ -38,6 +39,18 @@ public SegmentEndRecord(ushort segmentId, bool startNode) {
private static TrafficPriorityManager priorityMan => TrafficPriorityManager.Instance;
private static JunctionRestrictionsManager JRMan => JunctionRestrictionsManager.Instance;
+ public bool IsDefault() {
+ return
+ uturnAllowed_ == TernaryBool.Undefined &&
+ nearTurnOnRedAllowed_ == TernaryBool.Undefined &&
+ farTurnOnRedAllowed_ == TernaryBool.Undefined &&
+ laneChangingAllowedWhenGoingStraight_ == TernaryBool.Undefined &&
+ enteringBlockedJunctionAllowed_ == TernaryBool.Undefined &&
+ pedestrianCrossingAllowed_ == TernaryBool.Undefined &&
+ prioirtySign_ == PriorityType.None &&
+ arrowLanes_.AreDefault();
+ }
+
public void Record() {
uturnAllowed_ = JRMan.GetUturnAllowed(SegmentId, StartNode);
nearTurnOnRedAllowed_ = JRMan.GetNearTurnOnRedAllowed(SegmentId, StartNode);
@@ -49,13 +62,13 @@ public void Record() {
prioirtySign_ = priorityMan.GetPrioritySign(SegmentId, StartNode);
arrowLanes_ = LaneArrowsRecord.GetLanes(SegmentId, StartNode);
- foreach(IRecordable lane in arrowLanes_)
- lane.Record();
+ foreach(IRecordable lane in arrowLanes_.EmptyIfNull())
+ lane?.Record();
}
public void Restore() {
- foreach (IRecordable lane in arrowLanes_)
- lane.Restore();
+ foreach (IRecordable lane in arrowLanes_.EmptyIfNull())
+ lane?.Restore();
if (priorityMan.MaySegmentHavePrioritySign(SegmentId, StartNode) &&
prioirtySign_ != priorityMan.GetPrioritySign(SegmentId, StartNode)) {
@@ -74,8 +87,8 @@ public void Restore() {
public void Transfer(Dictionary map) {
ushort segmentId = map[InstanceID].NetSegment;
- foreach (IRecordable lane in arrowLanes_)
- lane.Transfer(map);
+ foreach (IRecordable lane in arrowLanes_.EmptyIfNull())
+ lane?.Transfer(map);
if (priorityMan.MaySegmentHavePrioritySign(segmentId, StartNode) &&
prioirtySign_ != priorityMan.GetPrioritySign(segmentId, StartNode)) {
@@ -95,8 +108,9 @@ public void Transfer(uint mappedId) {
ushort segmentId = (ushort)mappedId;
var mappedLanes = SpeedLimitLaneRecord.GetLanes(segmentId);
- for (int i = 0; i == arrowLanes_.Count; ++i) {
- arrowLanes_[i].Transfer(mappedLanes[i].LaneId);
+ int n = arrowLanes_?.Count ?? 0;
+ for (int i = 0; i == n; ++i) {
+ arrowLanes_[i]?.Transfer(mappedLanes[i].LaneId);
}
}
diff --git a/TLM/TLM/Util/Record/SegmentRecord.cs b/TLM/TLM/Util/Record/SegmentRecord.cs
index e31ac211d..9ef0b98a5 100644
--- a/TLM/TLM/Util/Record/SegmentRecord.cs
+++ b/TLM/TLM/Util/Record/SegmentRecord.cs
@@ -26,32 +26,40 @@ public void Record() {
parkingForward_ = pMan.IsParkingAllowed(SegmentId, NetInfo.Direction.Forward);
parkingBackward_ = pMan.IsParkingAllowed(SegmentId, NetInfo.Direction.Backward);
speedLanes_ = SpeedLimitLaneRecord.GetLanes(SegmentId);
- foreach (var lane in speedLanes_)
- lane.Record();
+ foreach (var lane in speedLanes_.EmptyIfNull())
+ lane?.Record();
vehicleRestrictionsLanes_ = VehicleRestrictionsLaneRecord.GetLanes(SegmentId);
- foreach (var lane in vehicleRestrictionsLanes_)
- lane.Record();
+ foreach (var lane in vehicleRestrictionsLanes_.EmptyIfNull())
+ lane?.Record();
allLaneIds_ = GetAllLanes(SegmentId);
}
+ public bool IsDefault() {
+ return
+ parkingForward_ == true &&
+ parkingBackward_ == true &&
+ speedLanes_.AreDefault() &&
+ vehicleRestrictionsLanes_.AreDefault();
+ }
+
public void Restore() {
// TODO fix SetParkingAllowed
pMan.SetParkingAllowed(SegmentId, NetInfo.Direction.Forward, parkingForward_);
pMan.SetParkingAllowed(SegmentId, NetInfo.Direction.Backward, parkingBackward_);
- foreach (var lane in speedLanes_)
- lane.Restore();
- foreach (var lane in vehicleRestrictionsLanes_)
- lane.Restore();
+ foreach (var lane in speedLanes_.EmptyIfNull())
+ lane?.Restore();
+ foreach (var lane in vehicleRestrictionsLanes_.EmptyIfNull())
+ lane?.Restore();
}
public void Transfer(Dictionary map){
ushort segmentId = map[InstanceID].NetSegment;
pMan.SetParkingAllowed(segmentId, NetInfo.Direction.Forward, parkingForward_);
pMan.SetParkingAllowed(segmentId, NetInfo.Direction.Backward, parkingBackward_);
- foreach (var lane in speedLanes_)
- lane.Transfer(map);
- foreach (var lane in vehicleRestrictionsLanes_)
- lane.Transfer(map);
+ foreach (var lane in speedLanes_.EmptyIfNull())
+ lane?.Transfer(map);
+ foreach (var lane in vehicleRestrictionsLanes_.EmptyIfNull())
+ lane?.Transfer(map);
}
public byte[] Serialize() => SerializationUtil.Serialize(this);
diff --git a/TLM/TLM/Util/Record/SpeedLimitLaneRecord.cs b/TLM/TLM/Util/Record/SpeedLimitLaneRecord.cs
index 1cb34ed0b..5b743d756 100644
--- a/TLM/TLM/Util/Record/SpeedLimitLaneRecord.cs
+++ b/TLM/TLM/Util/Record/SpeedLimitLaneRecord.cs
@@ -26,6 +26,8 @@ public void Record() {
: (float?)null;
}
+ public bool IsDefault() => speedLimit_ == null;
+
public void Restore() => Transfer(LaneId);
public void Transfer(Dictionary map) =>
diff --git a/TLM/TLM/Util/Record/TrafficRulesRecord.cs b/TLM/TLM/Util/Record/TrafficRulesRecord.cs
index cf7e530ad..1549f07d0 100644
--- a/TLM/TLM/Util/Record/TrafficRulesRecord.cs
+++ b/TLM/TLM/Util/Record/TrafficRulesRecord.cs
@@ -64,6 +64,8 @@ public void AddNodeAndSegmentEnds(ushort nodeId) {
}
}
+ public bool IsDefault() => Records.AreDefault();
+
public void Record() {
foreach (ushort nodeId in NodeIDs)
Records.Add(new NodeRecord(nodeId));
@@ -72,18 +74,18 @@ public void Record() {
foreach (int segmentEndIndex in SegmentEndIndeces)
Records.Add(new SegmentEndRecord(segmentEndIndex));
foreach (IRecordable record in Records)
- record.Record();
+ record?.Record();
}
public void Restore() {
- foreach (IRecordable record in Records)
- record.Restore();
+ foreach (IRecordable record in Records.EmptyIfNull())
+ record?.Restore();
}
public void Transfer(Dictionary map) {
- foreach (IRecordable record in Records) {
+ foreach (IRecordable record in Records.EmptyIfNull()) {
try {
- record.Transfer(map);
+ record?.Transfer(map);
}
catch(KeyNotFoundException ex) {
// hide message in release build to avoid scaring the user.
diff --git a/TLM/TLM/Util/Record/VehicleRestrictionsLaneRecord.cs b/TLM/TLM/Util/Record/VehicleRestrictionsLaneRecord.cs
index 0605a7105..58fb5bb94 100644
--- a/TLM/TLM/Util/Record/VehicleRestrictionsLaneRecord.cs
+++ b/TLM/TLM/Util/Record/VehicleRestrictionsLaneRecord.cs
@@ -21,6 +21,8 @@ public class VehicleRestrictionsLaneRecord : IRecordable {
InstanceID InstanceID => new InstanceID { NetLane = LaneId };
+ public bool IsDefault() => allowedVehicleTypes_ == null;
+
public void Record() {
allowedVehicleTypes_ = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypesRaw(SegmentId, LaneIndex);
}