public static void SaveConfigurationToFile(string filename, Configuration config)
        {
            var serializer = new XmlSerializer(typeof(Configuration));

            using (var writer = new StreamWriter(filename))
            {
                serializer.Serialize(writer, config);
            }
        }
        public void OnSaveData()
        {
            Debug.Log("Saving Mod Data.");
            var data = new FastList<byte>();

            GenerateUniqueId();

            Debug.Log("UniqueID: " + UniqueId);
            var uniqueIdBytes = BitConverter.GetBytes(UniqueId);

            foreach (var uniqueIdByte in uniqueIdBytes)
            {
                data.Add(uniqueIdByte);
            }

            var dataToSave = data.ToArray();
            SerializableData.SaveData(DataId, dataToSave);

            var filepath = Path.Combine(Application.dataPath, "trafficManagerSave_" + UniqueId + ".xml");
            Debug.Log("Save Location: " + filepath);
            var configuration = new Configuration();

            for (var i = 0; i < 32768; i++)
            {
                if (TrafficPriority.PrioritySegments.ContainsKey(i))
                {
                    if (TrafficPriority.PrioritySegments[i].Node1 != 0)
                    {
                        configuration.PrioritySegments.Add(new[] { TrafficPriority.PrioritySegments[i].Node1, i, (int)TrafficPriority.PrioritySegments[i].Instance1.Type });
                    }
                    if (TrafficPriority.PrioritySegments[i].Node2 != 0)
                    {
                        configuration.PrioritySegments.Add(new[] { TrafficPriority.PrioritySegments[i].Node2, i, (int)TrafficPriority.PrioritySegments[i].Instance2.Type });
                    }
                }

                if (CustomRoadAI.NodeDictionary.ContainsKey((ushort) i))
                {
                    var nodeDict = CustomRoadAI.NodeDictionary[(ushort)i];

                    configuration.NodeDictionary.Add(new[] {nodeDict.NodeId, Convert.ToInt32(nodeDict.ManualTrafficLights), Convert.ToInt32(nodeDict.TimedTrafficLights), Convert.ToInt32(nodeDict.TimedTrafficLightsActive)});
                }

                if (TrafficLightsManual.ManualSegments.ContainsKey(i))
                {
                    if (TrafficLightsManual.ManualSegments[i].Node1 != 0)
                    {
                        var manualSegment = TrafficLightsManual.ManualSegments[i].Instance1;

                        configuration.ManualSegments.Add(new[]
                        {
                            manualSegment.Node,
                            manualSegment.Segment,
                            (int)manualSegment.CurrentMode,
                            (int)manualSegment.LightLeft,
                            (int)manualSegment.LightMain,
                            (int)manualSegment.LightRight,
                            (int)manualSegment.LightPedestrian,
                            (int)manualSegment.LastChange,
                            (int)manualSegment.LastChangeFrame,
                            Convert.ToInt32(manualSegment.PedestrianEnabled)
                        });
                    }
                    if (TrafficLightsManual.ManualSegments[i].Node2 != 0)
                    {
                        var manualSegment = TrafficLightsManual.ManualSegments[i].Instance2;

                        configuration.ManualSegments.Add(new[]
                        {
                            manualSegment.Node,
                            manualSegment.Segment,
                            (int)manualSegment.CurrentMode,
                            (int)manualSegment.LightLeft,
                            (int)manualSegment.LightMain,
                            (int)manualSegment.LightRight,
                            (int)manualSegment.LightPedestrian,
                            (int)manualSegment.LastChange,
                            (int)manualSegment.LastChangeFrame,
                            Convert.ToInt32(manualSegment.PedestrianEnabled)
                        });
                    }
                }

                if (!TrafficLightsTimed.TimedScripts.ContainsKey((ushort) i)) continue;

                var timedNode = TrafficLightsTimed.GetTimedLight((ushort) i);

                configuration.TimedNodes.Add(new[] { timedNode.NodeId, timedNode.CurrentStep, timedNode.NumSteps(), Convert.ToInt32(timedNode.IsStarted())});

                var nodeGroup = new ushort[timedNode.NodeGroup.Count];

                for (var j = 0; j < timedNode.NodeGroup.Count; j++)
                {
                    nodeGroup[j] = timedNode.NodeGroup[j];
                }

                configuration.TimedNodeGroups.Add(nodeGroup);

                for (var j = 0; j < timedNode.NumSteps(); j++)
                {
                    configuration.TimedNodeSteps.Add(new[]
                    {
                        timedNode.Steps[j].NumSteps,
                        timedNode.Steps[j].Segments.Count
                    });

                    for (var k = 0; k < timedNode.Steps[j].Segments.Count; k++)
                    {
                        configuration.TimedNodeStepSegments.Add(new[]
                        {
                            (int)timedNode.Steps[j].LightLeft[k],
                            (int)timedNode.Steps[j].LightMain[k],
                            (int)timedNode.Steps[j].LightRight[k],
                            (int)timedNode.Steps[j].LightPedestrian[k],
                        });
                    }
                }
            }

            for (var i = 0; i < Singleton<NetManager>.instance.m_nodes.m_buffer.Length; i++)
            {
                var nodeFlags = Singleton<NetManager>.instance.m_nodes.m_buffer[i].m_flags;

                if (nodeFlags == 0) continue;
                if (Singleton<NetManager>.instance.m_nodes.m_buffer[i].Info.m_class.m_service != ItemClass.Service.Road)
                    continue;
                configuration.NodeTrafficLights +=
                    Convert.ToInt16((nodeFlags & NetNode.Flags.TrafficLights) != NetNode.Flags.None);
                configuration.NodeCrosswalk +=
                    Convert.ToInt16((nodeFlags & NetNode.Flags.Junction) != NetNode.Flags.None);
            }

            for (var i = 0; i < Singleton<NetManager>.instance.m_lanes.m_buffer.Length; i++)
            {
                var laneSegment = Singleton<NetManager>.instance.m_lanes.m_buffer[i].m_segment;

                if (TrafficPriority.PrioritySegments.ContainsKey(laneSegment))
                {
                    configuration.LaneFlags += i + ":" + Singleton<NetManager>.instance.m_lanes.m_buffer[i].m_flags + ",";
                }
            }

            Configuration.SaveConfigurationToFile(filepath, configuration);
        }
		private static void DeserializeData(byte[] data) {
			try {
				if (data != null && data.Length != 0) {
					Log.Message("Loading Data from New Load Routine!");
					var memoryStream = new MemoryStream();
					memoryStream.Write(data, 0, data.Length);
					memoryStream.Position = 0;

					var binaryFormatter = new BinaryFormatter();
					_configuration = (Configuration)binaryFormatter.Deserialize(memoryStream);
				} else {
					Log.Warning("No data to deserialize!");
				}
			} catch (Exception e) {
				Log.Error($"Error deserializing data: {e.Message}");
			}
			
			LoadDataState();
			TrafficPriority.HandleAllVehicles();
		}
		private static void SavePrioritySegment(ushort segmentId, Configuration configuration) {
			try {
				if (TrafficPriority.PrioritySegments[segmentId] == null) {
					return;
				}

				if (TrafficPriority.PrioritySegments[segmentId].Node1 != 0 && TrafficPriority.PrioritySegments[segmentId].Instance1.Type != PrioritySegment.PriorityType.None) {
					Log.Message($"Saving Priority Segment of type: {TrafficPriority.PrioritySegments[segmentId].Instance1.Type} @ node {TrafficPriority.PrioritySegments[segmentId].Node1}, seg. {segmentId}");
                    configuration.PrioritySegments.Add(new[]
					{
						TrafficPriority.PrioritySegments[segmentId].Node1, segmentId,
						(int) TrafficPriority.PrioritySegments[segmentId].Instance1.Type
					});
				}

				if (TrafficPriority.PrioritySegments[segmentId].Node2 == 0 || TrafficPriority.PrioritySegments[segmentId].Instance2.Type == PrioritySegment.PriorityType.None)
					return;

				Log.Message($"Saving Priority Segment of type: {TrafficPriority.PrioritySegments[segmentId].Instance2.Type} @ node {TrafficPriority.PrioritySegments[segmentId].Node2}, seg. {segmentId}");
				configuration.PrioritySegments.Add(new[] {
					TrafficPriority.PrioritySegments[segmentId].Node2, segmentId,
					(int) TrafficPriority.PrioritySegments[segmentId].Instance2.Type
				});
			} catch (Exception e) {
				Log.Error($"Error adding Priority Segments to Save: {e.ToString()}");
			}
		}
		private static void SaveTrafficLightSimulation(int i, Configuration configuration) {
			try {
				if (!TrafficLightSimulation.LightSimulationByNodeId.ContainsKey((ushort)i))
					return;
				var nodeSim = TrafficLightSimulation.LightSimulationByNodeId[(ushort)i];

				/*if (nodeSim == null)
					return;*/

				Log.Message($"Saving traffic light simulation at node {i}, timed: {nodeSim.TimedTrafficLights}, active: {nodeSim.TimedTrafficLightsActive}");

				configuration.NodeDictionary.Add(new[]
				{
					nodeSim.nodeId, Convert.ToInt32(nodeSim.ManualTrafficLights),
					Convert.ToInt32(nodeSim.TimedTrafficLights),
					Convert.ToInt32(nodeSim.TimedTrafficLightsActive)
				});
			} catch (Exception e) {
				Log.Error($"Error adding Nodes to Dictionary {e.Message}");
			}
		}
		private static void SaveManualTrafficLight(ushort segmentId, Configuration configuration) {
			try {
				if (!TrafficLightsManual.ManualSegments.ContainsKey(segmentId))
					return;

				if (TrafficLightsManual.ManualSegments[segmentId].Node1 != 0) {
					var manualSegment = TrafficLightsManual.ManualSegments[segmentId].Instance1;

					configuration.ManualSegments.Add(new[]
					{
						manualSegment.nodeId,
						manualSegment.SegmentId,
						(int) manualSegment.CurrentMode,
						(int) manualSegment.LightLeft,
						(int) manualSegment.LightMain,
						(int) manualSegment.LightRight,
						(int) manualSegment.LightPedestrian,
						(int) manualSegment.LastChange,
						(int) manualSegment.LastChangeFrame,
						Convert.ToInt32(manualSegment.PedestrianEnabled)
					});
				}
				if (TrafficLightsManual.ManualSegments[segmentId].Node2 == 0)
					return;
				var manualSegmentLight = TrafficLightsManual.ManualSegments[segmentId].Instance2;

				configuration.ManualSegments.Add(new[]
				{
					manualSegmentLight.nodeId,
					manualSegmentLight.SegmentId,
					(int) manualSegmentLight.CurrentMode,
					(int) manualSegmentLight.LightLeft,
					(int) manualSegmentLight.LightMain,
					(int) manualSegmentLight.LightRight,
					(int) manualSegmentLight.LightPedestrian,
					(int) manualSegmentLight.LastChange,
					(int) manualSegmentLight.LastChangeFrame,
					Convert.ToInt32(manualSegmentLight.PedestrianEnabled)
				});
			} catch (Exception e) {
				Log.Error($"Error saving ManualTraffic Lights {e.Message}");
			}
		}
		private static void SaveTimedTrafficLight(int i, Configuration configuration) {
			try {
				if (!TrafficLightsTimed.TimedScripts.ContainsKey((ushort)i))
					return;

				var timedNode = TrafficLightsTimed.GetTimedLight((ushort)i);
				timedNode.handleNewSegments();

				configuration.TimedNodes.Add(new[]
				{
					timedNode.nodeId, timedNode.CurrentStep, timedNode.NumSteps(),
					Convert.ToInt32(timedNode.IsStarted())
				});

				var nodeGroup = new ushort[timedNode.NodeGroup.Count];

				for (var j = 0; j < timedNode.NodeGroup.Count; j++) {
					nodeGroup[j] = timedNode.NodeGroup[j];
				}

				configuration.TimedNodeGroups.Add(nodeGroup);

				// get segment ids which are still defined but for which real road segments are missing
				NetManager netManager = Singleton<NetManager>.instance;

				for (var j = 0; j < timedNode.NumSteps(); j++) {
					int validCount = 0;
					var node = netManager.m_nodes.m_buffer[i];
					for (var s = 0; s < 8; s++) {
						var segmentId = node.GetSegment(s);
						if (segmentId <= 0)
							continue;
						
						var segLight = timedNode.Steps[j].segmentLightStates.ContainsKey(segmentId) ? timedNode.Steps[j].segmentLightStates[segmentId] : null;
						configuration.TimedNodeStepSegments.Add(new[]
						{
							(int) (segLight == null ? RoadBaseAI.TrafficLightState.Red : segLight.LightLeft),
							(int) (segLight == null ? RoadBaseAI.TrafficLightState.Red : segLight.LightMain),
							(int) (segLight == null ? RoadBaseAI.TrafficLightState.Red : segLight.LightRight),
							(int) (segLight == null ? RoadBaseAI.TrafficLightState.Red : segLight.LightPedestrian),
							(int) segLight.CurrentMode
						});

						++validCount;
					}

					configuration.TimedNodeSteps.Add(new[]
					{
						timedNode.Steps[j].minTime,
						timedNode.Steps[j].maxTime,
						validCount,
						(int)(timedNode.Steps[j].waitFlowBalance*10)
					});
				}
			} catch (Exception e) {
				Log.Error($"Error adding TimedTrafficLights to save {e.Message}");
			}
		}
		private static bool SaveNodeLights(int i, Configuration configuration) {
			try {
				if (!Flags.mayHaveTrafficLight((ushort)i))
					return true;

				bool hasTrafficLight = Flags.isNodeTrafficLight((ushort)i);
				if (hasTrafficLight) {
					Log.Message($"Saving that node {i} has a traffic light");
				} else {
					Log.Message($"Saving that node {i} does not have a traffic light");
				}
				configuration.NodeTrafficLights += $"{i}:{Convert.ToUInt16(hasTrafficLight)},";
				return false;
			} catch (Exception e) {
				Log.Error($"Error Adding Node Lights and Crosswalks {e.Message}");
				return true;
			}
		}
		private static void SaveLaneData(uint i, Configuration configuration) {
			try {
				NetLane lane = Singleton<NetManager>.instance.m_lanes.m_buffer[i];
				//NetLane.Flags flags = (NetLane.Flags)lane.m_flags;
				/*if ((flags & NetLane.Flags.LeftForwardRight) == NetLane.Flags.None) // only save lanes with explicit lane arrows
					return;*/
				var laneSegmentId = lane.m_segment;
				if (laneSegmentId <= 0)
					return;
				if ((lane.m_flags & (ushort)NetLane.Flags.Created) == 0 || laneSegmentId == 0)
					return;
				NetSegment segment = Singleton<NetManager>.instance.m_segments.m_buffer[laneSegmentId];
				if ((segment.m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None)
					return;

				//if (TrafficPriority.PrioritySegments.ContainsKey(laneSegmentId)) {
				Flags.LaneArrows? laneArrows = Flags.getLaneArrowFlags(i);
				if (laneArrows != null) {
					uint laneArrowInt = (uint)laneArrows;
					Log.Message($"Saving lane data for lane {i}, segment {laneSegmentId}, setting to {laneArrows.ToString()} ({laneArrowInt})");
                    configuration.LaneFlags += $"{i}:{laneArrowInt},";
				}
				//}
			} catch (Exception e) {
				Log.Error($"Error saving NodeLaneData {e.Message}");
			}
		}
		public override void OnSaveData() {
			Log.Warning("Saving Mod Data.");
			var configuration = new Configuration();

			if (TrafficPriority.PrioritySegments != null) {
				for (ushort i = 0; i < Singleton<NetManager>.instance.m_segments.m_size; i++) {
					SavePrioritySegment(i, configuration);
				}
			}

			for (ushort i = 0; i < Singleton<NetManager>.instance.m_nodes.m_size; i++) {
				if (TrafficLightSimulation.LightSimulationByNodeId != null) {
					SaveTrafficLightSimulation(i, configuration);
				}

				/*if (TrafficLightsManual.ManualSegments != null) {
					SaveManualTrafficLight(i, configuration);
				}*/

				if (TrafficLightsTimed.TimedScripts != null) {
					SaveTimedTrafficLight(i, configuration);
				}

				SaveNodeLights(i, configuration);
			}

			if (LoadingExtension.IsPathManagerCompatible) {
				for (uint i = 0; i < Singleton<NetManager>.instance.m_lanes.m_buffer.Length; i++) {
					SaveLaneData(i, configuration);
				}
			}

			var binaryFormatter = new BinaryFormatter();
			var memoryStream = new MemoryStream();

			try {
				binaryFormatter.Serialize(memoryStream, configuration);
				memoryStream.Position = 0;
				Log.Message($"Save data byte length {memoryStream.Length}");
				_serializableData.SaveData(DataId, memoryStream.ToArray());

				// save options
				_serializableData.SaveData("TMPE_Options", new byte[] { (byte)Options.simAccuracy, (byte)Options.laneChangingRandomization, (byte)Options.recklessDrivers, (byte)(Options.relaxedBusses ? 1 : 0), (byte) (Options.nodesOverlay ? 1 : 0), (byte)(Options.mayEnterBlockedJunctions ? 1 : 0), (byte)(Options.advancedAI ? 1 : 0), (byte)(Options.highwayRules ? 1 : 0), Convert.ToByte(Math.Round(Options.carCityTrafficSensitivity * 100f)), Convert.ToByte(Math.Round(Options.carHighwayTrafficSensitivity * 100f)), Convert.ToByte(Math.Round(Options.truckCityTrafficSensitivity * 100f)), Convert.ToByte(Math.Round(Options.truckHighwayTrafficSensitivity * 100f)) });
			} catch (Exception ex) {
				Log.Error("Unexpected error saving data: " + ex.Message);
			} finally {
				memoryStream.Close();
			}
		}
        public void OnSaveData()
        {
            FastList<byte> data = new FastList<byte>();

            GenerateUniqueID();

            byte[] uniqueIdBytes = BitConverter.GetBytes(uniqueID);
            foreach (byte uniqueIdByte in uniqueIdBytes)
            {
                data.Add(uniqueIdByte);
            }

            byte[] dataToSave = data.ToArray();
            SerializableData.SaveData(dataID, dataToSave);

            var filepath = Path.Combine(Application.dataPath, "trafficManagerSave_" + uniqueID + ".xml");

            var configuration = new Configuration();

            for (var i = 0; i < 32768; i++)
            {
                if (TrafficPriority.prioritySegments.ContainsKey(i))
                {
                    if (TrafficPriority.prioritySegments[i].node_1 != 0)
                    {
                        configuration.prioritySegments.Add(new int[3] { TrafficPriority.prioritySegments[i].node_1, i, (int)TrafficPriority.prioritySegments[i].instance_1.type });
                    }
                    if (TrafficPriority.prioritySegments[i].node_2 != 0)
                    {
                        configuration.prioritySegments.Add(new int[3] { TrafficPriority.prioritySegments[i].node_2, i, (int)TrafficPriority.prioritySegments[i].instance_2.type });
                    }
                }

                if (CustomRoadAI.nodeDictionary.ContainsKey((ushort) i))
                {
                    var nodeDict = CustomRoadAI.nodeDictionary[(ushort)i];

                    configuration.nodeDictionary.Add(new int[4] {nodeDict.NodeId, Convert.ToInt32(nodeDict._manualTrafficLights), Convert.ToInt32(nodeDict._timedTrafficLights), Convert.ToInt32(nodeDict.TimedTrafficLightsActive)});
                }

                if (TrafficLightsManual.ManualSegments.ContainsKey(i))
                {
                    if (TrafficLightsManual.ManualSegments[i].node_1 != 0)
                    {
                        var manualSegment = TrafficLightsManual.ManualSegments[i].instance_1;

                        configuration.manualSegments.Add(new int[10]
                        {
                            (int)manualSegment.node,
                            manualSegment.segment,
                            (int)manualSegment.currentMode,
                            (int)manualSegment.lightLeft,
                            (int)manualSegment.lightMain,
                            (int)manualSegment.lightRight,
                            (int)manualSegment.lightPedestrian,
                            (int)manualSegment.lastChange,
                            (int)manualSegment.lastChangeFrame,
                            Convert.ToInt32(manualSegment.pedestrianEnabled)
                        });
                    }
                    if (TrafficLightsManual.ManualSegments[i].node_2 != 0)
                    {
                        var manualSegment = TrafficLightsManual.ManualSegments[i].instance_2;

                        configuration.manualSegments.Add(new int[10]
                        {
                            (int)manualSegment.node,
                            manualSegment.segment,
                            (int)manualSegment.currentMode,
                            (int)manualSegment.lightLeft,
                            (int)manualSegment.lightMain,
                            (int)manualSegment.lightRight,
                            (int)manualSegment.lightPedestrian,
                            (int)manualSegment.lastChange,
                            (int)manualSegment.lastChangeFrame,
                            Convert.ToInt32(manualSegment.pedestrianEnabled)
                        });
                    }
                }

                if (TrafficLightsTimed.timedScripts.ContainsKey((ushort)i))
                {
                    var timedNode = TrafficLightsTimed.GetTimedLight((ushort) i);

                    configuration.timedNodes.Add(new int[4] { timedNode.nodeID, timedNode.currentStep, timedNode.NumSteps(), Convert.ToInt32(timedNode.isStarted())});

                    var nodeGroup = new ushort[timedNode.nodeGroup.Count];

                    for (var j = 0; j < timedNode.nodeGroup.Count; j++)
                    {
                        nodeGroup[j] = timedNode.nodeGroup[j];
                    }

                    configuration.timedNodeGroups.Add(nodeGroup);

                    for (var j = 0; j < timedNode.NumSteps(); j++)
                    {
                        configuration.timedNodeSteps.Add(new int[2]
                        {
                            timedNode.steps[j].numSteps,
                            timedNode.steps[j].segments.Count
                        });

                        for (var k = 0; k < timedNode.steps[j].segments.Count; k++)
                        {
                            configuration.timedNodeStepSegments.Add(new int[4]
                            {
                                (int)timedNode.steps[j].lightLeft[k],
                                (int)timedNode.steps[j].lightMain[k],
                                (int)timedNode.steps[j].lightRight[k],
                                (int)timedNode.steps[j].lightPedestrian[k],
                            });
                        }
                    }
                }
            }

            for (var i = 0; i < Singleton<NetManager>.instance.m_nodes.m_buffer.Length; i++)
            {
                var nodeFlags = Singleton<NetManager>.instance.m_nodes.m_buffer[i].m_flags;

                if (nodeFlags != 0)
                {
                    if (Singleton<NetManager>.instance.m_nodes.m_buffer[i].Info.m_class.m_service ==
                        ItemClass.Service.Road)
                    {
                        configuration.nodeTrafficLights +=
                            Convert.ToInt16((nodeFlags & NetNode.Flags.TrafficLights) != NetNode.Flags.None);
                        configuration.nodeCrosswalk +=
                            Convert.ToInt16((nodeFlags & NetNode.Flags.Junction) != NetNode.Flags.None);
                    }
                }
            }

            for (var i = 0; i < Singleton<NetManager>.instance.m_lanes.m_buffer.Length; i++)
            {
                var laneSegment = Singleton<NetManager>.instance.m_lanes.m_buffer[i].m_segment;

                if (TrafficPriority.prioritySegments.ContainsKey(laneSegment))
                {
                    configuration.laneFlags += i + ":" + Singleton<NetManager>.instance.m_lanes.m_buffer[i].m_flags + ",";
                }
            }

            Configuration.Serialize(filepath, configuration);
        }