Giter Site home page Giter Site logo

Comments (25)

pardeike avatar pardeike commented on August 25, 2024

Please add information about the method being patched as well as the used patch methods. Mainly the signatures.

from harmony.

Leigon avatar Leigon commented on August 25, 2024
namespace TollRoad
{
    public class Node
    {
        public static void Hook()
        {
            try
            {
                // NetNode override
                //public void CalculateNode( ushort nodeID )
                var harmony = HarmonyInstance.Create( "com.leigon.cities_skylines.toll_road" );
                HarmonyInstance.DEBUG = true;
                
                MethodInfo targetmethod = AccessTools.Method( typeof( NetNode ), "CalculateNode" );
                HarmonyMethod prefixmethod = new HarmonyMethod( typeof( TollRoad.Node ).GetMethod( "CalculateNode_Prefix" ) );
                harmony.Patch( targetmethod, prefixmethod, null );
            }
            catch( System.Exception ex )
            {
                Logger.LogError( "Node", ex.ToString() );
            }
        }

        public static void CalculateNode_Prefix( NetNode __instance, ushort nodeID )
        {
            NetNode thisNode = NetManager.instance.m_nodes.m_buffer[ nodeID ];

            Logger.Log( "NetNode", "CalculateNode" );

            NetManager.instance.m_nodes.m_buffer[ nodeID ] = thisNode;
        }
    }
}

Reflection of prefixed mathod:

  public void CalculateNode(ushort nodeID)
  {
    if (this.m_flags == NetNode.Flags.None)
      return;
    NetManager instance = Singleton<NetManager>.instance;
    Vector3 vector3_1 = Vector3.zero;
    int num1 = 0;
    int num2 = 0;
    bool flag1 = false;
    bool flag2 = false;
    bool flag3 = false;
    bool flag4 = false;
    bool flag5 = false;
    bool flag6 = false;
    bool flag7 = false;
    bool flag8 = false;
    bool flag9 = false;
    bool flag10 = true;
    bool flag11 = true;
    bool flag12 = Singleton<TerrainManager>.instance.HasDetailMapping(this.m_position);
    NetInfo with1 = (NetInfo) null;
    int num3 = 0;
    int num4 = 0;
    NetInfo with2 = (NetInfo) null;
    float num5 = -1E+07f;
    for (int index = 0; index < 8; ++index)
    {
      ushort segment = this.GetSegment(index);
      if ((int) segment != 0)
      {
        NetInfo info = instance.m_segments.m_buffer[(int) segment].Info;
        float nodeInfoPriority = info.m_netAI.GetNodeInfoPriority(segment, ref instance.m_segments.m_buffer[(int) segment]);
        if ((double) nodeInfoPriority > (double) num5)
        {
          with2 = info;
          num5 = nodeInfoPriority;
        }
      }
    }
    if (with2 == null)
      with2 = this.Info;
    if (with2 != this.Info)
    {
      this.Info = with2;
      Singleton<NetManager>.instance.UpdateNodeColors(nodeID);
      if (!with2.m_canDisable)
        this.m_flags &= NetNode.Flags.OneWayOutTrafficLights | NetNode.Flags.UndergroundTransition | NetNode.Flags.Created | NetNode.Flags.Deleted | NetNode.Flags.Original | NetNode.Flags.End | NetNode.Flags.Middle | NetNode.Flags.Bend | NetNode.Flags.Junction | NetNode.Flags.Moveable | NetNode.Flags.Untouchable | NetNode.Flags.Outside | NetNode.Flags.Temporary | NetNode.Flags.Double | NetNode.Flags.Fixed | NetNode.Flags.OnGround | NetNode.Flags.Ambiguous | NetNode.Flags.Water | NetNode.Flags.Sewage | NetNode.Flags.ForbidLaneConnection | NetNode.Flags.LevelCrossing | NetNode.Flags.OneWayIn | NetNode.Flags.Heating | NetNode.Flags.Electricity | NetNode.Flags.Collapsed | NetNode.Flags.DisableOnlyMiddle | NetNode.Flags.AsymForward | NetNode.Flags.AsymBackward | NetNode.Flags.CustomTrafficLights;
    }
    bool flag13 = false;
    for (int index1 = 0; index1 < 8; ++index1)
    {
      ushort segment1 = this.GetSegment(index1);
      if ((int) segment1 != 0)
      {
        ++num1;
        ushort startNode = instance.m_segments.m_buffer[(int) segment1].m_startNode;
        ushort endNode = instance.m_segments.m_buffer[(int) segment1].m_endNode;
        Vector3 startDirection = instance.m_segments.m_buffer[(int) segment1].m_startDirection;
        Vector3 endDirection = instance.m_segments.m_buffer[(int) segment1].m_endDirection;
        bool flag14 = (int) nodeID == (int) startNode;
        Vector3 vector3_2 = !flag14 ? endDirection : startDirection;
        NetInfo info1 = instance.m_segments.m_buffer[(int) segment1].Info;
        ItemClass connectionClass = info1.GetConnectionClass();
        if (!info1.m_netAI.CanModify())
          flag11 = false;
        int vehicleLaneCount1;
        int vehicleLaneCount2;
        if (flag14 == ((instance.m_segments.m_buffer[(int) segment1].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None))
        {
          vehicleLaneCount1 = info1.m_backwardVehicleLaneCount;
          vehicleLaneCount2 = info1.m_forwardVehicleLaneCount;
        }
        else
        {
          vehicleLaneCount1 = info1.m_forwardVehicleLaneCount;
          vehicleLaneCount2 = info1.m_backwardVehicleLaneCount;
        }
        for (int index2 = index1 + 1; index2 < 8; ++index2)
        {
          ushort segment2 = this.GetSegment(index2);
          if ((int) segment2 != 0)
          {
            NetInfo info2 = instance.m_segments.m_buffer[(int) segment2].Info;
            if (info2.GetConnectionClass().m_service == connectionClass.m_service || (info2.m_nodeConnectGroups & info1.m_connectGroup) != NetInfo.ConnectGroup.None || (info1.m_nodeConnectGroups & info2.m_connectGroup) != NetInfo.ConnectGroup.None)
            {
              Vector3 vector3_3 = (int) nodeID != (int) instance.m_segments.m_buffer[(int) segment2].m_startNode ? instance.m_segments.m_buffer[(int) segment2].m_endDirection : instance.m_segments.m_buffer[(int) segment2].m_startDirection;
              if ((double) vector3_2.x * (double) vector3_3.x + (double) vector3_2.z * (double) vector3_3.z < (double) (0.01f - Mathf.Min(info1.m_maxTurnAngleCos, info2.m_maxTurnAngleCos)))
              {
                if (info1.m_requireDirectRenderers && (info1.m_nodeConnectGroups == NetInfo.ConnectGroup.None || (info1.m_nodeConnectGroups & info2.m_connectGroup) != NetInfo.ConnectGroup.None) || info2.m_requireDirectRenderers && (info2.m_nodeConnectGroups == NetInfo.ConnectGroup.None || (info2.m_nodeConnectGroups & info1.m_connectGroup) != NetInfo.ConnectGroup.None))
                  ++num2;
              }
              else
                flag6 = true;
            }
            else
              flag6 = true;
          }
        }
        if ((int) instance.m_nodes.m_buffer[(int) startNode].m_elevation != (int) instance.m_nodes.m_buffer[(int) endNode].m_elevation)
          flag10 = false;
        Vector3 position1 = instance.m_nodes.m_buffer[(int) startNode].m_position;
        Vector3 position2 = instance.m_nodes.m_buffer[(int) endNode].m_position;
        flag12 = !flag14 ? flag12 && Singleton<TerrainManager>.instance.HasDetailMapping(position1) : flag12 && Singleton<TerrainManager>.instance.HasDetailMapping(position2);
        if (NetSegment.IsStraight(position1, startDirection, position2, endDirection))
          flag8 = true;
        else
          flag7 = true;
        if (num1 == 1)
        {
          flag13 = flag14;
          vector3_1 = vector3_2;
          flag1 = true;
        }
        else if (num1 == 2 && info1.IsCombatible(with1) && (info1.IsCombatible(with2) && vehicleLaneCount1 != 0 == (num4 != 0)) && vehicleLaneCount2 != 0 == (num3 != 0))
        {
          float num6 = (float) ((double) vector3_1.x * (double) vector3_2.x + (double) vector3_1.z * (double) vector3_2.z);
          if (vehicleLaneCount1 != num4 || vehicleLaneCount2 != num3)
          {
            if (vehicleLaneCount1 > vehicleLaneCount2)
            {
              flag4 = true;
              flag3 = true;
            }
            else
            {
              flag5 = true;
              flag3 = true;
            }
          }
          else if ((double) num6 < -0.999000012874603)
            flag2 = true;
          else
            flag3 = true;
          flag9 = flag14 != flag13;
        }
        else
          flag6 = true;
        with1 = info1;
        num3 = vehicleLaneCount1;
        num4 = vehicleLaneCount2;
      }
    }
    if (!with2.m_enableMiddleNodes & flag2)
      flag3 = true;
    if (!with2.m_enableBendingNodes & flag3)
      flag6 = true;
    if (with2.m_requireContinuous && (this.m_flags & NetNode.Flags.Untouchable) != NetNode.Flags.None)
      flag6 = true;
    if (with2.m_requireContinuous && !flag9 && (flag2 || flag3))
      flag6 = true;
    NetNode.Flags flags = this.m_flags & (NetNode.Flags.OneWayOutTrafficLights | NetNode.Flags.UndergroundTransition | NetNode.Flags.Created | NetNode.Flags.Deleted | NetNode.Flags.Original | NetNode.Flags.Disabled | NetNode.Flags.Untouchable | NetNode.Flags.Outside | NetNode.Flags.Temporary | NetNode.Flags.Double | NetNode.Flags.Fixed | NetNode.Flags.OnGround | NetNode.Flags.Ambiguous | NetNode.Flags.Water | NetNode.Flags.Sewage | NetNode.Flags.ForbidLaneConnection | NetNode.Flags.LevelCrossing | NetNode.Flags.OneWayIn | NetNode.Flags.Heating | NetNode.Flags.Electricity | NetNode.Flags.Collapsed | NetNode.Flags.DisableOnlyMiddle | NetNode.Flags.CustomTrafficLights);
    if ((flags & NetNode.Flags.Outside) != NetNode.Flags.None)
      this.m_flags = flags;
    else if (flag6)
      this.m_flags = flags | NetNode.Flags.Junction;
    else if (flag3)
    {
      if (flag4)
        flags |= NetNode.Flags.AsymForward;
      if (flag5)
        flags |= NetNode.Flags.AsymBackward;
      this.m_flags = flags | NetNode.Flags.Bend;
    }
    else if (flag2)
    {
      if ((!flag7 || !flag8) && ((this.m_flags & (NetNode.Flags.Untouchable | NetNode.Flags.Double)) == NetNode.Flags.None && flag10) && flag11)
        flags |= NetNode.Flags.Moveable;
      this.m_flags = flags | NetNode.Flags.Middle;
    }
    else if (flag1)
    {
      if ((this.m_flags & NetNode.Flags.Untouchable) == NetNode.Flags.None && flag10 && (flag11 && with2.m_enableMiddleNodes))
        flags |= NetNode.Flags.Moveable;
      this.m_flags = flags | NetNode.Flags.End;
    }
    this.m_heightOffset = flag12 || !with2.m_requireSurfaceMaps ? (byte) 0 : (byte) 64;
    this.m_connectCount = (byte) num2;
    BuildingInfo building;
    float heightOffset;
    with2.m_netAI.GetNodeBuilding(nodeID, ref this, out building, out heightOffset);
    this.UpdateBuilding(nodeID, building, heightOffset);
  }

from harmony.

pardeike avatar pardeike commented on August 25, 2024

Can you provide the IL code for the original method? Not necessarily the whole but mainly like +/- 10 lines around the calling for GetNodeBuilding to compare the IL code that Harmony spits out with the original IL code. Almost all problem can be examined by comparing the original IL code with the final Harmony result that is in the debug log.

Because currently, Harmony does not support TRY/CATCH on the IL level. And even if the decompiled code does not have a try/catch statement, the IL code can actually have it and right now, Harmony cannot handle the meta data of try/catch ranges and thus the corresponding IL codes will not work as expected. As a side result, a finally handler is not executed.

from harmony.

Leigon avatar Leigon commented on August 25, 2024

Sure.

IL_06eb: ldfld bool NetInfo::m_enableMiddleNodes
IL_06f0: brfalse IL_06ff
IL_06f5: ldloc.s V_49
IL_06f7: ldc.i4 0x100
IL_06fc: or
IL_06fd: stloc.s V_49
IL_06ff: ldarg.0
IL_0700: ldloc.s V_49
IL_0702: ldc.i4.s 16
IL_0704: or
IL_0705: stfld valuetype NetNode/Flags NetNode::m_flags
IL_070a: ldarg.0
IL_070b: ldloc.s V_15
IL_070d: brtrue IL_071e
IL_0712: ldloc.s V_19
IL_0714: ldfld bool NetInfo::m_requireSurfaceMaps
IL_0719: brtrue IL_0724
IL_071e: ldc.i4.0
IL_071f: br IL_0726
IL_0724: ldc.i4.s 64
IL_0726: conv.u1
IL_0727: stfld uint8 NetNode::m_heightOffset
IL_072c: ldarg.0
IL_072d: ldloc.3
IL_072e: conv.u1
IL_072f: stfld uint8 NetNode::m_connectCount
IL_0734: ldloc.s V_19
IL_0736: ldfld class NetAI NetInfo::m_netAI
IL_073b: ldarg.1
IL_073c: ldarg.0
IL_073d: ldloca.s V_50
IL_073f: ldloca.s V_51
IL_0741: callvirt instance void NetAI::GetNodeBuilding(uint16,
valuetype NetNode&,
class BuildingInfo&,
float32&)
IL_0746: ldarg.0
IL_0747: ldarg.1
IL_0748: ldloc.s V_50
IL_074a: ldloc.s V_51
IL_074c: call instance void NetNode::UpdateBuilding(uint16,
class BuildingInfo,
float32)
IL_0751: ret
} // end of method NetNode::CalculateNode

from harmony.

Leigon avatar Leigon commented on August 25, 2024

Hi @pardeike

Any luck with this?
Thanks,
-Adrian

from harmony.

pardeike avatar pardeike commented on August 25, 2024

I only had a quick look but could not spot the problem right away. The thing is that this error is at a place where Harmony does not interface with the IL code much. It just copies it from the original. The only thing that might be unusual here is that it seems to be a ref this.

I have to look more into this. Meanwhile, would you be able to create a minimal test case to reproduce this? The method here is a bit too big to handle.

I am actively working on the next release that fixes a few things so the timing is right.

Thanks

from harmony.

pardeike avatar pardeike commented on August 25, 2024

Can you please verify if this error persist with the latest master?

from harmony.

Leigon avatar Leigon commented on August 25, 2024

Hi, sorry for not helping out with this, I have had a bit of real life issues.

With the latest master I get:

System.InvalidProgramException: Invalid IL code in (wrapper dynamic-method) NetNode:CalculateNode_Patch1 (object,uint16): IL_0007: call 0x00000001

at (wrapper managed-to-native) System.RuntimeMethodHandle:GetFunctionPointer (intptr)
at System.RuntimeMethodHandle.GetFunctionPointer () [0x00000] in :0
at Harmony.ILCopying.Memory.GetMethodStart (System.Reflection.MethodBase method) [0x00000] in :0
at Harmony.PatchFunctions.UpdateWrapper (System.Reflection.MethodBase original, Harmony.PatchInfo patchInfo, System.String instanceID) [0x00000] in :0
at Harmony.PatchProcessor.Patch () [0x00000] in :0
at Harmony.HarmonyInstance.Patch (System.Reflection.MethodBase original, Harmony.HarmonyMethod prefix, Harmony.HarmonyMethod postfix, Harmony.HarmonyMethod transpiler) [0x00000] in :0
at TollRoad.Node.Hook () [0x00000] in :0

I assume my code is out of date?

using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using ColossalFramework;
using System;
using Harmony;
namespace TollRoad
{
    public class Node
    {
        public enum Flags
        {
            Toll = NetNode.Flags.Water
        }

        public static void Hook()
        {
            FileLog.logPath = "E:\\error.txt"; 
            try
            {
                // NetNode override
                //public void CalculateNode( ushort nodeID )
                var harmony = HarmonyInstance.Create( "com.leigon.cities_skylines.toll_road" );
                HarmonyInstance.DEBUG = true;

                MethodInfo targetmethod = AccessTools.Method( typeof( NetNode ), "CalculateNode" );
                HarmonyMethod prefixmethod = new HarmonyMethod( typeof( TollRoad.Node ).GetMethod( "CalculateNode_Prefix" ) );

                harmony.Patch( targetmethod, prefixmethod, null );
            }
            catch( System.Exception ex )
            {
                Logger.LogError( "Node", ex.ToString() );
                FileLog.Log( ex.ToString() );
            }
        }

        public static void CalculateNode_Prefix( NetNode __instance, ushort nodeID )
        {
            NetNode thisNode = NetManager.instance.m_nodes.m_buffer[ nodeID ];

            Logger.Log( "NetNode", "CalculateNode" );

            NetManager.instance.m_nodes.m_buffer[ nodeID ] = thisNode;
        }
    }
}
L_0000: Local var 0: NetManager
L_0000: Local var 1: UnityEngine.Vector3
L_0000: Local var 2: System.Int32
L_0000: Local var 3: System.Int32
L_0000: Local var 4: System.Boolean
L_0000: Local var 5: System.Boolean
L_0000: Local var 6: System.Boolean
L_0000: Local var 7: System.Boolean
L_0000: Local var 8: System.Boolean
L_0000: Local var 9: System.Boolean
L_0000: Local var 10: System.Boolean
L_0000: Local var 11: System.Boolean
L_0000: Local var 12: System.Boolean
L_0000: Local var 13: System.Boolean
L_0000: Local var 14: System.Boolean
L_0000: Local var 15: System.Boolean
L_0000: Local var 16: NetInfo
L_0000: Local var 17: System.Int32
L_0000: Local var 18: System.Int32
L_0000: Local var 19: NetInfo
L_0000: Local var 20: System.Single
L_0000: Local var 21: System.Int32
L_0000: Local var 22: System.UInt16
L_0000: Local var 23: NetInfo
L_0000: Local var 24: System.Single
L_0000: Local var 25: System.Boolean
L_0000: Local var 26: System.Int32
L_0000: Local var 27: System.UInt16
L_0000: Local var 28: System.UInt16
L_0000: Local var 29: System.UInt16
L_0000: Local var 30: UnityEngine.Vector3
L_0000: Local var 31: UnityEngine.Vector3
L_0000: Local var 32: System.Boolean
L_0000: Local var 33: UnityEngine.Vector3
L_0000: Local var 34: NetInfo
L_0000: Local var 35: ItemClass
L_0000: Local var 36: System.Int32
L_0000: Local var 37: System.Int32
L_0000: Local var 38: System.Int32
L_0000: Local var 39: System.UInt16
L_0000: Local var 40: NetInfo
L_0000: Local var 41: ItemClass
L_0000: Local var 42: System.Boolean
L_0000: Local var 43: UnityEngine.Vector3
L_0000: Local var 44: System.Single
L_0000: Local var 45: System.Single
L_0000: Local var 46: UnityEngine.Vector3
L_0000: Local var 47: UnityEngine.Vector3
L_0000: Local var 48: System.Single
L_0000: Local var 49: NetNode+Flags
L_0000: Local var 50: BuildingInfo
L_0000: Local var 51: System.Single
L_0000: ldarg.0
L_0001: ldarg 1
L_0007: call Void CalculateNode_Prefix(NetNode, UInt16)
L_000c: ldarg.0
L_000d: ldfld NetNode+Flags m_flags
L_0012: brtrue Label1
L_0017: br Label89
L_001c: Label1
L_001c: call NetManager get_instance()
L_0021: stloc.0
L_0022: call Vector3 get_zero()
L_0027: stloc.1
L_0028: ldc.i4.0
L_0029: stloc.2
L_002a: ldc.i4.0
L_002b: stloc.3
L_002c: ldc.i4.0
L_002d: stloc.s 4 (System.Boolean)
L_002f: ldc.i4.0
L_0030: stloc.s 5 (System.Boolean)
L_0032: ldc.i4.0
L_0033: stloc.s 6 (System.Boolean)
L_0035: ldc.i4.0
L_0036: stloc.s 7 (System.Boolean)
L_0038: ldc.i4.0
L_0039: stloc.s 8 (System.Boolean)
L_003b: ldc.i4.0
L_003c: stloc.s 9 (System.Boolean)
L_003e: ldc.i4.0
L_003f: stloc.s 10 (System.Boolean)
L_0041: ldc.i4.0
L_0042: stloc.s 11 (System.Boolean)
L_0044: ldc.i4.0
L_0045: stloc.s 12 (System.Boolean)
L_0047: ldc.i4.1
L_0048: stloc.s 13 (System.Boolean)
L_004a: ldc.i4.1
L_004b: stloc.s 14 (System.Boolean)
L_004d: call TerrainManager get_instance()
L_0052: ldarg.0
L_0053: ldfld UnityEngine.Vector3 m_position
L_0058: callvirt Boolean HasDetailMapping(Vector3)
L_005d: stloc.s 15 (System.Boolean)
L_005f: ldnull
L_0060: stloc.s 16 (NetInfo)
L_0062: ldc.i4.0
L_0063: stloc.s 17 (System.Int32)
L_0065: ldc.i4.0
L_0066: stloc.s 18 (System.Int32)
L_0068: ldnull
L_0069: stloc.s 19 (NetInfo)
L_006b: ldc.r4 -1E+07
L_0070: stloc.s 20 (System.Single)
L_0072: ldc.i4.0
L_0073: stloc.s 21 (System.Int32)
L_0075: br Label2
L_007a: Label5
L_007a: ldarg.0
L_007b: ldloc.s 21 (System.Int32)
L_007d: call UInt16 GetSegment(Int32)
L_0082: stloc.s 22 (System.UInt16)
L_0084: ldloc.s 22 (System.UInt16)
L_0086: brfalse Label3
L_008b: ldloc.0
L_008c: ldfld Array16`1[NetSegment] m_segments
L_0091: ldfld NetSegment[] m_buffer
L_0096: ldloc.s 22 (System.UInt16)
L_0098: ldelema NetSegment
L_009d: call NetInfo get_Info()
L_00a2: stloc.s 23 (NetInfo)
L_00a4: ldloc.s 23 (NetInfo)
L_00a6: ldfld NetAI m_netAI
L_00ab: ldloc.s 22 (System.UInt16)
L_00ad: ldloc.0
L_00ae: ldfld Array16`1[NetSegment] m_segments
L_00b3: ldfld NetSegment[] m_buffer
L_00b8: ldloc.s 22 (System.UInt16)
L_00ba: ldelema NetSegment
L_00bf: callvirt Single GetNodeInfoPriority(UInt16, NetSegment ByRef)
L_00c4: stloc.s 24 (System.Single)
L_00c6: ldloc.s 24 (System.Single)
L_00c8: ldloc.s 20 (System.Single)
L_00ca: ble.un Label4
L_00cf: ldloc.s 23 (NetInfo)
L_00d1: stloc.s 19 (NetInfo)
L_00d3: ldloc.s 24 (System.Single)
L_00d5: stloc.s 20 (System.Single)
L_00d7: Label3
L_00d7: Label4
L_00d7: ldloc.s 21 (System.Int32)
L_00d9: ldc.i4.1
L_00da: add
L_00db: stloc.s 21 (System.Int32)
L_00dd: Label2
L_00dd: ldloc.s 21 (System.Int32)
L_00df: ldc.i4.8
L_00e0: blt Label5
L_00e5: ldloc.s 19 (NetInfo)
L_00e7: brtrue Label6
L_00ec: ldarg.0
L_00ed: call NetInfo get_Info()
L_00f2: stloc.s 19 (NetInfo)
L_00f4: Label6
L_00f4: ldloc.s 19 (NetInfo)
L_00f6: ldarg.0
L_00f7: call NetInfo get_Info()
L_00fc: beq Label7
L_0101: ldarg.0
L_0102: ldloc.s 19 (NetInfo)
L_0104: call Void set_Info(NetInfo)
L_0109: call NetManager get_instance()
L_010e: ldarg.1
L_010f: callvirt Void UpdateNodeColors(UInt16)
L_0114: ldloc.s 19 (NetInfo)
L_0116: ldfld System.Boolean m_canDisable
L_011b: brtrue Label8
L_0120: ldarg.0
L_0121: dup
L_0122: ldfld NetNode+Flags m_flags
L_0127: ldc.i4.s -9
L_0129: and
L_012a: stfld NetNode+Flags m_flags
L_012f: Label7
L_012f: Label8
L_012f: ldc.i4.0
L_0130: stloc.s 25 (System.Boolean)
L_0132: ldc.i4.0
L_0133: stloc.s 26 (System.Int32)
L_0135: br Label9
L_013a: Label57
L_013a: ldarg.0
L_013b: ldloc.s 26 (System.Int32)
L_013d: call UInt16 GetSegment(Int32)
L_0142: stloc.s 27 (System.UInt16)
L_0144: ldloc.s 27 (System.UInt16)
L_0146: brfalse Label10
L_014b: ldloc.2
L_014c: ldc.i4.1
L_014d: add
L_014e: stloc.2
L_014f: ldloc.0
L_0150: ldfld Array16`1[NetSegment] m_segments
L_0155: ldfld NetSegment[] m_buffer
L_015a: ldloc.s 27 (System.UInt16)
L_015c: ldelema NetSegment
L_0161: ldfld System.UInt16 m_startNode
L_0166: stloc.s 28 (System.UInt16)
L_0168: ldloc.0
L_0169: ldfld Array16`1[NetSegment] m_segments
L_016e: ldfld NetSegment[] m_buffer
L_0173: ldloc.s 27 (System.UInt16)
L_0175: ldelema NetSegment
L_017a: ldfld System.UInt16 m_endNode
L_017f: stloc.s 29 (System.UInt16)
L_0181: ldloc.0
L_0182: ldfld Array16`1[NetSegment] m_segments
L_0187: ldfld NetSegment[] m_buffer
L_018c: ldloc.s 27 (System.UInt16)
L_018e: ldelema NetSegment
L_0193: ldfld UnityEngine.Vector3 m_startDirection
L_0198: stloc.s 30 (UnityEngine.Vector3)
L_019a: ldloc.0
L_019b: ldfld Array16`1[NetSegment] m_segments
L_01a0: ldfld NetSegment[] m_buffer
L_01a5: ldloc.s 27 (System.UInt16)
L_01a7: ldelema NetSegment
L_01ac: ldfld UnityEngine.Vector3 m_endDirection
L_01b1: stloc.s 31 (UnityEngine.Vector3)
L_01b3: ldarg.1
L_01b4: ldloc.s 28 (System.UInt16)
L_01b6: ceq
L_01b8: stloc.s 32 (System.Boolean)
L_01ba: ldloc.s 32 (System.Boolean)
L_01bc: brfalse Label11
L_01c1: ldloc.s 30 (UnityEngine.Vector3)
L_01c3: br Label12
L_01c8: Label11
L_01c8: ldloc.s 31 (UnityEngine.Vector3)
L_01ca: Label12
L_01ca: stloc.s 33 (UnityEngine.Vector3)
L_01cc: ldloc.0
L_01cd: ldfld Array16`1[NetSegment] m_segments
L_01d2: ldfld NetSegment[] m_buffer
L_01d7: ldloc.s 27 (System.UInt16)
L_01d9: ldelema NetSegment
L_01de: call NetInfo get_Info()
L_01e3: stloc.s 34 (NetInfo)
L_01e5: ldloc.s 34 (NetInfo)
L_01e7: callvirt ItemClass GetConnectionClass()
L_01ec: stloc.s 35 (ItemClass)
L_01ee: ldloc.s 34 (NetInfo)
L_01f0: ldfld NetAI m_netAI
L_01f5: callvirt Boolean CanModify()
L_01fa: brtrue Label13
L_01ff: ldc.i4.0
L_0200: stloc.s 14 (System.Boolean)
L_0202: Label13
L_0202: ldloc.s 32 (System.Boolean)
L_0204: ldloc.0
L_0205: ldfld Array16`1[NetSegment] m_segments
L_020a: ldfld NetSegment[] m_buffer
L_020f: ldloc.s 27 (System.UInt16)
L_0211: ldelema NetSegment
L_0216: ldfld NetSegment+Flags m_flags
L_021b: ldc.i4.s 16
L_021d: and
L_021e: ldc.i4.0
L_021f: ceq
L_0221: ldc.i4.0
L_0222: ceq
L_0224: bne.un Label14
L_0229: ldloc.s 34 (NetInfo)
L_022b: ldfld System.Int32 m_backwardVehicleLaneCount
L_0230: stloc.s 36 (System.Int32)
L_0232: ldloc.s 34 (NetInfo)
L_0234: ldfld System.Int32 m_forwardVehicleLaneCount
L_0239: stloc.s 37 (System.Int32)
L_023b: br Label15
L_0240: Label14
L_0240: ldloc.s 34 (NetInfo)
L_0242: ldfld System.Int32 m_forwardVehicleLaneCount
L_0247: stloc.s 36 (System.Int32)
L_0249: ldloc.s 34 (NetInfo)
L_024b: ldfld System.Int32 m_backwardVehicleLaneCount
L_0250: stloc.s 37 (System.Int32)
L_0252: Label15
L_0252: ldloc.s 26 (System.Int32)
L_0254: ldc.i4.1
L_0255: add
L_0256: stloc.s 38 (System.Int32)
L_0258: br Label16
L_025d: Label32
L_025d: ldarg.0
L_025e: ldloc.s 38 (System.Int32)
L_0260: call UInt16 GetSegment(Int32)
L_0265: stloc.s 39 (System.UInt16)
L_0267: ldloc.s 39 (System.UInt16)
L_0269: brfalse Label17
L_026e: ldloc.0
L_026f: ldfld Array16`1[NetSegment] m_segments
L_0274: ldfld NetSegment[] m_buffer
L_0279: ldloc.s 39 (System.UInt16)
L_027b: ldelema NetSegment
L_0280: call NetInfo get_Info()
L_0285: stloc.s 40 (NetInfo)
L_0287: ldloc.s 40 (NetInfo)
L_0289: callvirt ItemClass GetConnectionClass()
L_028e: stloc.s 41 (ItemClass)
L_0290: ldloc.s 41 (ItemClass)
L_0292: ldfld ItemClass+Service m_service
L_0297: ldloc.s 35 (ItemClass)
L_0299: ldfld ItemClass+Service m_service
L_029e: beq Label18
L_02a3: ldloc.s 40 (NetInfo)
L_02a5: ldfld NetInfo+ConnectGroup m_nodeConnectGroups
L_02aa: ldloc.s 34 (NetInfo)
L_02ac: ldfld NetInfo+ConnectGroup m_connectGroup
L_02b1: and
L_02b2: brtrue Label19
L_02b7: ldloc.s 34 (NetInfo)
L_02b9: ldfld NetInfo+ConnectGroup m_nodeConnectGroups
L_02be: ldloc.s 40 (NetInfo)
L_02c0: ldfld NetInfo+ConnectGroup m_connectGroup
L_02c5: and
L_02c6: brfalse Label20
L_02cb: Label18
L_02cb: Label19
L_02cb: ldarg.1
L_02cc: ldloc.0
L_02cd: ldfld Array16`1[NetSegment] m_segments
L_02d2: ldfld NetSegment[] m_buffer
L_02d7: ldloc.s 39 (System.UInt16)
L_02d9: ldelema NetSegment
L_02de: ldfld System.UInt16 m_startNode
L_02e3: ceq
L_02e5: stloc.s 42 (System.Boolean)
L_02e7: ldloc.s 42 (System.Boolean)
L_02e9: brfalse Label21
L_02ee: ldloc.0
L_02ef: ldfld Array16`1[NetSegment] m_segments
L_02f4: ldfld NetSegment[] m_buffer
L_02f9: ldloc.s 39 (System.UInt16)
L_02fb: ldelema NetSegment
L_0300: ldfld UnityEngine.Vector3 m_startDirection
L_0305: br Label22
L_030a: Label21
L_030a: ldloc.0
L_030b: ldfld Array16`1[NetSegment] m_segments
L_0310: ldfld NetSegment[] m_buffer
L_0315: ldloc.s 39 (System.UInt16)
L_0317: ldelema NetSegment
L_031c: ldfld UnityEngine.Vector3 m_endDirection
L_0321: Label22
L_0321: stloc.s 43 (UnityEngine.Vector3)
L_0323: ldloca.s 33 (UnityEngine.Vector3)
L_0325: ldfld System.Single x
L_032a: ldloca.s 43 (UnityEngine.Vector3)
L_032c: ldfld System.Single x
L_0331: mul
L_0332: ldloca.s 33 (UnityEngine.Vector3)
L_0334: ldfld System.Single z
L_0339: ldloca.s 43 (UnityEngine.Vector3)
L_033b: ldfld System.Single z
L_0340: mul
L_0341: add
L_0342: stloc.s 44 (System.Single)
L_0344: ldc.r4 0.01
L_0349: ldloc.s 34 (NetInfo)
L_034b: ldfld System.Single m_maxTurnAngleCos
L_0350: ldloc.s 40 (NetInfo)
L_0352: ldfld System.Single m_maxTurnAngleCos
L_0357: call Single Min(Single, Single)
L_035c: sub
L_035d: stloc.s 45 (System.Single)
L_035f: ldloc.s 44 (System.Single)
L_0361: ldloc.s 45 (System.Single)
L_0363: bge.un Label23
L_0368: ldloc.s 34 (NetInfo)
L_036a: ldfld System.Boolean m_requireDirectRenderers
L_036f: brfalse Label24
L_0374: ldloc.s 34 (NetInfo)
L_0376: ldfld NetInfo+ConnectGroup m_nodeConnectGroups
L_037b: brfalse Label25
L_0380: ldloc.s 34 (NetInfo)
L_0382: ldfld NetInfo+ConnectGroup m_nodeConnectGroups
L_0387: ldloc.s 40 (NetInfo)
L_0389: ldfld NetInfo+ConnectGroup m_connectGroup
L_038e: and
L_038f: brtrue Label26
L_0394: Label24
L_0394: ldloc.s 40 (NetInfo)
L_0396: ldfld System.Boolean m_requireDirectRenderers
L_039b: brfalse Label27
L_03a0: ldloc.s 40 (NetInfo)
L_03a2: ldfld NetInfo+ConnectGroup m_nodeConnectGroups
L_03a7: brfalse Label28
L_03ac: ldloc.s 40 (NetInfo)
L_03ae: ldfld NetInfo+ConnectGroup m_nodeConnectGroups
L_03b3: ldloc.s 34 (NetInfo)
L_03b5: ldfld NetInfo+ConnectGroup m_connectGroup
L_03ba: and
L_03bb: brfalse Label29
L_03c0: Label25
L_03c0: Label26
L_03c0: Label28
L_03c0: ldloc.3
L_03c1: ldc.i4.1
L_03c2: add
L_03c3: stloc.3
L_03c4: Label27
L_03c4: Label29
L_03c4: br Label30
L_03c9: Label23
L_03c9: ldc.i4.1
L_03ca: stloc.s 9 (System.Boolean)
L_03cc: Label30
L_03cc: br Label31
L_03d1: Label20
L_03d1: ldc.i4.1
L_03d2: stloc.s 9 (System.Boolean)
L_03d4: Label17
L_03d4: Label31
L_03d4: ldloc.s 38 (System.Int32)
L_03d6: ldc.i4.1
L_03d7: add
L_03d8: stloc.s 38 (System.Int32)
L_03da: Label16
L_03da: ldloc.s 38 (System.Int32)
L_03dc: ldc.i4.8
L_03dd: blt Label32
L_03e2: ldloc.0
L_03e3: ldfld Array16`1[NetNode] m_nodes
L_03e8: ldfld NetNode[] m_buffer
L_03ed: ldloc.s 28 (System.UInt16)
L_03ef: ldelema NetNode
L_03f4: ldfld System.Byte m_elevation
L_03f9: ldloc.0
L_03fa: ldfld Array16`1[NetNode] m_nodes
L_03ff: ldfld NetNode[] m_buffer
L_0404: ldloc.s 29 (System.UInt16)
L_0406: ldelema NetNode
L_040b: ldfld System.Byte m_elevation
L_0410: beq Label33
L_0415: ldc.i4.0
L_0416: stloc.s 13 (System.Boolean)
L_0418: Label33
L_0418: ldloc.0
L_0419: ldfld Array16`1[NetNode] m_nodes
L_041e: ldfld NetNode[] m_buffer
L_0423: ldloc.s 28 (System.UInt16)
L_0425: ldelema NetNode
L_042a: ldfld UnityEngine.Vector3 m_position
L_042f: stloc.s 46 (UnityEngine.Vector3)
L_0431: ldloc.0
L_0432: ldfld Array16`1[NetNode] m_nodes
L_0437: ldfld NetNode[] m_buffer
L_043c: ldloc.s 29 (System.UInt16)
L_043e: ldelema NetNode
L_0443: ldfld UnityEngine.Vector3 m_position
L_0448: stloc.s 47 (UnityEngine.Vector3)
L_044a: ldloc.s 32 (System.Boolean)
L_044c: brfalse Label34
L_0451: ldloc.s 15 (System.Boolean)
L_0453: brfalse Label35
L_0458: call TerrainManager get_instance()
L_045d: ldloc.s 47 (UnityEngine.Vector3)
L_045f: callvirt Boolean HasDetailMapping(Vector3)
L_0464: br Label36
L_0469: Label35
L_0469: ldc.i4.0
L_046a: Label36
L_046a: stloc.s 15 (System.Boolean)
L_046c: br Label37
L_0471: Label34
L_0471: ldloc.s 15 (System.Boolean)
L_0473: brfalse Label38
L_0478: call TerrainManager get_instance()
L_047d: ldloc.s 46 (UnityEngine.Vector3)
L_047f: callvirt Boolean HasDetailMapping(Vector3)
L_0484: br Label39
L_0489: Label38
L_0489: ldc.i4.0
L_048a: Label39
L_048a: stloc.s 15 (System.Boolean)
L_048c: Label37
L_048c: ldloc.s 46 (UnityEngine.Vector3)
L_048e: ldloc.s 30 (UnityEngine.Vector3)
L_0490: ldloc.s 47 (UnityEngine.Vector3)
L_0492: ldloc.s 31 (UnityEngine.Vector3)
L_0494: call Boolean IsStraight(Vector3, Vector3, Vector3, Vector3)
L_0499: brfalse Label40
L_049e: ldc.i4.1
L_049f: stloc.s 11 (System.Boolean)
L_04a1: br Label41
L_04a6: Label40
L_04a6: ldc.i4.1
L_04a7: stloc.s 10 (System.Boolean)
L_04a9: Label41
L_04a9: ldloc.2
L_04aa: ldc.i4.1
L_04ab: bne.un Label42
L_04b0: ldloc.s 32 (System.Boolean)
L_04b2: stloc.s 25 (System.Boolean)
L_04b4: ldloc.s 33 (UnityEngine.Vector3)
L_04b6: stloc.1
L_04b7: ldc.i4.1
L_04b8: stloc.s 4 (System.Boolean)
L_04ba: br Label43
L_04bf: Label42
L_04bf: ldloc.2
L_04c0: ldc.i4.2
L_04c1: bne.un Label44
L_04c6: ldloc.s 34 (NetInfo)
L_04c8: ldloc.s 16 (NetInfo)
L_04ca: callvirt Boolean IsCombatible(NetInfo)
L_04cf: brfalse Label45
L_04d4: ldloc.s 34 (NetInfo)
L_04d6: ldloc.s 19 (NetInfo)
L_04d8: callvirt Boolean IsCombatible(NetInfo)
L_04dd: brfalse Label46
L_04e2: ldloc.s 36 (System.Int32)
L_04e4: ldc.i4.0
L_04e5: ceq
L_04e7: ldc.i4.0
L_04e8: ceq
L_04ea: ldloc.s 18 (System.Int32)
L_04ec: ldc.i4.0
L_04ed: ceq
L_04ef: ldc.i4.0
L_04f0: ceq
L_04f2: bne.un Label47
L_04f7: ldloc.s 37 (System.Int32)
L_04f9: ldc.i4.0
L_04fa: ceq
L_04fc: ldc.i4.0
L_04fd: ceq
L_04ff: ldloc.s 17 (System.Int32)
L_0501: ldc.i4.0
L_0502: ceq
L_0504: ldc.i4.0
L_0505: ceq
L_0507: bne.un Label48
L_050c: ldloca.s 1 (UnityEngine.Vector3)
L_050e: ldfld System.Single x
L_0513: ldloca.s 33 (UnityEngine.Vector3)
L_0515: ldfld System.Single x
L_051a: mul
L_051b: ldloca.s 1 (UnityEngine.Vector3)
L_051d: ldfld System.Single z
L_0522: ldloca.s 33 (UnityEngine.Vector3)
L_0524: ldfld System.Single z
L_0529: mul
L_052a: add
L_052b: stloc.s 48 (System.Single)
L_052d: ldloc.s 36 (System.Int32)
L_052f: ldloc.s 18 (System.Int32)
L_0531: bne.un Label49
L_0536: ldloc.s 37 (System.Int32)
L_0538: ldloc.s 17 (System.Int32)
L_053a: beq Label50
L_053f: Label49
L_053f: ldloc.s 36 (System.Int32)
L_0541: ldloc.s 37 (System.Int32)
L_0543: ble Label51
L_0548: ldc.i4.1
L_0549: stloc.s 7 (System.Boolean)
L_054b: ldc.i4.1
L_054c: stloc.s 6 (System.Boolean)
L_054e: br Label52
L_0553: Label51
L_0553: ldc.i4.1
L_0554: stloc.s 8 (System.Boolean)
L_0556: ldc.i4.1
L_0557: stloc.s 6 (System.Boolean)
L_0559: Label52
L_0559: br Label53
L_055e: Label50
L_055e: ldloc.s 48 (System.Single)
L_0560: ldc.r4 -0.999
L_0565: bge.un Label54
L_056a: ldc.i4.1
L_056b: stloc.s 5 (System.Boolean)
L_056d: br Label55
L_0572: Label54
L_0572: ldc.i4.1
L_0573: stloc.s 6 (System.Boolean)
L_0575: Label53
L_0575: Label55
L_0575: ldloc.s 32 (System.Boolean)
L_0577: ldloc.s 25 (System.Boolean)
L_0579: ceq
L_057b: ldc.i4.0
L_057c: ceq
L_057e: stloc.s 12 (System.Boolean)
L_0580: br Label56
L_0585: Label44
L_0585: Label45
L_0585: Label46
L_0585: Label47
L_0585: Label48
L_0585: ldc.i4.1
L_0586: stloc.s 9 (System.Boolean)
L_0588: Label43
L_0588: Label56
L_0588: ldloc.s 34 (NetInfo)
L_058a: stloc.s 16 (NetInfo)
L_058c: ldloc.s 36 (System.Int32)
L_058e: stloc.s 17 (System.Int32)
L_0590: ldloc.s 37 (System.Int32)
L_0592: stloc.s 18 (System.Int32)
L_0594: Label10
L_0594: ldloc.s 26 (System.Int32)
L_0596: ldc.i4.1
L_0597: add
L_0598: stloc.s 26 (System.Int32)
L_059a: Label9
L_059a: ldloc.s 26 (System.Int32)
L_059c: ldc.i4.8
L_059d: blt Label57
L_05a2: ldloc.s 19 (NetInfo)
L_05a4: ldfld System.Boolean m_enableMiddleNodes
L_05a9: ldc.i4.0
L_05aa: ceq
L_05ac: ldloc.s 5 (System.Boolean)
L_05ae: and
L_05af: brfalse Label58
L_05b4: ldc.i4.1
L_05b5: stloc.s 6 (System.Boolean)
L_05b7: Label58
L_05b7: ldloc.s 19 (NetInfo)
L_05b9: ldfld System.Boolean m_enableBendingNodes
L_05be: ldc.i4.0
L_05bf: ceq
L_05c1: ldloc.s 6 (System.Boolean)
L_05c3: and
L_05c4: brfalse Label59
L_05c9: ldc.i4.1
L_05ca: stloc.s 9 (System.Boolean)
L_05cc: Label59
L_05cc: ldloc.s 19 (NetInfo)
L_05ce: ldfld System.Boolean m_requireContinuous
L_05d3: brfalse Label60
L_05d8: ldarg.0
L_05d9: ldfld NetNode+Flags m_flags
L_05de: ldc.i4 512
L_05e3: and
L_05e4: brfalse Label61
L_05e9: ldc.i4.1
L_05ea: stloc.s 9 (System.Boolean)
L_05ec: Label60
L_05ec: Label61
L_05ec: ldloc.s 19 (NetInfo)
L_05ee: ldfld System.Boolean m_requireContinuous
L_05f3: brfalse Label62
L_05f8: ldloc.s 12 (System.Boolean)
L_05fa: brtrue Label63
L_05ff: ldloc.s 5 (System.Boolean)
L_0601: brtrue Label64
L_0606: ldloc.s 6 (System.Boolean)
L_0608: brfalse Label65
L_060d: Label64
L_060d: ldc.i4.1
L_060e: stloc.s 9 (System.Boolean)
L_0610: Label62
L_0610: Label63
L_0610: Label65
L_0610: ldarg.0
L_0611: ldfld NetNode+Flags m_flags
L_0616: ldc.i4 -1610613233
L_061b: and
L_061c: stloc.s 49 (NetNode+Flags)
L_061e: ldloc.s 49 (NetNode+Flags)
L_0620: ldc.i4 1024
L_0625: and
L_0626: brfalse Label66
L_062b: ldarg.0
L_062c: ldloc.s 49 (NetNode+Flags)
L_062e: stfld NetNode+Flags m_flags
L_0633: br Label67
L_0638: Label66
L_0638: ldloc.s 9 (System.Boolean)
L_063a: brfalse Label68
L_063f: ldarg.0
L_0640: ldloc.s 49 (NetNode+Flags)
L_0642: ldc.i4 128
L_0647: or
L_0648: stfld NetNode+Flags m_flags
L_064d: br Label69
L_0652: Label68
L_0652: ldloc.s 6 (System.Boolean)
L_0654: brfalse Label70
L_0659: ldloc.s 7 (System.Boolean)
L_065b: brfalse Label71
L_0660: ldloc.s 49 (NetNode+Flags)
L_0662: ldc.i4 536870912
L_0667: or
L_0668: stloc.s 49 (NetNode+Flags)
L_066a: Label71
L_066a: ldloc.s 8 (System.Boolean)
L_066c: brfalse Label72
L_0671: ldloc.s 49 (NetNode+Flags)
L_0673: ldc.i4 1073741824
L_0678: or
L_0679: stloc.s 49 (NetNode+Flags)
L_067b: Label72
L_067b: ldarg.0
L_067c: ldloc.s 49 (NetNode+Flags)
L_067e: ldc.i4.s 64
L_0680: or
L_0681: stfld NetNode+Flags m_flags
L_0686: br Label73
L_068b: Label70
L_068b: ldloc.s 5 (System.Boolean)
L_068d: brfalse Label74
L_0692: ldloc.s 10 (System.Boolean)
L_0694: brfalse Label75
L_0699: ldloc.s 11 (System.Boolean)
L_069b: brtrue Label76
L_06a0: Label75
L_06a0: ldarg.0
L_06a1: ldfld NetNode+Flags m_flags
L_06a6: ldc.i4 4608
L_06ab: and
L_06ac: brtrue Label77
L_06b1: ldloc.s 13 (System.Boolean)
L_06b3: brfalse Label78
L_06b8: ldloc.s 14 (System.Boolean)
L_06ba: brfalse Label79
L_06bf: ldloc.s 49 (NetNode+Flags)
L_06c1: ldc.i4 256
L_06c6: or
L_06c7: stloc.s 49 (NetNode+Flags)
L_06c9: Label76
L_06c9: Label77
L_06c9: Label78
L_06c9: Label79
L_06c9: ldarg.0
L_06ca: ldloc.s 49 (NetNode+Flags)
L_06cc: ldc.i4.s 32
L_06ce: or
L_06cf: stfld NetNode+Flags m_flags
L_06d4: br Label80
L_06d9: Label74
L_06d9: ldloc.s 4 (System.Boolean)
L_06db: brfalse Label81
L_06e0: ldarg.0
L_06e1: ldfld NetNode+Flags m_flags
L_06e6: ldc.i4 512
L_06eb: and
L_06ec: brtrue Label82
L_06f1: ldloc.s 13 (System.Boolean)
L_06f3: brfalse Label83
L_06f8: ldloc.s 14 (System.Boolean)
L_06fa: brfalse Label84
L_06ff: ldloc.s 19 (NetInfo)
L_0701: ldfld System.Boolean m_enableMiddleNodes
L_0706: brfalse Label85
L_070b: ldloc.s 49 (NetNode+Flags)
L_070d: ldc.i4 256
L_0712: or
L_0713: stloc.s 49 (NetNode+Flags)
L_0715: Label82
L_0715: Label83
L_0715: Label84
L_0715: Label85
L_0715: ldarg.0
L_0716: ldloc.s 49 (NetNode+Flags)
L_0718: ldc.i4.s 16
L_071a: or
L_071b: stfld NetNode+Flags m_flags
L_0720: Label67
L_0720: Label69
L_0720: Label73
L_0720: Label80
L_0720: Label81
L_0720: ldarg.0
L_0721: ldloc.s 15 (System.Boolean)
L_0723: brtrue Label86
L_0728: ldloc.s 19 (NetInfo)
L_072a: ldfld System.Boolean m_requireSurfaceMaps
L_072f: brtrue Label87
L_0734: Label86
L_0734: ldc.i4.0
L_0735: br Label88
L_073a: Label87
L_073a: ldc.i4.s 64
L_073c: Label88
L_073c: conv.u1
L_073d: stfld System.Byte m_heightOffset
L_0742: ldarg.0
L_0743: ldloc.3
L_0744: conv.u1
L_0745: stfld System.Byte m_connectCount
L_074a: ldloc.s 19 (NetInfo)
L_074c: ldfld NetAI m_netAI
L_0751: ldarg.1
L_0752: ldarg.0
L_0753: ldloca.s 50 (BuildingInfo)
L_0755: ldloca.s 51 (System.Single)
L_0757: callvirt Void GetNodeBuilding(UInt16, NetNode ByRef, BuildingInfo ByRef, Single ByRef)
L_075c: ldarg.0
L_075d: ldarg.1
L_075e: ldloc.s 50 (BuildingInfo)
L_0760: ldloc.s 51 (System.Single)
L_0762: call Void UpdateBuilding(UInt16, BuildingInfo, Single)
L_0767: Label89
L_0767: ret
DONE

from harmony.

pardeike avatar pardeike commented on August 25, 2024

I have no idea why the IL code at 0007 is illegal. It is the call to your prefix method. That method is static and takes two parameters: NetNode __instance and ushort nodeID and both are loaded onto the stack with the IL commands before: L_0000: ldarg.0 and L_0001: ldarg 1. That makes sense if the original method is an instance method of NetNode. Because the 0th argument is the instance (NetNode) and the 1st argument will be the argument to the method, in this case the nodeID.

Could it be that the nodeID of the original is not the same type as in your patch? I can see of the debug log that Harmony says uint16 but you are using a ushort.

from harmony.

pardeike avatar pardeike commented on August 25, 2024

On a second thought, I think it has to do with the type of NetNode. Can you post the definition?

from harmony.

Leigon avatar Leigon commented on August 25, 2024
#region Assembly Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll
#endregion

using System;
using ColossalFramework.Math;
using UnityEngine;

public struct NetNode
{
    public Notification.Problem m_problems;
    public byte m_maxWaitTime;
    public byte m_connectCount;
    public byte m_heightOffset;
    public byte m_elevation;
    public byte m_laneOffset;
    public ushort m_infoIndex;
    public ushort m_finalCounter;
    public ushort m_tempCounter;
    public ushort m_nextGridNode;
    public ushort m_nextBuildingNode;
    public ushort m_nextLaneNode;
    public ushort m_transportLine;
    public ushort m_building;
    public byte m_coverage;
    public ushort m_segment6;
    public Bounds m_bounds;
    public Vector3 m_position;
    public uint m_buildIndex;
    public uint m_lane;
    public ushort m_segment0;
    public Flags m_flags;
    public ushort m_segment2;
    public ushort m_segment3;
    public ushort m_segment4;
    public ushort m_segment5;
    public ushort m_segment1;
    public ushort m_segment7;

    public NetInfo Info { get; set; }

    public static bool BlendJunction( ushort nodeID );
    public static void CalculateGroupData( NetInfo.Node nodeInfo, ref int vertexCount, ref int triangleCount, ref int objectCount, ref RenderGroup.VertexArrays vertexArrays );
    public static ushort FindOwnerBuilding( ushort nodeID, float maxDistance );
    public static void PopulateGroupData( NetInfo info, NetInfo.Node nodeInfo, Matrix4x4 leftMatrix, Matrix4x4 rightMatrix, Vector4 meshScale, Vector4 objectIndex, ref int vertexIndex, ref int triangleIndex, RenderGroup.MeshData data, ref bool requireSurfaceMaps );
    public static void PopulateGroupData( NetInfo info, NetInfo.Node nodeInfo, Matrix4x4 leftMatrix, Matrix4x4 rightMatrix, Matrix4x4 leftMatrixB, Matrix4x4 rightMatrixB, Vector4 meshScale, Vector4 centerPos, Vector4 sideScale, Vector4 objectIndex, ref int vertexIndex, ref int triangleIndex, RenderGroup.MeshData data, ref bool requireSurfaceMaps );
    public static void RenderLod( RenderManager.CameraInfo cameraInfo, NetInfo.LodValue lod );
    public bool AddSegment( ushort segment );
    public void AfterTerrainUpdate( ushort nodeID, float minX, float minZ, float maxX, float maxZ );
    public bool CalculateGroupData( ushort nodeID, int layer, ref int vertexCount, ref int triangleCount, ref int objectCount, ref RenderGroup.VertexArrays vertexArrays );
    public void CalculateNode( ushort nodeID );
    public void CountLanes( ushort nodeID, ushort ignoreSegment, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, bool onePerSegment, ref int forward, ref int backward );
    public void CountLanes( ushort nodeID, ushort ignoreSegment, NetInfo.Direction directions, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, Vector3 direction, ref int left, ref int forward, ref int right, ref int left2, ref int forward2, ref int right2 );
    public int CountSegments();
    public int CountSegments( NetSegment.Flags flags, ushort ignoreSegment );
    public ushort GetSegment( int index );
    public bool IsConnectedTo( ushort node );
    public bool IsConnectedTo( ushort node1, ushort node2 );
    public void PopulateGroupData( ushort nodeID, int groupX, int groupZ, int layer, ref int vertexIndex, ref int triangleIndex, Vector3 groupPosition, RenderGroup.MeshData data, ref Vector3 min, ref Vector3 max, ref float maxRenderDistance, ref float maxInstanceDistance, ref bool requireSurfaceMaps );
    public bool RayCast( Segment3 ray, float snapElevation, out float t, out float priority );
    public bool RemoveSegment( ushort segment );
    public void RenderInstance( RenderManager.CameraInfo cameraInfo, ushort nodeID, int layerMask );
    public void TerrainUpdated( ushort nodeID, float minX, float minZ, float maxX, float maxZ );
    public void UpdateBounds( ushort nodeID );
    public void UpdateBuilding( ushort nodeID, BuildingInfo newBuilding, float heightOffset );
    public void UpdateLaneConnection( ushort nodeID );
    public void UpdateNode( ushort nodeID );

    [Flags]
    public enum Flags
    {
        CustomTrafficLights = int.MinValue,
        All = -1,
        None = 0,
        Created = 1,
        Deleted = 2,
        Original = 4,
        Disabled = 8,
        End = 16,
        Middle = 32,
        Bend = 64,
        Junction = 128,
        Moveable = 256,
        Untouchable = 512,
        Outside = 1024,
        Temporary = 2048,
        Double = 4096,
        Fixed = 8192,
        OnGround = 16384,
        Ambiguous = 32768,
        Water = 65536,
        Sewage = 131072,
        ForbidLaneConnection = 262144,
        Underground = 524288,
        Transition = 1048576,
        UndergroundTransition = 1572864,
        LevelCrossing = 2097152,
        OneWayOut = 4194304,
        TrafficLights = 8388608,
        OneWayOutTrafficLights = 12582912,
        OneWayIn = 16777216,
        Heating = 33554432,
        Electricity = 67108864,
        Collapsed = 134217728,
        DisableOnlyMiddle = 268435456,
        AsymForward = 536870912,
        AsymBackward = 1073741824
    }
}

from harmony.

pardeike avatar pardeike commented on August 25, 2024

Still cannot reproduce. This compiles and runs just fine:

using Harmony;
using System;

namespace HarmonyConsoleApp
{
	class Program
	{
		static void Main(string[] args)
		{
			var harmony = HarmonyInstance.Create("test");
			harmony.PatchAll(typeof(Program).Assembly);

			var node = new NetNode();
			node.CalculateNode(123);
			Console.ReadKey();
		}
	}

	public struct NetNode
	{
		public void CalculateNode(ushort nodeID)
		{
			Console.WriteLine("CalculateNode " + nodeID);
		}
	}

	[HarmonyPatch(typeof(NetNode))]
	[HarmonyPatch("CalculateNode")]
	static class Patch
	{
		[HarmonyPrefix]
		public static void CalculateNode_Prefix(NetNode __instance, ushort nodeID)
		{
			Console.WriteLine("Patch with " + __instance + " #" + nodeID);
		}
	}
}

from harmony.

pardeike avatar pardeike commented on August 25, 2024

Which .Net version are you using and also: are you testing in Debug or in Release compile mode? Are you sure you have the lates source code when you compile Harmony?

from harmony.

Leigon avatar Leigon commented on August 25, 2024

.Net 4, Debug.

I got latest through github desktop on a new clone today and installed c#7 via Install-Package Microsoft.Net.Compilers

from harmony.

pardeike avatar pardeike commented on August 25, 2024

What happens if you try to run my example?

from harmony.

Leigon avatar Leigon commented on August 25, 2024

Your sample works.

from harmony.

pardeike avatar pardeike commented on August 25, 2024

Then the question you might be able to answer better than me is: what is the difference between my example and the concrete use case you have.

from harmony.

Leigon avatar Leigon commented on August 25, 2024

Humm, I just created a new console app and using the skylines dll (and your sample without the struct) it works fine.

There is either something to do with my project settings or how skylines calls the mod dll I guess?

from harmony.

Leigon avatar Leigon commented on August 25, 2024

I have tried several iterations and they all work in the console app and not from the game...

Eventually I tried something simple and this didn't work in game but did in the app:
`
public class Node
{
public static void Hook()
{
FileLog.logPath = "E:\error.txt";

            NetNode2 node2 = new NetNode2(); 
            node2.CalculateNode( 1234 );

            var harmony = HarmonyInstance.Create( "test" );
            harmony.PatchAll( typeof( Node ).Assembly );

            node2.CalculateNode( 5678 );
    }
}

public struct NetNode2
{
    public void CalculateNode( ushort nodeID )
    {
        FileLog.Log( "CalculateNode " + nodeID );
    }
}

[HarmonyPatch( typeof( NetNode2 ) )]
[HarmonyPatch( "CalculateNode" )]
static class Patch2
{
    [HarmonyPrefix]
    public static void CalculateNode_Prefix( NetNode2 __instance, ushort nodeID )
    {
        FileLog.Log( "CalculateNode Prefix " + nodeID );
    }
}

`

Same error.
The project looks identical apart from one being a DLL and one being a EXE.

In morning I will create a new project and see if I can get that working, I can only assume its something I am doing (using a ThreadingExtension and hooking on OnCreated).

Thanks for the help, will get back to you tomorrow.
-Adrian

from harmony.

Leigon avatar Leigon commented on August 25, 2024

I started from scratch with a .net 4.5.2 debug dll mod simplest as possible with debug output:
`
using ICities;
using ColossalFramework.UI;
using UnityEngine;
using System;
using System.Reflection;
using Harmony;
using System.Diagnostics;

namespace TollRoad
{
public class ThreadingExtension : ThreadingExtensionBase
{
public static ThreadingExtension Instance { get; private set; }

    private static UInt32 LastInstanceCount = 1;
    private UInt32 InstanceCount { get; set; }

    public ThreadingExtension()
    {
        FileLog.logPath = "E:\\error.txt";
        Instance = null;
        InstanceCount = LastInstanceCount++;
        FileLog.Log( "ThreadingExtension Created " + InstanceCount.ToString() );
    }

    public override void OnCreated( IThreading threading )
    {
        FileLog.Log( "OnCreated " + InstanceCount.ToString() );
        if( Instance != null )
        {
            UnHook();
        }

        base.OnCreated( threading );
        Hook();

        Instance = this;

        NetNode2 test = new NetNode2();
        test.CalculateNode( 12345 );
    }

    public static void Hook()
    {
        FileLog.Log( "Hook" );
        try
        {
            var harmony = HarmonyInstance.Create( "com.leigon.cities_skylines.toll_road" );
            HarmonyInstance.DEBUG = true;

            MethodInfo targetmethod = AccessTools.Method( typeof( NetNode2 ), "CalculateNode" );
            HarmonyMethod prefixmethod = new HarmonyMethod( typeof( ThreadingExtension ).GetMethod( "CalculateNode_Prefix" ) );
            LogStackTrace();
            harmony.Patch( targetmethod, prefixmethod, null );
        }
        catch( System.Exception ex )
        {
            FileLog.Log( ex.ToString() );
        }
    }

    public static void UnHook()
    {
        FileLog.Log( "UnHook" );
        try
        {
            var harmony = HarmonyInstance.Create( "com.leigon.cities_skylines.toll_road" );
            HarmonyInstance.DEBUG = true;

            MethodInfo targetmethod = AccessTools.Method( typeof( NetNode2 ), "CalculateNode" );
            MethodInfo prefixmethod = AccessTools.Method( typeof( ThreadingExtension ), "CalculateNode_Prefix" );
            LogStackTrace();
            harmony.RemovePatch( targetmethod, prefixmethod );
        }
        catch( System.Exception ex )
        {
            FileLog.Log( ex.ToString() );
        }
    }

    public static void CalculateNode_Prefix( NetNode2 __instance, ushort nodeID )
    {
        FileLog.Log( "CalculateNode Prefix " + nodeID );
    }

    public override void OnReleased()
    {
        FileLog.Log( "OnReleased " + InstanceCount.ToString() );
        UnHook();

        Instance = null;

        base.OnReleased();
    }

    public static void LogStackTrace()
    {
        FileLog.Log( "--------------- Stack Trace ---------------" );
        StackTrace st = new StackTrace( true );
        for( int i = 1; i < st.FrameCount; i++ )
        {
            StackFrame sf = st.GetFrame( i );
            FileLog.Log( i.ToString() + ": " + sf.GetMethod() );
        }
        FileLog.Log( "-------------------------------------------" );
    }
}

public struct NetNode2
{
    public void CalculateNode( ushort nodeID )
    {
        FileLog.Log( "CalculateNode " + nodeID );
    }
}

}
`
Entering the game:

ThreadingExtension Created 1
OnCreated 1
Hook
--------------- Stack Trace ---------------
1: Void Hook()
2: Void OnCreated(IThreading)
3: Void OnThreadingExtensionsCreated()
4: Void GetImplementations()
5: Void .ctor(SimulationManager)
6: Void CreateRelay()
7: Void MetaDataLoaded()
8: Boolean MoveNext()
9: Void InvokeMoveNext(IEnumerator, IntPtr)
-------------------------------------------
### Patch TollRoad.NetNode2, Void CalculateNode(UInt16)
L_0000: ldarg.0
L_0001: ldarg 1
L_0007: call Void CalculateNode_Prefix(NetNode2, UInt16)
L_000c: nop
L_000d: ldstr "CalculateNode "
L_0012: ldarg.1
L_0013: box System.UInt16
L_0018: call System.String Concat(System.Object, System.Object)
L_001d: call Void Log(System.String)
L_0022: nop
L_0023: ret
DONE

System.InvalidProgramException: Invalid IL code in (wrapper dynamic-method) TollRoad.NetNode2:CalculateNode_Patch1 (object,uint16): IL_0007: call      0x00000001


  at (wrapper managed-to-native) System.RuntimeMethodHandle:GetFunctionPointer (intptr)
  at System.RuntimeMethodHandle.GetFunctionPointer () [0x00000] in <filename unknown>:0 
  at Harmony.ILCopying.Memory.GetMethodStart (System.Reflection.MethodBase method) [0x00000] in <filename unknown>:0 
  at Harmony.PatchFunctions.UpdateWrapper (System.Reflection.MethodBase original, Harmony.PatchInfo patchInfo, System.String instanceID) [0x00000] in <filename unknown>:0 
  at Harmony.PatchProcessor.Patch () [0x00000] in <filename unknown>:0 
  at Harmony.HarmonyInstance.Patch (System.Reflection.MethodBase original, Harmony.HarmonyMethod prefix, Harmony.HarmonyMethod postfix, Harmony.HarmonyMethod transpiler) [0x00000] in <filename unknown>:0 
  at TollRoad.ThreadingExtension.Hook () [0x00000] in <filename unknown>:0 
CalculateNode 12345

Exiting to main menu:

OnReleased 1
UnHook
--------------- Stack Trace ---------------
1: Void UnHook()
2: Void OnReleased()
3: Void OnThreadingExtensionsReleased()
4: Void Release()
5: Void ReleaseRelay()
6: Boolean MoveNext()
7: Void Update()
-------------------------------------------
### Patch TollRoad.NetNode2, Void CalculateNode(UInt16)
L_0000: nop
L_0001: ldstr "CalculateNode "
L_0006: ldarg.1
L_0007: box System.UInt16
L_000c: call System.String Concat(System.Object, System.Object)
L_0011: call Void Log(System.String)
L_0016: nop
L_0017: ret
DONE

Do you have Cities Skylines?

from harmony.

pardeike avatar pardeike commented on August 25, 2024

Unfortunately, I don't have Cities Skylines.
Can you try with simpler versions of the Prefix? Like this:

public static void CalculateNode_Prefix( ushort nodeID );
// or
public static void CalculateNode_Prefix(  );

I just cannot see why it fails ont the CALL at loc 0007. Maybe I have to add Boxing but I never had to do this so far.

from harmony.

Leigon avatar Leigon commented on August 25, 2024

Looks like its because NetNode2 is a struct. It does not work in game but does in the console app.
As you can see below the first 3 tests succeed.

If you need a copy of the game to test with I can get you one if that helps?

public static void CalculateNode_Prefix( );

ThreadingExtension Created 1
OnCreated 1
Hook
### Patch TollRoad.NetNode2, Void CalculateNode()
L_0000: call Void CalculateNode_Prefix()
L_0005: nop
L_0006: ldstr "CalculateNode"
L_000b: call Void Log(System.String)
L_0010: nop
L_0011: ret
DONE

CalculateNode Prefix
CalculateNode
OnReleased 1
UnHook
### Patch TollRoad.NetNode2, Void CalculateNode()
L_0000: nop
L_0001: ldstr "CalculateNode"
L_0006: call Void Log(System.String)
L_000b: nop
L_000c: ret
DONE

public static void CalculateNode_Prefix( ushort nodeID );

ThreadingExtension Created 1
OnCreated 1
Hook
### Patch TollRoad.NetNode2, Void CalculateNode(UInt16)
L_0000: ldarg 1
L_0006: call Void CalculateNode_Prefix(UInt16)
L_000b: nop
L_000c: ldstr "CalculateNode "
L_0011: ldarg.1
L_0012: box System.UInt16
L_0017: call System.String Concat(System.Object, System.Object)
L_001c: call Void Log(System.String)
L_0021: nop
L_0022: ret
DONE

CalculateNode Prefix 12345
CalculateNode 12345
OnReleased 1
UnHook
### Patch TollRoad.NetNode2, Void CalculateNode(UInt16)
L_0000: nop
L_0001: ldstr "CalculateNode "
L_0006: ldarg.1
L_0007: box System.UInt16
L_000c: call System.String Concat(System.Object, System.Object)
L_0011: call Void Log(System.String)
L_0016: nop
L_0017: ret
DONE

NetNode2 as a class
public static void CalculateNode_Prefix( NetNode2 __instance, ushort nodeID );

ThreadingExtension Created 1
OnCreated 1
Hook
### Patch TollRoad.NetNode2, Void CalculateNode(UInt16)
L_0000: ldarg.0
L_0001: ldarg 1
L_0007: call Void CalculateNode_Prefix(TollRoad.NetNode2, UInt16)
L_000c: nop
L_000d: ldstr "CalculateNode "
L_0012: ldarg.1
L_0013: box System.UInt16
L_0018: call System.String Concat(System.Object, System.Object)
L_001d: call Void Log(System.String)
L_0022: nop
L_0023: ret
DONE

CalculateNode Prefix 12345
CalculateNode 12345
OnReleased 1
UnHook
### Patch TollRoad.NetNode2, Void CalculateNode(UInt16)
L_0000: nop
L_0001: ldstr "CalculateNode "
L_0006: ldarg.1
L_0007: box System.UInt16
L_000c: call System.String Concat(System.Object, System.Object)
L_0011: call Void Log(System.String)
L_0016: nop
L_0017: ret
DONE

NetNode2 as a struct
public static void CalculateNode_Prefix( NetNode2 __instance, ushort nodeID );

ThreadingExtension Created 1
OnCreated 1
Hook
### Patch TollRoad.NetNode2, Void CalculateNode(UInt16)
L_0000: ldarg.0
L_0001: ldarg 1
L_0007: call Void CalculateNode_Prefix(NetNode2, UInt16)
L_000c: nop
L_000d: ldstr "CalculateNode "
L_0012: ldarg.1
L_0013: box System.UInt16
L_0018: call System.String Concat(System.Object, System.Object)
L_001d: call Void Log(System.String)
L_0022: nop
L_0023: ret
DONE

System.InvalidProgramException: Invalid IL code in (wrapper dynamic-method) TollRoad.NetNode2:CalculateNode_Patch1 (object,uint16): IL_0007: call      0x00000001


  at (wrapper managed-to-native) System.RuntimeMethodHandle:GetFunctionPointer (intptr)
  at System.RuntimeMethodHandle.GetFunctionPointer () [0x00000] in <filename unknown>:0 
  at Harmony.ILCopying.Memory.GetMethodStart (System.Reflection.MethodBase method) [0x00000] in <filename unknown>:0 
  at Harmony.PatchFunctions.UpdateWrapper (System.Reflection.MethodBase original, Harmony.PatchInfo patchInfo, System.String instanceID) [0x00000] in <filename unknown>:0 
  at Harmony.PatchProcessor.Patch () [0x00000] in <filename unknown>:0 
  at Harmony.HarmonyInstance.Patch (System.Reflection.MethodBase original, Harmony.HarmonyMethod prefix, Harmony.HarmonyMethod postfix, Harmony.HarmonyMethod transpiler) [0x00000] in <filename unknown>:0 
  at TollRoad.ThreadingExtension.Hook () [0x00000] in <filename unknown>:0 
CalculateNode 12345
OnReleased 1
UnHook
### Patch TollRoad.NetNode2, Void CalculateNode(UInt16)
L_0000: nop
L_0001: ldstr "CalculateNode "
L_0006: ldarg.1
L_0007: box System.UInt16
L_000c: call System.String Concat(System.Object, System.Object)
L_0011: call Void Log(System.String)
L_0016: nop
L_0017: ret
DONE

from harmony.

VictorPhilipp avatar VictorPhilipp commented on August 25, 2024

I experience the same problem. Cities: Skylines utilizes mono to decompile and recompile mod DLLs on-the-fly to ensure compatibility with different operating systems. That could make the difference here.

D:\Games\Steam\steamapps\common\Cities_Skylines\Mono\bin>mono -V
Mono JIT compiler version 2.0 (Visual Studio built mono)
Copyright (C) 2002-2010 Novell, Inc and Contributors. www.mono-project.com
        TLS:           normal
        GC:            Included Boehm (with typed GC)
        SIGSEGV:       normal
        Notification:  Thread + polling
        Architecture:  x86
        Disabled:      none

from harmony.

pardeike avatar pardeike commented on August 25, 2024

This could be a variation on #77

from harmony.

pardeike avatar pardeike commented on August 25, 2024

I just fixed #77 - please verify if this is still an issue. I will close this for now.

from harmony.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.