Skip to content

Commit

Permalink
Fix transport lines (#325)
Browse files Browse the repository at this point in the history
* Add error handling to ReflectionHelper
* Fix call to update loans
  • Loading branch information
kaenganxt committed Aug 21, 2023
1 parent 4895ec6 commit 1ef063b
Show file tree
Hide file tree
Showing 11 changed files with 485 additions and 79 deletions.
32 changes: 27 additions & 5 deletions src/api/Helpers/ReflectionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,19 @@ public static T Call<T>(Type type, string name, params object[] param)

public static object Call(Type type, string name, params object[] param)
{
return type.GetMethod(name, AllAccessFlags, null, param.Select(p => p.GetType()).ToArray(), null)
?.Invoke(null, param);
return Call(type, name, param.Select(p => p.GetType()).ToArray(), param);
}

public static object Call(Type type, string name, Type[] types, params object[] param)
{
MethodInfo methodInfo = type.GetMethod(name, AllAccessFlags, null, types, null);
if (methodInfo == null)
{
Log.Error($"ReflectionHelper::Call failed on {type}::{name}");
return null;
}

return methodInfo.Invoke(null, param);
}

public static T Call<T>(object obj, string name, params object[] param)
Expand All @@ -61,13 +72,24 @@ public static object Call(object obj, string name, params object[] param)

public static object Call(object obj, string name, Type[] types, params object[] param)
{
return obj.GetType().GetMethod(name, AllAccessFlags, null, types, null)
?.Invoke(obj, param);
MethodInfo methodInfo = obj.GetType().GetMethod(name, AllAccessFlags, null, types, null);
if (methodInfo == null)
{
Log.Error($"ReflectionHelper::Call failed on {obj.GetType()}.{name}");
return null;
}
return methodInfo.Invoke(obj, param);
}

public static void SetAttr(object obj, string attribute, object value)
{
obj.GetType().GetField(attribute, AllAccessFlags)?.SetValue(obj, value);
FieldInfo field = obj.GetType().GetField(attribute, AllAccessFlags);
if (field == null)
{
Log.Error($"ReflectionHelper::SetAttr failed on {obj.GetType()}.{attribute}");
return;
}
field.SetValue(obj, value);
}

public static T GetAttr<T>(object obj, string attribute)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,93 @@ namespace CSM.BaseGame.Commands.Data.TransportLines
public class TransportLineTempCommand : CommandBase
{
/// <summary>
/// The new prefab info index.
/// Current prefab info index.
/// </summary>
[ProtoMember(1)]
public ushort InfoIndex { get; set; }

/// <summary>
/// The source line this temp line refers to.
/// If SetEditLine should be called with the force parameter.
/// </summary>
[ProtoMember(2)]
public ushort SourceLine { get; set; }
public bool ForceSetEditLine { get; set; }

/// <summary>
/// The index of the stop that will be moved.
/// The current temp line id.
/// </summary>
[ProtoMember(3)]
public int MoveIndex { get; set; }
public ushort TempLine { get; set; }

/// <summary>
/// The index of the stop that will be added.
/// The source line this temp line refers to.
/// </summary>
[ProtoMember(4)]
public int AddIndex { get; set; }
public ushort SourceLine { get; set; }

/// <summary>
/// The position of a new stop.
/// A line id to be released, 0 otherwise.
/// </summary>
[ProtoMember(5)]
public ushort ReleaseLine { get; set; }

/// <summary>
/// If the temp line should be created.
/// </summary>
[ProtoMember(6)]
public bool CreateLine { get; set; }

/// <summary>
/// The index of a previously added stop.
/// </summary>
[ProtoMember(7)]
public int LastAddIndex { get; set; }

/// <summary>
/// The index of a previously moved stop.
/// </summary>
[ProtoMember(8)]
public int LastMoveIndex { get; set; }

/// <summary>
/// The position of a previously moved stop.
/// </summary>
[ProtoMember(9)]
public Vector3 LastMovePos { get; set; }

/// <summary>
/// The position of a previously added stop.
/// </summary>
[ProtoMember(10)]
public Vector3 LastAddPos { get; set; }

/// <summary>
/// The index of the stop that will be added.
/// </summary>
[ProtoMember(11)]
public int AddIndex { get; set; }

/// <summary>
/// The index of the stop that will be moved.
/// </summary>
[ProtoMember(12)]
public int MoveIndex { get; set; }

/// <summary>
/// The position to add a new stop to.
/// </summary>
[ProtoMember(13)]
public Vector3 AddPos { get; set; }

/// <summary>
/// If the line has fixed platforms.
/// </summary>
[ProtoMember(6)]
[ProtoMember(14)]
public bool FixedPlatform { get; set; }

/// <summary>
/// The list of generated Array16 ids.
/// </summary>
[ProtoMember(7)]
[ProtoMember(15)]
public ushort[] Array16Ids { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ protected override void Handle(EconomyPayLoanCommand command)
EconomyPanel panel = typeof(ToolsModifierControl).GetField("m_EconomyPanel", ReflectionHelper.AllAccessFlags)?.GetValue(null) as EconomyPanel;
if (panel != null)
{
SimulationManager.instance.m_ThreadingWrapper.QueueMainThread(() => ReflectionHelper.Call(panel, "PopulateLoansTab"));
SimulationManager.instance.m_ThreadingWrapper.QueueMainThread(() => ReflectionHelper.Call(panel, "UpdateLoansTab"));
}

IgnoreHelper.Instance.EndIgnore();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protected override void Handle(EconomyTakeLoanCommand command)
EconomyPanel panel = typeof(ToolsModifierControl).GetField("m_EconomyPanel", ReflectionHelper.AllAccessFlags)?.GetValue(null) as EconomyPanel;
if (panel != null)
{
SimulationManager.instance.m_ThreadingWrapper.QueueMainThread(() => ReflectionHelper.Call(panel, "PopulateLoansTab"));
SimulationManager.instance.m_ThreadingWrapper.QueueMainThread(() => ReflectionHelper.Call(panel, "UpdateLoansTab"));
}

IgnoreHelper.Instance.EndIgnore();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ protected override void Handle(TransportLineInitCommand command)
TransportTool tool = Singleton<ToolSimulator>.instance.GetTool<TransportTool>(command.SenderId);

ReflectionHelper.SetAttr(tool, "m_errors", ToolBase.ToolErrors.Pending);
ReflectionHelper.SetAttr(tool, "m_lastMoveIndex", -2);
ReflectionHelper.SetAttr(tool, "m_lastAddIndex", -2);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protected override void Handle(TransportLineSyncCommand command)
if (command.UpdatePaths)
{
ushort tempLine = ReflectionHelper.GetAttr<ushort>(tool, "m_tempLine");
TransportManager.instance.m_lines.m_buffer[(int)tempLine].UpdatePaths(tempLine);
TransportManager.instance.m_lines.m_buffer[tempLine].UpdatePaths(tempLine);
}

IgnoreHelper.Instance.EndIgnore();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using CSM.BaseGame.Helpers;
using CSM.BaseGame.Injections;
using ColossalFramework;
using CSM.API;
using UnityEngine;

namespace CSM.BaseGame.Commands.Handler.TransportLines
{
Expand All @@ -14,15 +16,115 @@ protected override void Handle(TransportLineTempCommand command)
TransportTool tool = Singleton<ToolSimulator>.instance.GetTool<TransportTool>(command.SenderId);

ArrayHandler.StartApplying(command.Array16Ids, null);
IgnoreHelper.Instance.StartIgnore();

// Update received values
ReflectionHelper.SetAttr(tool, "m_lastAddIndex", command.LastAddIndex);
ReflectionHelper.SetAttr(tool, "m_lastAddPos", command.LastAddPos);
ReflectionHelper.SetAttr(tool, "m_lastMoveIndex", command.LastMoveIndex);
ReflectionHelper.SetAttr(tool, "m_lastMovePos", command.LastMovePos);

TransportInfo info = PrefabCollection<TransportInfo>.GetPrefab(command.InfoIndex);

IgnoreHelper.Instance.StartIgnore();
TransportManager instance = Singleton<TransportManager>.instance;

ReflectionHelper.Call(tool, "EnsureTempLine", info, command.SourceLine, command.MoveIndex, command.AddIndex, command.AddPos, command.FixedPlatform);
// The following is a reproduction of the "EnsureTempLine" logic adapted for the remote players (e.g. no "temporary" flag for the temp line)

IgnoreHelper.Instance.EndIgnore();
// Release lines
if (command.ReleaseLine != 0)
{
instance.ReleaseLine(command.ReleaseLine);
}

// Create temp line if necessary
if (command.CreateLine)
{
Singleton<TransportManager>.instance.CreateLine(out ushort tempLine,
ref Singleton<SimulationManager>.instance.m_randomizer, info, newNumber: false);
instance.m_lines.m_buffer[command.TempLine].m_flags |= TransportLine.Flags.Temporary;
if (tempLine != command.TempLine)
{
Log.Error("Received temp line id does not match reserved temp line id");
Chat.Instance.PrintGameMessage(Chat.MessageType.Error,
"Received temp line id does not match reserved temp line id. Please restart the game session.");
}
}

// Set temp line and copy current edit line to it if necessary
ReflectionHelper.SetAttr(tool, "m_tempLine", command.TempLine);
ReflectionHelper.Call(tool, "SetEditLine", new[] { typeof(ushort), typeof(bool) },
command.TempLine == 0 ? (ushort)0 : command.SourceLine, command.ForceSetEditLine);

// Update local working values after SetEditLine call
command.LastAddIndex = ReflectionHelper.GetAttr<int>(tool, "m_lastAddIndex");
command.LastAddPos = ReflectionHelper.GetAttr<Vector3>(tool, "m_lastAddPos");
command.LastMoveIndex = ReflectionHelper.GetAttr<int>(tool, "m_lastMoveIndex");
command.LastMovePos = ReflectionHelper.GetAttr<Vector3>(tool, "m_lastMovePos");

// Handle changes in indices
if (command.TempLine != 0)
{
if (command.LastMoveIndex != command.MoveIndex
|| command.LastAddIndex != command.AddIndex
|| command.LastAddPos != command.AddPos)
{
if (command.LastAddIndex != -2 &&
instance.m_lines.m_buffer[command.TempLine].RemoveStop(command.TempLine, command.LastAddIndex))
{
command.LastAddIndex = -2;
command.LastAddPos = Vector3.zero;
}

if (command.LastMoveIndex != -2 && instance.m_lines.m_buffer[command.TempLine]
.MoveStop(command.TempLine, command.LastMoveIndex, command.LastMovePos,
command.FixedPlatform))
{
command.LastMoveIndex = -2;
command.LastMovePos = Vector3.zero;
}

instance.m_lines.m_buffer[command.TempLine].CopyMissingPaths(command.SourceLine);
if (command.MoveIndex != -2 && instance.m_lines.m_buffer[command.TempLine]
.MoveStop(command.TempLine, command.MoveIndex, command.AddPos, command.FixedPlatform,
out var oldPos))
{
command.LastMoveIndex = command.MoveIndex;
command.LastMovePos = oldPos;
command.LastAddPos = command.AddPos;
}

if (command.AddIndex != -2 && instance.m_lines.m_buffer[command.TempLine]
.AddStop(command.TempLine, command.AddIndex, command.AddPos, command.FixedPlatform))
{
command.LastAddIndex = command.AddIndex;
command.LastAddPos = command.AddPos;
}

instance.UpdateLine(command.TempLine);

// Write updated values back to tool instances
ReflectionHelper.SetAttr(tool, "m_lastAddIndex", command.LastAddIndex);
ReflectionHelper.SetAttr(tool, "m_lastAddPos", command.LastAddPos);
ReflectionHelper.SetAttr(tool, "m_lastMoveIndex", command.LastMoveIndex);
ReflectionHelper.SetAttr(tool, "m_lastMovePos", command.LastMovePos);
}

// Some other stuff
instance.m_lines.m_buffer[command.TempLine].m_color =
instance.m_lines.m_buffer[command.SourceLine].m_color;
instance.m_lines.m_buffer[command.TempLine].m_flags &= ~TransportLine.Flags.Hidden;

if ((instance.m_lines.m_buffer[command.SourceLine].m_flags & TransportLine.Flags.CustomColor) != 0)
{
instance.m_lines.m_buffer[command.TempLine].m_flags |= TransportLine.Flags.CustomColor;
}
else
{
instance.m_lines.m_buffer[command.TempLine].m_flags &= ~TransportLine.Flags.CustomColor;
}
}

IgnoreHelper.Instance.EndIgnore();
ArrayHandler.StopApplying();
}
}
Expand Down
25 changes: 20 additions & 5 deletions src/basegame/Helpers/ToolSimulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ public class ToolSimulator: Singleton<ToolSimulator>

public T GetTool<T>(int sender) where T : ToolBase
{
ToolBase tool;
if (_currentTools.ContainsKey(sender))
if (_currentTools.TryGetValue(sender, out ToolBase tool))
{
tool = _currentTools[sender];
if (tool.GetType() == typeof(T))
{
return (T)tool;
Expand All @@ -47,7 +45,6 @@ public class ToolSimulator: Singleton<ToolSimulator>
ReflectionHelper.SetAttr(tool, "m_toolController", controller);
// See ToolController::Awake
ReflectionHelper.SetAttr(controller, "m_brushData", new float[4096]);
ReflectionHelper.SetAttr(controller, "m_collidingSegments", new float[4096]);
ReflectionHelper.SetAttr(controller, "ID_BrushTex", Shader.PropertyToID("_BrushTex"));
ReflectionHelper.SetAttr(controller, "ID_BrushWS", Shader.PropertyToID("_BrushWS"));
ReflectionHelper.SetAttr(controller, "m_collidingSegments1", new ulong[576]);
Expand Down Expand Up @@ -147,7 +144,25 @@ public class ToolSimulator: Singleton<ToolSimulator>

public void RemoveSender(int sender)
{
_currentTools.Remove(sender);
if (_currentTools.TryGetValue(sender, out ToolBase tool))
{
_currentTools.Remove(sender);

// Tool based cleanup
switch (tool)
{
case TransportTool transportTool:
IgnoreHelper.Instance.StartIgnore();
ushort tempLine = ReflectionHelper.GetAttr<ushort>(transportTool, "m_tempLine");
if (tempLine != 0)
{
Singleton<TransportManager>.instance.ReleaseLine(tempLine);
}

IgnoreHelper.Instance.EndIgnore();
break;
}
}
}

public void Clear()
Expand Down
1 change: 0 additions & 1 deletion src/basegame/Injections/Tools/TransportToolHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using ColossalFramework;
using CSM.API;
using CSM.API.Commands;
using CSM.API.Helpers;
using HarmonyLib;
using ProtoBuf;
using UnityEngine;
Expand Down

0 comments on commit 1ef063b

Please sign in to comment.