Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

don't save empty records in asset editor #1681

Merged
merged 11 commits into from
Nov 19, 2022
Merged
2 changes: 1 addition & 1 deletion TLM/TLM/Lifecycle/AssetDataExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static void OnAssetSavedImpl(string name, object asset, out Dictionary<st
Log.Info("AssetDataExtension.OnAssetSavedImpl(): prefab is " + prefab);
var assetData = AssetData.GetAssetData(prefab);
if (assetData == null) {
Log._Debug("AssetDataExtension.OnAssetSavedImpl(): No segments to record.");
Log._Debug("AssetDataExtension.OnAssetSavedImpl(): Nothing to record.");
} else {
Log._Debug("AssetDataExtension.OnAssetSavedImpl(): assetData=" + assetData);
userData = new Dictionary<string, byte[]>();
Expand Down
13 changes: 13 additions & 0 deletions TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,19 @@ public bool ClearSegmentEnd(ushort segmentId, bool startNode) {
return ret;
}

public bool ClearNode(ushort nodeId) {
bool ret = false;
ref NetNode node = ref nodeId.ToNode();
for (int segmentIndex = 0; segmentIndex < Constants.MAX_SEGMENTS_OF_NODE; ++segmentIndex) {
ushort segmentId = node.GetSegment(segmentIndex);
if (segmentId != 0) {
bool startNode = segmentId.ToSegment().IsStartNode(nodeId);
ret |= ClearSegmentEnd(segmentId, startNode);
}
}
return ret;
}

private void SetSegmentJunctionRestrictions(ushort segmentId, bool startNode, JunctionRestrictions restrictions) {
if (restrictions.HasValue(JunctionRestrictionFlags.AllowUTurn)) {
SetUturnAllowed(segmentId, startNode, restrictions.GetValueOrDefault(JunctionRestrictionFlags.AllowUTurn));
Expand Down
38 changes: 38 additions & 0 deletions TLM/TLM/Manager/Impl/TrafficLightManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace TrafficManager.Manager.Impl {
using TrafficManager.Util.Extensions;
using ColossalFramework;
using TrafficManager.TrafficLight.Impl;
using TrafficManager.API.Traffic.Data;

/// <summary>
/// Manages traffic light toggling
Expand Down Expand Up @@ -129,6 +130,43 @@ public bool ToggleTrafficLight(ushort nodeId, ref NetNode node, out ToggleTraffi
return SetTrafficLight(nodeId, !HasTrafficLight(nodeId, ref node), ref node, out reason);
}

public void ResetTrafficLightAndPrioritySignsFromNode(ushort nodeId) {
if (!Shortcuts.InSimulationThread()) {
SimulationManager.instance.AddAction(() => ResetTrafficLightAndPrioritySignsFromNode(nodeId));
return;
}

ref NetNode netNode = ref nodeId.ToNode();
if (!netNode.IsValid())
return;
if (netNode.m_flags.IsFlagSet(NetNode.Flags.CustomTrafficLights) &&
(this as ITrafficLightManager).CanToggleTrafficLight(nodeId)) {
TrafficPriorityManager.Instance.RemovePrioritySignsFromNode(nodeId);

// if CustomTrafficLights is not set, UpdateNodeFlags() resets traffic lights.
netNode.m_flags &= ~NetNode.Flags.CustomTrafficLights;
NetManager.instance.UpdateNodeFlags(nodeId);

Constants.ManagerFactory.GeometryManager.MarkAsUpdated(nodeId, true);
Notifier.Instance.OnNodeModified(nodeId, this);
}
}

public bool? GetHasTrafficLight(ushort nodeId) {
NetNode.Flags flags = nodeId.ToNode().m_flags;
return flags.IsFlagSet(NetNode.Flags.CustomTrafficLights)
? HasTrafficLight(nodeId)
: null;
}

public void SetHasTrafficLight(ushort nodeId, bool? value) {
if (value == null) {
ResetTrafficLightAndPrioritySignsFromNode(nodeId);
} else {
SetTrafficLight(nodeId, value.Value, ref nodeId.ToNode());
}
}

bool ITrafficLightManager.CanToggleTrafficLight(ushort nodeId) {
ref NetNode netNode = ref nodeId.ToNode();
return netNode.IsValid() &&
Expand Down
8 changes: 6 additions & 2 deletions TLM/TLM/State/Asset/AssetData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ public static AssetData GetAssetData(BuildingInfo prefab) {
if (!HasPaths(prefab)) {
return null;
}

var record = RecordAll();
if (record == null || record.IsDefault()) {
return null;
}

return new AssetData {
Version = VersionUtil.ModVersion,
Record = RecordAll(),
Record = record,
PathNetworkIDs = GetPathsNetworkIDs(prefab),
};
}
Expand Down
8 changes: 0 additions & 8 deletions TLM/TLM/UI/MainMenu/OSD/OnscreenDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@ private static void Hide() {
}
}

/// <summary>Clear the OSD panel and display the idle hint.</summary>
public static void DisplayIdle() {
var items = new List<OsdItem>();
items.Add(new MainMenu.OSD.Label(
localizedText: Translation.Menu.Get("Onscreen.Idle:Choose a tool")));
Display(items);
}

/// <summary>
/// On Screen Display feature:
/// Clear, and hide the keybind panel.
Expand Down
12 changes: 2 additions & 10 deletions TLM/TLM/UI/SubTools/JunctionRestrictionsTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,9 @@ public JunctionRestrictionsTool(TrafficManagerTool mainTool)

public override void OnToolGUI(Event e) {
// handle delete
// TODO: #568 provide unified delete key for all managers.
if (KeybindSettingsBase.RestoreDefaultsKey.KeyDown(e)) {
ref NetNode node = ref SelectedNodeId.ToNode();

for (int segmentIndex = 0; segmentIndex < Constants.MAX_SEGMENTS_OF_NODE; ++segmentIndex) {
ushort segmentId = node.GetSegment(segmentIndex);
if (segmentId != 0) {
// TODO: #568 provide unified delete key for all managers.
bool startNode = segmentId.ToSegment().IsStartNode(SelectedNodeId);
JunctionRestrictionsManager.Instance.ClearSegmentEnd(segmentId, startNode);
}
}
JunctionRestrictionsManager.Instance.ClearNode(SelectedNodeId);
}
}

Expand Down
125 changes: 92 additions & 33 deletions TLM/TLM/UI/TrafficManagerTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class TrafficManagerTool
// activate when we know the mechinism.
private bool ReadjustPathMode => false; //ShiftIsPressed;

private bool NodeSelectionMode => AltIsPressed;

// /// <summary>Set this to true to once call <see cref="RequestOnscreenDisplayUpdate"/>.</summary>
// public bool InvalidateOnscreenDisplayFlag { get; set; }

Expand Down Expand Up @@ -346,7 +348,7 @@ public void SetToolMode(ToolMode newToolMode) {
toolMode_ = ToolMode.None;

Log._Debug($"SetToolMode: reset because toolmode not found {newToolMode}");
OnscreenDisplay.DisplayIdle();
ScreenDisplay();
ModUI.Instance?.MainMenu?.UpdateButtons();
return;
}
Expand Down Expand Up @@ -493,10 +495,6 @@ void DefaultRenderOverlay(RenderManager.CameraInfo cameraInfo)
base.RenderOverlay(cameraInfo); // render path.
}

if (HoveredSegmentId == 0) {
return;
}

var netAdjust = NetManager.instance?.NetAdjust;

if (netAdjust == null) {
Expand All @@ -507,8 +505,14 @@ void DefaultRenderOverlay(RenderManager.CameraInfo cameraInfo)
ref NetSegment segment = ref HoveredSegmentId.ToSegment();
var color = ToolsModifierControl.toolController.m_validColorInfo;
float alpha = 1f;
NetTool.CheckOverlayAlpha(ref segment, ref alpha);
if (HoveredSegmentId != 0) {
NetTool.CheckOverlayAlpha(ref segment, ref alpha);
}

color.a *= alpha;
if (SelectedNodeId != 0) {
Highlight.DrawNodeCircle(cameraInfo, SelectedNodeId, color);
}

if (ReadjustPathMode) {
if (Input.GetMouseButton(0)) {
Expand All @@ -531,6 +535,10 @@ void DefaultRenderOverlay(RenderManager.CameraInfo cameraInfo)
importantColor: color,
nonImportantColor: color);
}
} else if (NodeSelectionMode) {
if (HoveredNodeId != SelectedNodeId && HoveredNodeId != 0) {
Highlight.DrawNodeCircle(cameraInfo, HoveredNodeId, color);
}
} else {
NetTool.RenderOverlay(cameraInfo, ref segment, color, color);
}
Expand Down Expand Up @@ -593,8 +601,11 @@ protected override void OnToolUpdate() {
if(secondaryMouseClicked) {
if(GetToolMode() == ToolMode.None) {
RoadSelectionPanels roadSelectionPanels = UIView.GetAView().GetComponent<RoadSelectionPanels>();
if(roadSelectionPanels && roadSelectionPanels.RoadWorldInfoPanelExt && roadSelectionPanels.RoadWorldInfoPanelExt.isVisible) {
if (roadSelectionPanels && roadSelectionPanels.RoadWorldInfoPanelExt && roadSelectionPanels.RoadWorldInfoPanelExt.isVisible) {
RoadSelectionPanels.RoadWorldInfoPanel.Hide();
} else if (SelectedNodeId != 0) {
SelectedNodeId = 0;
RequestOnscreenDisplayUpdate();
} else {
ModUI.Instance.CloseMainMenu();
}
Expand Down Expand Up @@ -680,38 +691,46 @@ public void OnToolGUIImpl(Event e) {
}
}

void DefaultOnToolGUI(Event e) {
private void DefaultOnToolGUI(Event e) {
if (!TMPELifecycle.PlayMode) {
return; // world info view panels are not availble in edit mode
}
if (e.type == EventType.MouseDown && e.button == 0) {
bool isRoad = HoveredSegmentId != 0 && HoveredSegmentId.ToSegment().Info.m_netAI is RoadBaseAI;
if (!isRoad)
return;

if (ReadjustPathMode) {
bool isRoundabout = RoundaboutMassEdit.Instance.TraverseLoop(HoveredSegmentId, out var segmentList);
if (!isRoundabout) {
var segments = SegmentTraverser.Traverse(
HoveredSegmentId,
TraverseDirection.AnyDirection,
TraverseSide.Straight,
SegmentStopCriterion.None,
(_) => true);
segmentList = new List<ushort>(segments);
if (NodeSelectionMode) {
SelectedNodeId = HoveredNodeId;
RequestOnscreenDisplayUpdate();
} else {
bool isRoad = HoveredSegmentId != 0 && HoveredSegmentId.ToSegment().Info.m_netAI is RoadBaseAI;
if (!isRoad)
return;

if (ReadjustPathMode) {
bool isRoundabout = RoundaboutMassEdit.Instance.TraverseLoop(HoveredSegmentId, out var segmentList);
if (!isRoundabout) {
var segments = SegmentTraverser.Traverse(
HoveredSegmentId,
TraverseDirection.AnyDirection,
TraverseSide.Straight,
SegmentStopCriterion.None,
(_) => true);
segmentList = new List<ushort>(segments);
}
RoadSelectionUtil.SetRoad(HoveredSegmentId, segmentList);
}
RoadSelectionUtil.SetRoad(HoveredSegmentId, segmentList);
}

InstanceID instanceID = new InstanceID {
NetSegment = HoveredSegmentId,
};
InstanceID instanceID = new InstanceID {
NetSegment = HoveredSegmentId,
};

SimulationManager.instance.m_ThreadingWrapper.QueueMainThread(() => {
OpenWorldInfoPanel(
instanceID,
HitPos);
});
SimulationManager.instance.m_ThreadingWrapper.QueueMainThread(() => {
OpenWorldInfoPanel(
instanceID,
HitPos);
});
}
} else if (SelectedNodeId != 0 && KeybindSettingsBase.RestoreDefaultsKey.KeyDown(e)) {
ushort nodeId = SelectedNodeId;
SimulationManager.instance.AddAction(() => PriorityRoad.EraseAllTrafficRoadsForNode(nodeId));
}
}

Expand Down Expand Up @@ -1612,9 +1631,49 @@ public void RequestOnscreenDisplayUpdate() {

if (activeOsd == null && activeLegacyOsd == null) {
// No tool hint support was available means we have to show the default
OnscreenDisplay.DisplayIdle();
ScreenDisplay();
}
}

/// <summary>Clear the OSD panel and display the idle hint.</summary>
public void ScreenDisplay() {
var items = new List<OsdItem>();
items.Add(new MainMenu.OSD.Label(
localizedText: Translation.Menu.Get("Onscreen.Idle:Choose a tool")));
items.Add(new MainMenu.OSD.HardcodedMouseShortcut(
button: ColossalFramework.UI.UIMouseButton.Left,
shift: false,
ctrl: false,
alt: false,
localizedText: "Onscreen.Default:Select a road")); // select a road to set as main road.
items.Add(new MainMenu.OSD.HardcodedMouseShortcut(
button: ColossalFramework.UI.UIMouseButton.Left,
shift: false,
ctrl: false,
alt: true,
localizedText: "Onscreen.Default:Select a node")); // select a node to erase all traffic rules.

if (SelectedNodeId != 0) {
items.Add(new MainMenu.OSD.Shortcut(
keybindSetting: KeybindSettingsBase.RestoreDefaultsKey,
localizedText: "Onscreen.Default:Erase")); // Erase all traffic rules from selected node.
items.Add(new MainMenu.OSD.HardcodedMouseShortcut(
button: ColossalFramework.UI.UIMouseButton.Right,
shift: false,
ctrl: false,
alt: false,
localizedText: "Onscreen.Default:Deselect node"));
}

items.Add(new MainMenu.OSD.HoldModifier(
shift: false,
ctrl: true,
alt: false,
localizedText: "Onscreen.Default:Show traffic rules")); // show traffic rules for high priority roads

OnscreenDisplay.Display(items);
}

public void AddUUIButton() {
try {
var hotkeys = new UUIHotKeys { ActivationKey = KeybindSettingsBase.ToggleMainMenu.Key };
Expand Down
11 changes: 11 additions & 0 deletions TLM/TLM/Util/PriorityRoad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -674,5 +674,16 @@ public static IRecordable RecordRoad(List<ushort> segmentList) {
record.Record();
return record;
}

public static void EraseAllTrafficRoadsForNode(ushort nodeId) {
try {
TrafficLightManager.Instance.ResetTrafficLightAndPrioritySignsFromNode(nodeId);
LaneConnectionManager.Instance.RemoveLaneConnectionsFromNode(nodeId);
LaneArrowManager.Instance.ResetNodeLaneArrows(nodeId);
JunctionRestrictionsManager.Instance.ClearNode(nodeId);
} catch (Exception ex) {
ex.LogException();
}
}
} //end class
}
14 changes: 13 additions & 1 deletion TLM/TLM/Util/Record/IRecordable.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System.Linq;
using System.Collections.Generic;

namespace TrafficManager.Util.Record {
Expand All @@ -19,6 +19,18 @@ public interface IRecordable {
/// <param name="map">maps old Instance IDs to new Instance IDs</param>
void Transfer(Dictionary<InstanceID, InstanceID> map);

/// <summary>
/// Detects if record is empty to help releasing empty records from memory.
/// </summary>
/// <returns>true if record stores only default values. false if record stores any useful information.</returns>
bool IsDefault();

byte[] Serialize();
}

public static class RecordUtil {
public static bool AreDefault<T>(this IEnumerable<T> records)
where T : IRecordable =>
records == null || records.All(record => record.IsDefault());
}
}
2 changes: 2 additions & 0 deletions TLM/TLM/Util/Record/LaneArrowsRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<InstanceID, InstanceID> map) =>
Expand Down
5 changes: 5 additions & 0 deletions TLM/TLM/Util/Record/LaneConnectionRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading