private void RenderPoleMesh(ushort vehicleID, ref Vehicle vehicleData, Vector3 position, Quaternion rotation, Vector3 swayPosition, bool underground, bool overground, VehicleManager vehicleManager, VehicleInfo.MeshInfo meshInfo, MaterialPropertyBlock materialBlock) { VehicleInfoBase subInfo = meshInfo.m_subInfo; bool flag = Singleton <ToolManager> .instance.m_properties.m_mode == ItemClass.Availability.AssetEditor; if ((flag && !BuildingDecoration.IsSubMeshRendered(subInfo)) || (meshInfo.m_vehicleFlagsRequired & (Vehicle.Flags.TakingOff | Vehicle.Flags.Landing)) == 0 || !(subInfo != null)) { return; } Matrix4x4 matrix = CalculatePoleMatrix(vehicleID, ref vehicleData, position, rotation, swayPosition, meshInfo, subInfo, flag); vehicleManager.m_drawCallData.m_defaultCalls++; if (underground) { if (subInfo.m_undergroundMaterial == null && subInfo.m_material != null) { VehicleProperties properties = vehicleManager.m_properties; if (properties != null) { subInfo.m_undergroundMaterial = new Material(properties.m_undergroundShader); subInfo.m_undergroundMaterial.CopyPropertiesFromMaterial(subInfo.m_material); } } Graphics.DrawMesh(subInfo.m_mesh, matrix, subInfo.m_undergroundMaterial, vehicleManager.m_undergroundLayer, null, 0, materialBlock); } if (overground) { Graphics.DrawMesh(subInfo.m_mesh, matrix, subInfo.m_material, m_info.m_prefabDataLayer, null, 0, materialBlock); } }
public static void SaveDecorations(BuildingInfo target) { Building data = new Building(); data.m_position = new Vector3(0.0f, 60f, 0.0f); data.Width = target.m_cellWidth; data.Length = target.m_cellLength; //begin mod if (OptionsWrapper <Options> .Options.PrecisePathsPostions) { SavePrecisePaths(target); } else { BuildingDecoration.SavePaths(target, (ushort)0, ref data); } //end mod BuildingDecoration.SaveProps(target, (ushort)0, ref data); }
public static void LoadDecorations(BuildingInfo source) { UnityEngine.Debug.Log($"Loading decorations for {source.name}"); Building data = new Building(); data.m_position = new Vector3(0.0f, 60f, 0.0f); data.Width = source.m_cellWidth; data.Length = source.m_cellLength; BuildingDecoration.LoadPaths(source, (ushort)0, ref data, 0.0f); BuildingDecoration.LoadProps(source, (ushort)0, ref data); //begin mod try { LoadSpecialPoints((source), (ushort)0, ref data); } catch (Exception e) { UnityEngine.Debug.LogException(e); } //end mod }
// Run before the original method. Skip the original one if the vehicle is a cable car public static bool Prefix(RenderManager.CameraInfo cameraInfo, VehicleInfo info, Vector3 position, ref Quaternion rotation, Vector3 swayPosition, Vector4 lightState, Vector4 tyrePosition, Vector3 velocity, float acceleration, Color color, Vehicle.Flags flags, int variationMask, InstanceID id, bool underground, bool overground) { // if the vehicle is not a cable car, skip and use the original method if ((int)info.m_vehicleType != 0x1000) { return(true); } // limit rotation along the x and z axes for all meshes except submesh1 // submesh1 would rotate in the original way(along with the cable) Quaternion originalRotation = rotation; rotation.x = 0.0f; rotation.z = 0.0f; // change how cable cars sway // so they don't move up and down on the cables as if they're ships moving in sea waves swayPosition.y = 0.0f; if ((cameraInfo.m_layerMask & (1 << info.m_prefabDataLayer)) == 0) { // return false to skip the original method return(false); } Vector3 scale = Vector3.one; if ((flags & Vehicle.Flags.Inverted) != 0) { scale = new Vector3(-1f, 1f, -1f); Vector4 vector = lightState; lightState.x = vector.y; lightState.y = vector.x; lightState.z = vector.w; lightState.w = vector.z; } info.m_vehicleAI.RenderExtraStuff(id.Vehicle, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[id.Vehicle], cameraInfo, id, position, rotation, tyrePosition, lightState, scale, swayPosition, underground, overground); if (cameraInfo.CheckRenderDistance(position, info.m_lodRenderDistance)) { VehicleManager instance = Singleton <VehicleManager> .instance; Matrix4x4 bodyMatrix = info.m_vehicleAI.CalculateBodyMatrix(flags, ref position, ref rotation, ref scale, ref swayPosition); Matrix4x4 originalBodyMatrix = info.m_vehicleAI.CalculateBodyMatrix(flags, ref position, ref originalRotation, ref scale, ref swayPosition); Matrix4x4 value = info.m_vehicleAI.CalculateTyreMatrix(flags, ref position, ref rotation, ref scale, ref bodyMatrix); if (Singleton <InfoManager> .instance.CurrentMode == InfoManager.InfoMode.None) { RenderGroup.MeshData effectMeshData = info.m_vehicleAI.GetEffectMeshData(); EffectInfo.SpawnArea area = new EffectInfo.SpawnArea(bodyMatrix, effectMeshData, info.m_generatedInfo.m_tyres, info.m_lightPositions); if (info.m_effects != null) { for (int i = 0; i < info.m_effects.Length; i++) { VehicleInfo.Effect effect = info.m_effects[i]; if (((effect.m_vehicleFlagsRequired | effect.m_vehicleFlagsForbidden) & flags) == effect.m_vehicleFlagsRequired && effect.m_parkedFlagsRequired == VehicleParked.Flags.None) { effect.m_effect.RenderEffect(id, area, velocity, acceleration, 1f, -1f, Singleton <SimulationManager> .instance.m_simulationTimeDelta, cameraInfo); } } } } if ((flags & Vehicle.Flags.Inverted) != 0) { tyrePosition.x = 0f - tyrePosition.x; tyrePosition.y = 0f - tyrePosition.y; } MaterialPropertyBlock materialBlock = instance.m_materialBlock; materialBlock.Clear(); materialBlock.SetMatrix(instance.ID_TyreMatrix, value); materialBlock.SetVector(instance.ID_TyrePosition, tyrePosition); materialBlock.SetVector(instance.ID_LightState, lightState); bool flag = Singleton <ToolManager> .instance.m_properties.m_mode == ItemClass.Availability.AssetEditor; if (!flag) { materialBlock.SetColor(instance.ID_Color, color); } bool flag2 = true; if (flag) { flag2 = BuildingDecoration.IsMainMeshRendered(); } if (info.m_subMeshes != null) { for (int j = 0; j < info.m_subMeshes.Length; j++) { VehicleInfo.MeshInfo meshInfo = info.m_subMeshes[j]; VehicleInfoBase subInfo = meshInfo.m_subInfo; if ((!flag && ((meshInfo.m_vehicleFlagsRequired | meshInfo.m_vehicleFlagsForbidden) & flags) == meshInfo.m_vehicleFlagsRequired && (meshInfo.m_variationMask & variationMask) == 0 && meshInfo.m_parkedFlagsRequired == VehicleParked.Flags.None) || (flag && BuildingDecoration.IsSubMeshRendered(subInfo))) { if (!(subInfo != null)) { continue; } instance.m_drawCallData.m_defaultCalls++; if (underground) { if (subInfo.m_undergroundMaterial == null && subInfo.m_material != null) { VehicleProperties properties = instance.m_properties; if (properties != null) { subInfo.m_undergroundMaterial = new Material(properties.m_undergroundShader); subInfo.m_undergroundMaterial.CopyPropertiesFromMaterial(subInfo.m_material); } } subInfo.m_undergroundMaterial.SetVectorArray(instance.ID_TyreLocation, subInfo.m_generatedInfo.m_tyres); if (j == 1) { Graphics.DrawMesh(subInfo.m_mesh, originalBodyMatrix, subInfo.m_undergroundMaterial, instance.m_undergroundLayer, null, 0, materialBlock); } else { Graphics.DrawMesh(subInfo.m_mesh, bodyMatrix, subInfo.m_undergroundMaterial, instance.m_undergroundLayer, null, 0, materialBlock); } } if (overground) { subInfo.m_material.SetVectorArray(instance.ID_TyreLocation, subInfo.m_generatedInfo.m_tyres); if (j == 1) { Graphics.DrawMesh(subInfo.m_mesh, originalBodyMatrix, subInfo.m_material, info.m_prefabDataLayer, null, 0, materialBlock); } else { Graphics.DrawMesh(subInfo.m_mesh, bodyMatrix, subInfo.m_material, info.m_prefabDataLayer, null, 0, materialBlock); } } } else if (subInfo == null) { flag2 = false; } } } if (!flag2) { // return false to skip the original method return(false); } instance.m_drawCallData.m_defaultCalls++; if (underground) { if (info.m_undergroundMaterial == null && info.m_material != null) { VehicleProperties properties2 = instance.m_properties; if (properties2 != null) { info.m_undergroundMaterial = new Material(properties2.m_undergroundShader); info.m_undergroundMaterial.CopyPropertiesFromMaterial(info.m_material); } } info.m_undergroundMaterial.SetVectorArray(instance.ID_TyreLocation, info.m_generatedInfo.m_tyres); Graphics.DrawMesh(info.m_mesh, bodyMatrix, info.m_undergroundMaterial, instance.m_undergroundLayer, null, 0, materialBlock); } if (overground) { info.m_material.SetVectorArray(instance.ID_TyreLocation, info.m_generatedInfo.m_tyres); Graphics.DrawMesh(info.m_mesh, bodyMatrix, info.m_material, info.m_prefabDataLayer, null, 0, materialBlock); } // return false to skip the original method return(false); } Matrix4x4 bodyMatrix2 = info.m_vehicleAI.CalculateBodyMatrix(flags, ref position, ref rotation, ref scale, ref swayPosition); Matrix4x4 originalBodyMatrix2 = info.m_vehicleAI.CalculateBodyMatrix(flags, ref position, ref originalRotation, ref scale, ref swayPosition); if (Singleton <ToolManager> .instance.m_properties.m_mode == ItemClass.Availability.AssetEditor) { Matrix4x4 value2 = info.m_vehicleAI.CalculateTyreMatrix(flags, ref position, ref rotation, ref scale, ref bodyMatrix2); VehicleManager instance2 = Singleton <VehicleManager> .instance; MaterialPropertyBlock materialBlock2 = instance2.m_materialBlock; materialBlock2.Clear(); materialBlock2.SetMatrix(instance2.ID_TyreMatrix, value2); materialBlock2.SetVector(instance2.ID_TyrePosition, tyrePosition); materialBlock2.SetVector(instance2.ID_LightState, lightState); Mesh mesh = null; Material material = null; if (info.m_lodObject != null) { MeshFilter component = info.m_lodObject.GetComponent <MeshFilter>(); if (component != null) { mesh = component.sharedMesh; } Renderer component2 = info.m_lodObject.GetComponent <Renderer>(); if (component2 != null) { material = component2.sharedMaterial; } } if (mesh != null && material != null) { materialBlock2.SetVectorArray(instance2.ID_TyreLocation, info.m_generatedInfo.m_tyres); Graphics.DrawMesh(mesh, bodyMatrix2, material, info.m_prefabDataLayer, null, 0, materialBlock2); } } else if (Singleton <InfoManager> .instance.CurrentMode == InfoManager.InfoMode.None) { RenderGroup.MeshData effectMeshData2 = info.m_vehicleAI.GetEffectMeshData(); EffectInfo.SpawnArea area2 = new EffectInfo.SpawnArea(bodyMatrix2, effectMeshData2, info.m_generatedInfo.m_tyres, info.m_lightPositions); if (info.m_effects != null) { for (int k = 0; k < info.m_effects.Length; k++) { VehicleInfo.Effect effect2 = info.m_effects[k]; if (((effect2.m_vehicleFlagsRequired | effect2.m_vehicleFlagsForbidden) & flags) == effect2.m_vehicleFlagsRequired && effect2.m_parkedFlagsRequired == VehicleParked.Flags.None) { effect2.m_effect.RenderEffect(id, area2, velocity, acceleration, 1f, -1f, Singleton <SimulationManager> .instance.m_simulationTimeDelta, cameraInfo); } } } } bool flag3 = true; if (info.m_subMeshes != null) { for (int l = 0; l < info.m_subMeshes.Length; l++) { VehicleInfo.MeshInfo meshInfo2 = info.m_subMeshes[l]; VehicleInfoBase subInfo2 = meshInfo2.m_subInfo; if (((meshInfo2.m_vehicleFlagsRequired | meshInfo2.m_vehicleFlagsForbidden) & flags) == meshInfo2.m_vehicleFlagsRequired && (meshInfo2.m_variationMask & variationMask) == 0 && meshInfo2.m_parkedFlagsRequired == VehicleParked.Flags.None) { if (!(subInfo2 != null)) { continue; } if (underground) { if (l == 1) { subInfo2.m_undergroundLodTransforms[subInfo2.m_undergroundLodCount] = originalBodyMatrix2; } else { subInfo2.m_undergroundLodTransforms[subInfo2.m_undergroundLodCount] = bodyMatrix2; } subInfo2.m_undergroundLodLightStates[subInfo2.m_undergroundLodCount] = lightState; subInfo2.m_undergroundLodColors[subInfo2.m_undergroundLodCount] = color.linear; subInfo2.m_undergroundLodMin = Vector3.Min(subInfo2.m_undergroundLodMin, position); subInfo2.m_undergroundLodMax = Vector3.Max(subInfo2.m_undergroundLodMax, position); if (++subInfo2.m_undergroundLodCount == subInfo2.m_undergroundLodTransforms.Length) { Vehicle.RenderUndergroundLod(cameraInfo, subInfo2); } } if (overground) { if (l == 1) { subInfo2.m_lodTransforms[subInfo2.m_lodCount] = originalBodyMatrix2; } else { subInfo2.m_lodTransforms[subInfo2.m_lodCount] = bodyMatrix2; } subInfo2.m_lodLightStates[subInfo2.m_lodCount] = lightState; subInfo2.m_lodColors[subInfo2.m_lodCount] = color.linear; subInfo2.m_lodMin = Vector3.Min(subInfo2.m_lodMin, position); subInfo2.m_lodMax = Vector3.Max(subInfo2.m_lodMax, position); if (++subInfo2.m_lodCount == subInfo2.m_lodTransforms.Length) { Vehicle.RenderLod(cameraInfo, subInfo2); } } } else if (subInfo2 == null) { flag3 = false; } } } if (!flag3) { return(false); } if (underground) { info.m_undergroundLodTransforms[info.m_undergroundLodCount] = bodyMatrix2; info.m_undergroundLodLightStates[info.m_undergroundLodCount] = lightState; info.m_undergroundLodColors[info.m_undergroundLodCount] = color.linear; info.m_undergroundLodMin = Vector3.Min(info.m_undergroundLodMin, position); info.m_undergroundLodMax = Vector3.Max(info.m_undergroundLodMax, position); if (++info.m_undergroundLodCount == info.m_undergroundLodTransforms.Length) { Vehicle.RenderUndergroundLod(cameraInfo, info); } } if (overground) { info.m_lodTransforms[info.m_lodCount] = bodyMatrix2; info.m_lodLightStates[info.m_lodCount] = lightState; info.m_lodColors[info.m_lodCount] = color.linear; info.m_lodMin = Vector3.Min(info.m_lodMin, position); info.m_lodMax = Vector3.Max(info.m_lodMax, position); if (++info.m_lodCount == info.m_lodTransforms.Length) { Vehicle.RenderLod(cameraInfo, info); } } // return false to skip the original method return(false); }
/* Detoured method. We save a list of all the segment ids (and ids of their lanes and nodes as well) to m_pendingSegments * We will use it a few moments later when the OnAssetSaved method is called * See line 408 */ public static void SavePaths(BuildingInfo info, ushort buildingID, ref Building data) { Debug.Log("SavePaths TMPE detour"); // List <IdentificationTool.AssetSegment> SavedSegments = new List <IdentificationTool.AssetSegment>(); // ns end FastList <BuildingInfo.PathInfo> fastList = new FastList <BuildingInfo.PathInfo>(); List <ushort> list = new List <ushort>(); List <ushort> list2 = new List <ushort>(); for (ushort num = 1; num < 49152; num += 1) { if (Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)num].m_flags != Building.Flags.None) { list.AddRange(BuildingDecoration.GetBuildingSegments(ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)num])); list2.Add(num); } } NetManager instance = Singleton <NetManager> .instance; for (int i = 0; i < 36864; i++) { if ((instance.m_segments.m_buffer[i].m_flags & (NetSegment.Flags.Created | NetSegment.Flags.Deleted)) == NetSegment.Flags.Created) { if (!list.Contains((ushort)i)) { NetInfo info2 = instance.m_segments.m_buffer[i].Info; ushort startNode = instance.m_segments.m_buffer[i].m_startNode; ushort endNode = instance.m_segments.m_buffer[i].m_endNode; Vector3 position = instance.m_nodes.m_buffer[(int)startNode].m_position; Vector3 position2 = instance.m_nodes.m_buffer[(int)endNode].m_position; Vector3 startDirection = instance.m_segments.m_buffer[i].m_startDirection; Vector3 endDirection = instance.m_segments.m_buffer[i].m_endDirection; Vector3 a; float num2; float num3; if (NetSegment.IsStraight(position, startDirection, position2, endDirection)) { a = (position + position2) * 0.5f; } else if (Line2.Intersect(VectorUtils.XZ(position), VectorUtils.XZ(position + startDirection), VectorUtils.XZ(position2), VectorUtils.XZ(position2 + endDirection), out num2, out num3)) { float minNodeDistance = info2.GetMinNodeDistance(); num2 = Mathf.Max(minNodeDistance, num2); num3 = Mathf.Max(minNodeDistance, num3); a = (position + startDirection * num2 + position2 + endDirection * num3) * 0.5f; } else { a = (position + position2) * 0.5f; } BuildingInfo.PathInfo pathInfo = new BuildingInfo.PathInfo(); pathInfo.m_netInfo = info2; pathInfo.m_finalNetInfo = info2; pathInfo.m_nodes = new Vector3[2]; pathInfo.m_nodes[0] = position - data.m_position; pathInfo.m_nodes[0].z = -pathInfo.m_nodes[0].z; pathInfo.m_nodes[1] = position2 - data.m_position; pathInfo.m_nodes[1].z = -pathInfo.m_nodes[1].z; pathInfo.m_curveTargets = new Vector3[1]; pathInfo.m_curveTargets[0] = a - data.m_position; pathInfo.m_curveTargets[0].z = -pathInfo.m_curveTargets[0].z; pathInfo.m_forbidLaneConnection = new bool[2]; pathInfo.m_forbidLaneConnection[0] = ((instance.m_nodes.m_buffer[(int)startNode].m_flags & NetNode.Flags.ForbidLaneConnection) != NetNode.Flags.None); pathInfo.m_forbidLaneConnection[1] = ((instance.m_nodes.m_buffer[(int)endNode].m_flags & NetNode.Flags.ForbidLaneConnection) != NetNode.Flags.None); pathInfo.m_trafficLights = new BuildingInfo.TrafficLights[2]; pathInfo.m_trafficLights[0] = /*BuildingDecoration.*/ FlagsToTrafficLights(instance.m_nodes.m_buffer[(int)startNode].m_flags); pathInfo.m_trafficLights[1] = /*BuildingDecoration.*/ FlagsToTrafficLights(instance.m_nodes.m_buffer[(int)endNode].m_flags); pathInfo.m_yieldSigns = new bool[2]; pathInfo.m_yieldSigns[0] = ((instance.m_segments.m_buffer[i].m_flags & NetSegment.Flags.YieldStart) != NetSegment.Flags.None); pathInfo.m_yieldSigns[1] = ((instance.m_segments.m_buffer[i].m_flags & NetSegment.Flags.YieldEnd) != NetSegment.Flags.None); if (info.m_placementMode == BuildingInfo.PlacementMode.Roadside && (position.z > (float)info.m_cellLength * 4f + 8f || position2.z > (float)info.m_cellLength * 4f + 8f)) { pathInfo.m_maxSnapDistance = 7.5f; } else { pathInfo.m_maxSnapDistance = 0.1f; } pathInfo.m_invertSegments = ((instance.m_segments.m_buffer[i].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None); fastList.Add(pathInfo); SavedSegments.Add(new IdentificationTool.AssetSegment((ushort)i)); // ns } } } for (int j = 0; j < 32768; j++) { if ((instance.m_nodes.m_buffer[j].m_flags & (NetNode.Flags.Created | NetNode.Flags.Deleted)) == NetNode.Flags.Created && instance.m_nodes.m_buffer[j].CountSegments() == 0) { bool flag = false; foreach (ushort num4 in list2) { if (Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)num4].ContainsNode((ushort)j)) { flag = true; break; } } if (!flag) { NetInfo info3 = instance.m_nodes.m_buffer[j].Info; Vector3 position3 = instance.m_nodes.m_buffer[j].m_position; BuildingInfo.PathInfo pathInfo2 = new BuildingInfo.PathInfo(); pathInfo2.m_netInfo = info3; pathInfo2.m_finalNetInfo = info3; pathInfo2.m_nodes = new Vector3[1]; pathInfo2.m_nodes[0] = position3 - data.m_position; pathInfo2.m_nodes[0].z = -pathInfo2.m_nodes[0].z; pathInfo2.m_curveTargets = new Vector3[0]; pathInfo2.m_forbidLaneConnection = new bool[1]; pathInfo2.m_forbidLaneConnection[0] = ((instance.m_nodes.m_buffer[j].m_flags & NetNode.Flags.ForbidLaneConnection) != NetNode.Flags.None); pathInfo2.m_trafficLights = new BuildingInfo.TrafficLights[1]; pathInfo2.m_trafficLights[0] = /*BuildingDecoration.*/ FlagsToTrafficLights(instance.m_nodes.m_buffer[j].m_flags); pathInfo2.m_yieldSigns = new bool[0]; pathInfo2.m_maxSnapDistance = 0.1f; pathInfo2.m_invertSegments = false; fastList.Add(pathInfo2); } } } info.m_paths = fastList.ToArray(); // ns: if (SavedSegments.Count > 0) { m_pendingSegments = SavedSegments; } }