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

Place Intersection improvements, bugfixing #1308

Merged
merged 4 commits into from
Jan 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions TLM/TLM/Patch/_BuildingDecoration/LoadPathsPatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ namespace TrafficManager.Patches._BuildingDecoration {
using TrafficManager.Util;
using System;
using System.Reflection.Emit;
using JetBrains.Annotations;

//public static void LoadPaths(BuildingInfo info, ushort buildingID, ref Building data, float elevation)
[HarmonyPatch(typeof(BuildingDecoration), nameof(BuildingDecoration.LoadPaths))]
[UsedImplicitly]
public class LoadPathsPatch {
///<summary>Called after intersection is built</summary>
///<summary>Called after intersection is built</summary>
internal static void AfterIntersectionBuilt(BuildingInfo info) {
if (!Shortcuts.InSimulationThread())
return; // only rendering
Expand All @@ -18,21 +20,24 @@ internal static void AfterIntersectionBuilt(BuildingInfo info) {
}

// code from: https://github.com/Strdate/SmartIntersections/blob/master/SmartIntersections/Patch/LoadPathsPatch.cs
[UsedImplicitly]
public static IEnumerable<CodeInstruction> Transpiler(ILGenerator il, IEnumerable<CodeInstruction> instructions) {
var fTempNodeBuffer = AccessTools.DeclaredField(typeof(NetManager), nameof(NetManager.m_tempNodeBuffer))
?? throw new Exception("cound not find NetManager.m_tempNodeBuffer");
var mClear = AccessTools.DeclaredMethod(fTempNodeBuffer.FieldType, nameof(FastList<ushort>.Clear))
?? throw new Exception("cound not find m_tempNodeBuffer.Clear");
var fTempSegmentBuffer = AccessTools.DeclaredField(typeof(NetManager), nameof(NetManager.m_tempSegmentBuffer))
?? throw new Exception("Could not find NetManager.m_tempSegmentBuffer");
var mSize = AccessTools.DeclaredField(fTempSegmentBuffer.FieldType, nameof(FastList<ushort>.m_size))
?? throw new Exception("Could not find m_tempSegmentBuffer.m_size");
var mAfterIntersectionBuilt = AccessTools.DeclaredMethod(
typeof(LoadPathsPatch), nameof(AfterIntersectionBuilt))
?? throw new Exception("cound not find AfterIntersectionBuilt()");
?? throw new Exception("Could not find AfterIntersectionBuilt()");

List<CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions);
bool comp(int i) =>
codes[i].opcode == OpCodes.Ldfld && codes[i].operand == fTempNodeBuffer &&
codes[i + 1].opcode == OpCodes.Callvirt && codes[i + 1].operand == mClear;
int index = TranspilerUtil.SearchGeneric(codes, comp, index: 0, counter: 2);
index -= 1; // index to insert instructions.

bool predicate(int i) =>
codes[i].opcode == OpCodes.Blt &&
codes[i - 1].opcode == OpCodes.Ldfld && codes[i - 1].operand == mSize &&
codes[i - 2].opcode == OpCodes.Ldfld && codes[i - 2].operand == fTempSegmentBuffer;
int index = TranspilerUtil.SearchGeneric(codes, predicate, index: 0, counter: 1);
index += 1; // index to insert instructions. (end of the loop)

var newInstructions = new[] {
new CodeInstruction(OpCodes.Ldarg_0), // load argument info
Expand Down
46 changes: 19 additions & 27 deletions TLM/TLM/Util/PlaceIntersectionUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ namespace TrafficManager.Util {
using System.Collections.Generic;
using System.Linq;
using CSUtil.Commons;
using Manager.Impl;
using TrafficManager.State.Asset;
using TrafficManager.Util;
using TrafficManager.Lifecycle;
using TrafficManager.Util.Extensions;

public static class PlaceIntersectionUtil {
///<summary>maps old netowkr ids to new network ids</summary>
/// <param name="oldSegments">source segment id array created by on asset serialization</param>
/// <param name="newSegmentIds">segment list provided by LoadPaths.</param>
public static void MapSegments(
/// <param name="map">segment map to fill in with pairs (old;new)</param>
private static void FillSegmentsMap(
SegmentNetworkIDs[] oldSegments,
ushort[] newSegmentIds,
Dictionary<InstanceID, InstanceID> map) {
Expand All @@ -34,8 +37,9 @@ public static void MapSegments(
/// </summary>
/// <param name="newSegmentIds">segment list provided by LoadPaths.</param>
public static void ApplyTrafficRules(BuildingInfo intersectionInfo, ushort[] newSegmentIds) {
/*************************
* Prepration: */
/****************/
/* Preparation: */
/****************/

Log._Debug($"PlaceIntersectionUtil.ApplyTrafficRules({intersectionInfo?.ToString() ?? "null"})");

Expand Down Expand Up @@ -64,34 +68,22 @@ public static void ApplyTrafficRules(BuildingInfo intersectionInfo, ushort[] new
var pathNetworkIDs = assetData.PathNetworkIDs;
if (pathNetworkIDs == null) return;

/*************************
* Apply traffic rules: */
/***********************/
/* Create segment map: */
/***********************/
Shortcuts.AssertNotNull(newSegmentIds, "newSegmentIds");
FillSegmentsMap(oldSegments: pathNetworkIDs, newSegmentIds: newSegmentIds, map: map);

MapSegments(oldSegments: pathNetworkIDs, newSegmentIds: newSegmentIds, map: map);
// Note to previous solution:
// Node/segment calculation shouldn't be performed at this state!
// Forcing it here may trigger another 'fake' LoadPaths call breaking other mods attached to that method!

foreach (var item in map)
CalculateNetwork(item.Value);

assetData.Record.Transfer(map);
/*****************************************/
/* Queue traffic rules transfer process: */
/*****************************************/
UtilityManager.Instance.QueueTransferRecordable(assetData.Record, map);

OnPlaceIntersection?.Invoke(intersectionInfo, map);
}

/// <summary>
/// early calculate networks so that we are able to set traffic rules without delay.
/// </summary>
public static void CalculateNetwork(InstanceID instanceId) {
switch (instanceId.Type) {
case InstanceType.NetNode:
ushort nodeId = instanceId.NetNode;
nodeId.ToNode().CalculateNode(nodeId);
break;
case InstanceType.NetSegment:
ushort segmentId = instanceId.NetSegment;
segmentId.ToSegment().CalculateSegment(segmentId);
break;
}
}

}
}