private static float HandleMovableBridge(ref Vehicle vehicleData, ushort buildingID, ref Building buildingData, bool passing, bool near, float minY, float maxY, float maxSpeed, float vehicleTopY)
        {
            BuildingInfo buildingInfo = buildingData.Info;

            if (!(buildingInfo.m_buildingAI is MovableBridgeAI))
            {
                return(float.MaxValue);
            }

            MovableBridgeAI movableBridgeAi = (MovableBridgeAI)buildingInfo.m_buildingAI;
            float           bridgeClearance = buildingData.m_position.y + movableBridgeAi.m_BridgeClearance;

            if (bridgeClearance > vehicleTopY)
            {
                return(float.MaxValue);
            }

            if (!passing && !near)
            {
                return(float.MaxValue);
            }

            ushort bridgeState = MovableBridgeAI.GetBridgeState(ref buildingData);

            buildingData.m_customBuffer1 |= MovableBridgeAI.FLAG_SHIP_NEAR_BRIDGE;
            if (passing)
            {
                buildingData.m_customBuffer1 |= MovableBridgeAI.FLAG_SHIP_PASSING_BRIDGE_ANY;
            }
            if (bridgeState == MovableBridgeAI.STATE_BRIDGE_OPEN_LEFT ||
                bridgeState == MovableBridgeAI.STATE_BRIDGE_OPEN_RIGHT ||
                bridgeState == MovableBridgeAI.STATE_BRIDGE_OPEN_BOTH ||
                (bridgeState == MovableBridgeAI.STATE_BRIDGE_WAITING_LEFT && passing) ||
                (bridgeState == MovableBridgeAI.STATE_BRIDGE_WAITING_RIGHT && passing) ||
                (bridgeState == MovableBridgeAI.STATE_BRIDGE_WAITING_BOTH && passing))
            {
                return(float.MaxValue);
            }
            if (!passing)
            {
                return(kPassingSpeed);
            }

            vehicleData.m_blockCounter = 0;

            return(0f);
        }
        public static void Prefix(BuildingInfo __instance)
        {
            if (!Mod.IsInGame && !Mod.IsInAssetEditor)
            {
                return;
            }

            if (__instance.editorCategory == "MovableBridge")
            {
                BuildingAI oldAI = __instance.gameObject.GetComponent <BuildingAI>();
                if (oldAI is MovableBridgeAI)
                {
                    UnityEngine.Debug.Log($"MovableBridgeAI already set for ${__instance.name}");
                    return;
                }

                UnityEngine.Debug.Log($"Adding MovableBridgeAI to ${__instance.name}");

                MovableBridgeAI newAI = __instance.gameObject.AddComponent <MovableBridgeAI>();
                newAI.m_electricityConsumption = 0;
                newAI.m_waterConsumption       = 0;
                newAI.m_sewageAccumulation     = 0;
                newAI.m_garbageAccumulation    = 0;
                newAI.CopyFrom(oldAI);

                UnityEngine.Object.DestroyImmediate(oldAI);

                // disable building LOD
                __instance.m_lodObject = null;

                foreach (BuildingInfo.PathInfo pathInfo in __instance.m_paths)
                {
                    if (pathInfo.m_netInfo.editorCategory == "MovableBridge_Movable" && pathInfo.m_nodes.Length > 1)
                    {
                        if (pathInfo.m_trafficLights == null)
                        {
                            pathInfo.m_trafficLights = new BuildingInfo.TrafficLights[pathInfo.m_nodes.Length];
                        }
                        pathInfo.m_trafficLights[0] = BuildingInfo.TrafficLights.ForceOn;
                        pathInfo.m_trafficLights[pathInfo.m_trafficLights.Length - 1] = BuildingInfo.TrafficLights.ForceOn;
                    }
                }
            }
        }
        private static float HandleMovableBridge(ref Vehicle vehicleData, ushort buildingID, ref Building buildingData, bool passing, bool near1, bool near2, float minY, float maxY, float maxSpeed, float vehicleTopY, Vector2 forwardDir)
        {
            BuildingInfo buildingInfo = buildingData.Info;

            if (!(buildingInfo.m_buildingAI is MovableBridgeAI))
            {
                return(float.MaxValue);
            }

            MovableBridgeAI movableBridgeAi = (MovableBridgeAI)buildingInfo.m_buildingAI;
            float           bridgeClearance = buildingData.m_position.y + movableBridgeAi.m_BridgeClearance;

            if (bridgeClearance > vehicleTopY)
            {
                return(float.MaxValue);
            }

            if (!passing && !near1 && !near2)
            {
                return(float.MaxValue);
            }

            Vector2 buildingForwardDir = new Vector2(Mathf.Sin(buildingData.m_angle), Mathf.Cos(buildingData.m_angle));
            var     dot  = Vector2.Dot(forwardDir, buildingForwardDir);
            bool    left = dot > 0;

            ushort bridgeState = MovableBridgeAI.GetBridgeState(ref buildingData);

            buildingData.m_customBuffer1 |= MovableBridgeAI.FLAG_SHIP_NEAR_BRIDGE;
            if (passing || near1)
            {
                buildingData.m_customBuffer1 |= (left ? MovableBridgeAI.FLAG_SHIP_PASSING_BRIDGE_LEFT : MovableBridgeAI.FLAG_SHIP_PASSING_BRIDGE_RIGHT);
            }

            if (passing)
            {
                return(float.MaxValue);
            }

            if (bridgeState == MovableBridgeAI.STATE_BRIDGE_OPEN_LEFT ||
                (bridgeState == MovableBridgeAI.STATE_BRIDGE_WAITING_LEFT && near1))
            {
                if (left)
                {
                    return(float.MaxValue);
                }
            }
            else if (bridgeState == MovableBridgeAI.STATE_BRIDGE_OPEN_RIGHT ||
                     (bridgeState == MovableBridgeAI.STATE_BRIDGE_WAITING_RIGHT && near1))
            {
                if (!left)
                {
                    return(float.MaxValue);
                }
            }
            else if (bridgeState == MovableBridgeAI.STATE_BRIDGE_OPEN_BOTH ||
                     (bridgeState == MovableBridgeAI.STATE_BRIDGE_WAITING_BOTH && near1))
            {
                return(float.MaxValue);
            }

            if (!near1)
            {
                return(kPassingSpeed);
            }

            vehicleData.m_blockCounter = 0;

            return(0f);
        }