/* Called when an asset is saved */ public void OnAssetSaved(string name, object asset, out Dictionary <string, byte[]> userData) { Debug.Log("TMPE: OnAssetSaved"); userData = null; if (!LoadingExtension.IsInAssetEditor) { return; } BuildingInfo info = asset as BuildingInfo; if (info == null) { return; } bool success = true; TmpeAssetData data = new TmpeAssetData(); data.Segments = BuildingDecorationPatch.m_pendingSegments; Configuration config = SerializableDataExtension.CreateConfiguration(ref success); userData = new Dictionary <string, byte[]>(); // ??? !!! SerializableDataExtension.OnBeforeGameSaved(ref success); data.TmpeConfiguration = SerializableDataExtension.Serialize(config, ref success); SerializableDataExtension.OnAfterGameSaved(ref success); if (!success) { return; } if (BuildingDecorationPatch.m_pendingSegments?.Count > 0) { userData.Add(SerializableDataExtension.DataId + segmentsString, SerializableDataExtension.Serialize <List <IdentificationTool.AssetSegment> >(data.Segments, ref success)); userData.Add(SerializableDataExtension.DataId + dataString, data.TmpeConfiguration); AssetDataManager.Instance.AssetsWithData[IdentificationTool.GetNameWithoutPrefix(info.name)] = data; } }
public static List <IdentificationTool.AssetSegment> m_pendingSegments; // Segments pending to be saved public static void ProcessNewPaths(List <ushort> segments, BuildingInfo info) { try { #if DEBUG Debug.Log("Loading TMPE settings..."); #endif TmpeAssetData data = AssetDataManager.Instance.AssetsWithData[IdentificationTool.GetNameWithoutPrefix(info.name)]; Debug.Log("Hoooray! Tmpe settings loaded"); Configuration config = SerializableDataExtension.DeserializeData(data.TmpeConfiguration, out bool error); if (error) { throw new Exception("Tmpe: Failed to deserialize data"); } /* We identify the old ids with the new ids */ IdentificationTool.CreateDictionaries(segments, data.Segments, out Dictionary <ushort, ushort> segmentPairs, out Dictionary <ushort, ushort> nodePairs, out Dictionary <uint, uint> lanePairs); IdentificationTool.TranslateGameConfiguration(config, segmentPairs, nodePairs, lanePairs); /*SerializableDataExtension.LoadDataState(config, out bool error2); * if (error2) * throw new Exception("Tmpe: error when applying loaded data");*/ /* Apply settings after some time elapses (hack) */ ProvisionalDataLoader.StartTimer(config); } catch (Exception ex) { #if DEBUG Debug.Log(ex); #endif } }
/* Called when the savegame/asset is loading. Does not work when Loading Screen mod is enabled due to a bug */ public void OnAssetLoaded(string name, object asset, Dictionary <string, byte[]> userData) { BuildingInfo info = asset as BuildingInfo; if (info != null) { try { TmpeAssetData data = new TmpeAssetData(); data.TmpeConfiguration = userData[SerializableDataExtension.DataId + dataString]; //data.TmpeConfiguration = SerializableDataExtension.DeserializeData(userData[SerializableDataExtension.DataId + dataString], out bool error); data.Segments = Deserialize <List <IdentificationTool.AssetSegment> >(userData[SerializableDataExtension.DataId + segmentsString]); AssetDataManager.Instance.AssetsWithData[IdentificationTool.GetNameWithoutPrefix(info.name)] = data; #if DEBUG Debug.Log("Successfully deserialized TMPE asset data (" + info.name + ")"); #endif } catch (Exception e) { Debug.Log(e); } } }
/* STOCK CODE START */ /* Called when building (intersection) loads its segments. Detoured method. Added code is marked 'ns' * We obrain a list with all the segments and pass them to the ProcessNewPaths method. We create our own list for that purpose instead of * using instance.m_tempSegmentBuffer because it almost seems that the game can create multiple segments per one saved path in the file which * makes absolutely no sense at all but would lead to our list being shifted compared to the (third) one in which we had saved the ids of the * old segments. Whatever, you don't really have to understand this, I studied it a lot when creating my previous mods and it's the part I * understand the most compared to the rest */ public static void LoadPaths(BuildingInfo info, ushort buildingID, ref Building data, float elevation) { #if DEBUG Debug.Log("LoadPaths TMPE detour"); #endif // ns Dictionary <string, TmpeAssetData> dict = AssetDataManager.Instance.AssetsWithData; bool isAssetWithTmpeSettings = dict.ContainsKey(IdentificationTool.GetNameWithoutPrefix(info.name)); List <ushort> CreatedSegments = null; if (isAssetWithTmpeSettings) { CreatedSegments = new List <ushort>(); } // ns end if (info.m_paths != null) { NetManager instance = Singleton <NetManager> .instance; instance.m_tempNodeBuffer.Clear(); instance.m_tempSegmentBuffer.Clear(); for (int i = 0; i < info.m_paths.Length; i++) { // ns if (isAssetWithTmpeSettings) { CreatedSegments.Add(0); } // ns end BuildingInfo.PathInfo pathInfo = info.m_paths[i]; if (pathInfo.m_finalNetInfo != null && pathInfo.m_nodes != null && pathInfo.m_nodes.Length != 0) { Vector3 vector = data.CalculatePosition(pathInfo.m_nodes[0]); bool flag = /*BuildingDecoration.*/ RequireFixedHeight(info, pathInfo.m_finalNetInfo, pathInfo.m_nodes[0]); if (!flag) { vector.y = NetSegment.SampleTerrainHeight(pathInfo.m_finalNetInfo, vector, false, pathInfo.m_nodes[0].y + elevation); } Ray ray = new Ray(vector + new Vector3(0f, 8f, 0f), Vector3.down); NetTool.ControlPoint controlPoint; if (!/*BuildingDecoration.*/ FindConnectNode(instance.m_tempNodeBuffer, vector, pathInfo.m_finalNetInfo, out controlPoint)) { if (NetTool.MakeControlPoint(ray, 16f, pathInfo.m_finalNetInfo, true, NetNode.Flags.Untouchable, NetSegment.Flags.Untouchable, Building.Flags.All, pathInfo.m_nodes[0].y + elevation - pathInfo.m_finalNetInfo.m_buildHeight, true, out controlPoint)) { Vector3 vector2 = controlPoint.m_position - vector; if (!flag) { vector2.y = 0f; } float sqrMagnitude = vector2.sqrMagnitude; if (sqrMagnitude > pathInfo.m_maxSnapDistance * pathInfo.m_maxSnapDistance) { controlPoint.m_position = vector; controlPoint.m_elevation = 0f; controlPoint.m_node = 0; controlPoint.m_segment = 0; } else { controlPoint.m_position.y = vector.y; } } else { controlPoint.m_position = vector; } } ushort num; ushort num2; int num3; int num4; if (controlPoint.m_node != 0) { instance.m_tempNodeBuffer.Add(controlPoint.m_node); } else if (NetTool.CreateNode(pathInfo.m_finalNetInfo, controlPoint, controlPoint, controlPoint, NetTool.m_nodePositionsSimulation, 0, false, false, false, false, pathInfo.m_invertSegments, false, 0, out num, out num2, out num3, out num4) == ToolBase.ToolErrors.None) { instance.m_tempNodeBuffer.Add(num); controlPoint.m_node = num; if (pathInfo.m_forbidLaneConnection != null && pathInfo.m_forbidLaneConnection.Length > 0 && pathInfo.m_forbidLaneConnection[0]) { NetNode[] buffer = instance.m_nodes.m_buffer; ushort num5 = num; buffer[(int)num5].m_flags = (buffer[(int)num5].m_flags | NetNode.Flags.ForbidLaneConnection); } if (pathInfo.m_trafficLights != null && pathInfo.m_trafficLights.Length > 0) { /*BuildingDecoration.*/ TrafficLightsToFlags(pathInfo.m_trafficLights[0], ref instance.m_nodes.m_buffer[(int)num].m_flags); } } for (int j = 1; j < pathInfo.m_nodes.Length; j++) { vector = data.CalculatePosition(pathInfo.m_nodes[j]); bool flag2 = /*BuildingDecoration.*/ RequireFixedHeight(info, pathInfo.m_finalNetInfo, pathInfo.m_nodes[j]); if (!flag2) { vector.y = NetSegment.SampleTerrainHeight(pathInfo.m_finalNetInfo, vector, false, pathInfo.m_nodes[j].y + elevation); } ray = new Ray(vector + new Vector3(0f, 8f, 0f), Vector3.down); NetTool.ControlPoint controlPoint2; if (!/*BuildingDecoration.*/ FindConnectNode(instance.m_tempNodeBuffer, vector, pathInfo.m_finalNetInfo, out controlPoint2)) { if (NetTool.MakeControlPoint(ray, 16f, pathInfo.m_finalNetInfo, true, NetNode.Flags.Untouchable, NetSegment.Flags.Untouchable, Building.Flags.All, pathInfo.m_nodes[j].y + elevation - pathInfo.m_finalNetInfo.m_buildHeight, true, out controlPoint2)) { Vector3 vector3 = controlPoint2.m_position - vector; if (!flag2) { vector3.y = 0f; } float sqrMagnitude2 = vector3.sqrMagnitude; if (sqrMagnitude2 > pathInfo.m_maxSnapDistance * pathInfo.m_maxSnapDistance) { controlPoint2.m_position = vector; controlPoint2.m_elevation = 0f; controlPoint2.m_node = 0; controlPoint2.m_segment = 0; } else { controlPoint2.m_position.y = vector.y; } } else { controlPoint2.m_position = vector; } } NetTool.ControlPoint middlePoint = controlPoint2; if (pathInfo.m_curveTargets != null && pathInfo.m_curveTargets.Length >= j) { middlePoint.m_position = data.CalculatePosition(pathInfo.m_curveTargets[j - 1]); if (!flag || !flag2) { middlePoint.m_position.y = NetSegment.SampleTerrainHeight(pathInfo.m_finalNetInfo, middlePoint.m_position, false, pathInfo.m_curveTargets[j - 1].y + elevation); } } else { middlePoint.m_position = (controlPoint.m_position + controlPoint2.m_position) * 0.5f; } middlePoint.m_direction = VectorUtils.NormalizeXZ(middlePoint.m_position - controlPoint.m_position); controlPoint2.m_direction = VectorUtils.NormalizeXZ(controlPoint2.m_position - middlePoint.m_position); ushort num6; ushort num7; ushort num8; int num9; int num10; if (NetTool.CreateNode(pathInfo.m_finalNetInfo, controlPoint, middlePoint, controlPoint2, NetTool.m_nodePositionsSimulation, 1, false, false, false, false, false, pathInfo.m_invertSegments, false, 0, out num6, out num7, out num8, out num9, out num10) == ToolBase.ToolErrors.None) { instance.m_tempNodeBuffer.Add(num7); instance.m_tempSegmentBuffer.Add(num8); // ns if (isAssetWithTmpeSettings) { CreatedSegments[CreatedSegments.Count - 1] = num8; } // ns end controlPoint2.m_node = num7; if (pathInfo.m_forbidLaneConnection != null && pathInfo.m_forbidLaneConnection.Length > j && pathInfo.m_forbidLaneConnection[j]) { NetNode[] buffer2 = instance.m_nodes.m_buffer; ushort num11 = num7; buffer2[(int)num11].m_flags = (buffer2[(int)num11].m_flags | NetNode.Flags.ForbidLaneConnection); } if (pathInfo.m_trafficLights != null && pathInfo.m_trafficLights.Length > j) { /*BuildingDecoration.*/ TrafficLightsToFlags(pathInfo.m_trafficLights[j], ref instance.m_nodes.m_buffer[(int)num7].m_flags); } if (pathInfo.m_yieldSigns != null && pathInfo.m_yieldSigns.Length >= j * 2) { if (pathInfo.m_yieldSigns[j * 2 - 2]) { NetSegment[] buffer3 = instance.m_segments.m_buffer; ushort num12 = num8; buffer3[(int)num12].m_flags = (buffer3[(int)num12].m_flags | NetSegment.Flags.YieldStart); } if (pathInfo.m_yieldSigns[j * 2 - 1]) { NetSegment[] buffer4 = instance.m_segments.m_buffer; ushort num13 = num8; buffer4[(int)num13].m_flags = (buffer4[(int)num13].m_flags | NetSegment.Flags.YieldEnd); } } } controlPoint = controlPoint2; flag = flag2; } } } for (int k = 0; k < instance.m_tempNodeBuffer.m_size; k++) { ushort num14 = instance.m_tempNodeBuffer.m_buffer[k]; if ((instance.m_nodes.m_buffer[(int)num14].m_flags & NetNode.Flags.Untouchable) == NetNode.Flags.None) { if (buildingID != 0) { if ((data.m_flags & Building.Flags.Active) == Building.Flags.None && instance.m_nodes.m_buffer[(int)num14].Info.m_canDisable) { NetNode[] buffer5 = instance.m_nodes.m_buffer; ushort num15 = num14; buffer5[(int)num15].m_flags = (buffer5[(int)num15].m_flags | NetNode.Flags.Disabled); } NetNode[] buffer6 = instance.m_nodes.m_buffer; ushort num16 = num14; buffer6[(int)num16].m_flags = (buffer6[(int)num16].m_flags | NetNode.Flags.Untouchable); instance.UpdateNode(num14); instance.m_nodes.m_buffer[(int)num14].m_nextBuildingNode = data.m_netNode; data.m_netNode = num14; } else { instance.UpdateNode(num14); } } } for (int l = 0; l < instance.m_tempSegmentBuffer.m_size; l++) { ushort num17 = instance.m_tempSegmentBuffer.m_buffer[l]; if ((instance.m_segments.m_buffer[(int)num17].m_flags & NetSegment.Flags.Untouchable) == NetSegment.Flags.None) { if (buildingID != 0) { NetSegment[] buffer7 = instance.m_segments.m_buffer; ushort num18 = num17; buffer7[(int)num18].m_flags = (buffer7[(int)num18].m_flags | NetSegment.Flags.Untouchable); instance.UpdateSegment(num17); } else { if ((Singleton <ToolManager> .instance.m_properties.m_mode & ItemClass.Availability.AssetEditor) != ItemClass.Availability.None) { NetInfo info2 = instance.m_segments.m_buffer[(int)num17].Info; if ((info2.m_availableIn & ItemClass.Availability.AssetEditor) == ItemClass.Availability.None) { NetSegment[] buffer8 = instance.m_segments.m_buffer; ushort num19 = num17; buffer8[(int)num19].m_flags = (buffer8[(int)num19].m_flags | NetSegment.Flags.Untouchable); } } instance.UpdateSegment(num17); } } } // ns if (isAssetWithTmpeSettings && CreatedSegments.Count > 0) { if (CreatedSegments.Last() == 0) { CreatedSegments.RemoveAt(CreatedSegments.Count - 1); } ProcessNewPaths(CreatedSegments, info); } // ns end instance.m_tempNodeBuffer.Clear(); instance.m_tempSegmentBuffer.Clear(); } }