public static bool ReadMarkerXML(string fileName, double StartingPosition, ref Marker Marker) { double EndingPosition = Double.PositiveInfinity; AbstractMessage Message = null; //The current XML file to load XmlDocument currentXML = new XmlDocument(); //Load the marker's XML file currentXML.Load(fileName); string Path = System.IO.Path.GetDirectoryName(fileName); if (currentXML.DocumentElement != null) { bool iM = false; XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/TextMarker"); if (DocumentNodes == null || DocumentNodes.Count == 0) { DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/ImageMarker"); iM = true; } if (DocumentNodes == null || DocumentNodes.Count == 0) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "No marker nodes defined in XML file " + fileName); return(false); } foreach (XmlNode n in DocumentNodes) { if (n.ChildNodes.OfType <XmlElement>().Any()) { bool EarlyDefined = false, LateDefined = false; string EarlyText = null, Text = null, LateText = null; string[] Trains = null; Texture EarlyTexture = null, Texture = null, LateTexture = null; double EarlyTime = 0.0, LateTime = 0.0, TimeOut = Double.PositiveInfinity; MessageColor EarlyColor = MessageColor.White, OnTimeColor = MessageColor.White, LateColor = MessageColor.White; foreach (XmlNode c in n.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "early": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "No paramaters defined for the early message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": EarlyText = cc.InnerText; break; case "texture": case "image": string f; try { f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MessageEarlyTexture path was malformed in file " + fileName); break; } if (System.IO.File.Exists(f)) { if (!Plugin.CurrentHost.RegisterTexture(f, new TextureParameters(null, null), out EarlyTexture)) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Loading MessageEarlyTexture " + f + " failed."); } } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MessageEarlyTexture " + f + " does not exist."); } break; case "time": if (!Parser.TryParseTime(cc.InnerText, out EarlyTime)) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Early message time invalid in " + fileName); } EarlyDefined = true; break; case "color": EarlyColor = ParseColor(cc.InnerText, fileName); break; } } break; case "ontime": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "No paramaters defined for the on-time message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": Text = cc.InnerText; break; case "texture": case "image": string f; try { f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MessageTexture path was malformed in file " + fileName); break; } if (System.IO.File.Exists(f)) { if (!Plugin.CurrentHost.RegisterTexture(f, new TextureParameters(null, null), out Texture)) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Loading MessageTexture " + f + " failed."); } } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MessageTexture " + f + " does not exist."); } break; case "color": OnTimeColor = ParseColor(cc.InnerText, fileName); break; case "time": Plugin.CurrentHost.AddMessage(MessageType.Error, false, "OnTime should not contain a TIME declaration in " + fileName); break; } } break; case "late": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "No paramaters defined for the late message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": LateText = cc.InnerText; break; case "texture": case "image": string f; try { f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MessageLateTexture path was malformed in file " + fileName); break; } if (System.IO.File.Exists(f)) { if (!Plugin.CurrentHost.RegisterTexture(f, new TextureParameters(null, null), out LateTexture)) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Loading MessageLateTexture " + f + " failed."); } } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "MessageLateTexture " + f + " does not exist."); } break; case "time": if (!Parser.TryParseTime(cc.InnerText, out LateTime)) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Early message time invalid in " + fileName); } LateDefined = true; break; case "color": LateColor = ParseColor(cc.InnerText, fileName); break; } } break; case "timeout": if (!NumberFormats.TryParseDouble(c.InnerText, new[] { 1.0 }, out TimeOut)) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Marker timeout invalid in " + fileName); } break; case "distance": if (!NumberFormats.TryParseDouble(c.InnerText, new[] { 1.0 }, out EndingPosition)) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Marker distance invalid in " + fileName); } break; case "trains": Trains = c.InnerText.Split(';'); break; } } //Check this marker is valid if (TimeOut == Double.PositiveInfinity && EndingPosition == Double.PositiveInfinity) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "No marker timeout or distance defined in marker XML " + fileName); return(false); } if (EndingPosition != Double.PositiveInfinity) { if (Math.Abs(EndingPosition) == EndingPosition) { //Positive EndingPosition = StartingPosition + EndingPosition; } else { //Negative EndingPosition = StartingPosition; StartingPosition -= EndingPosition; } } TextureMessage t = new TextureMessage(Plugin.CurrentHost); GeneralMessage m = new GeneralMessage(); //Add variants if (EarlyDefined) { if (iM) { if (EarlyTexture != null) { t.MessageEarlyTime = EarlyTime; t.MessageEarlyTexture = EarlyTexture; } else { Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } else { if (EarlyText != null) { m.MessageEarlyTime = EarlyTime; m.MessageEarlyText = EarlyText; m.MessageEarlyColor = EarlyColor; } else { Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } } if (LateDefined) { if (iM) { if (LateTexture != null) { t.MessageLateTime = LateTime; t.MessageLateTexture = LateTexture; } else { Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "A late time was defined, but no message was specified in MarkerXML " + fileName); } } else { if (LateText != null) { m.MessageLateTime = LateTime; m.MessageLateText = LateText; m.MessageLateColor = LateColor; } else { Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } } //Final on-time message if (iM) { t.Trains = Trains; if (Texture != null) { t.MessageOnTimeTexture = Texture; } } else { m.Trains = Trains; if (Text != null) { m.MessageOnTimeText = Text; m.Color = OnTimeColor; } } if (iM) { Message = t; } else { Message = m; } } } } Marker = new Marker(StartingPosition, EndingPosition, Message); return(true); }
// parse route for data private void ParseRouteForData(string FileName, System.Text.Encoding Encoding, Expression[] Expressions, double[] UnitOfLength, ref RouteData Data, bool PreviewOnly) { CurrentStation = -1; CurrentStop = -1; CurrentSection = 0; string Section = ""; bool SectionAlwaysPrefix = false; int BlockIndex = 0; CurrentRoute.Stations = new RouteStation[] { }; Data.RequestStops = new StopRequest[] { }; double progressFactor = Expressions.Length == 0 ? 0.3333 : 0.3333 / Expressions.Length; // process non-track namespaces //Check for any special-cased fixes we might need CheckForAvailablePatch(FileName, ref Data, ref Expressions, PreviewOnly); //Apply parameters to object loaders if (!PreviewOnly) { for (int i = 0; i < Plugin.CurrentHost.Plugins.Length; i++) { if (Plugin.CurrentHost.Plugins[i].Object != null) { EnabledHacks.BveTsHacks = Plugin.CurrentOptions.EnableBveTsHacks; EnabledHacks.BlackTransparency = true; Plugin.CurrentHost.Plugins[i].Object.SetCompatibilityHacks(EnabledHacks); //Remember that these will be ignored if not the correct plugin Plugin.CurrentHost.Plugins[i].Object.SetObjectParser(Plugin.CurrentOptions.CurrentXParser); Plugin.CurrentHost.Plugins[i].Object.SetObjectParser(Plugin.CurrentOptions.CurrentObjParser); } } } for (int j = 0; j < Expressions.Length; j++) { Plugin.CurrentProgress = j * progressFactor; if ((j & 255) == 0) { System.Threading.Thread.Sleep(1); if (Plugin.Cancel) { Plugin.IsLoading = false; return; } } if (Expressions[j].Text.StartsWith("[") && Expressions[j].Text.EndsWith("]")) { Section = Expressions[j].Text.Substring(1, Expressions[j].Text.Length - 2).Trim(new char[] { }); if (string.Compare(Section, "object", StringComparison.OrdinalIgnoreCase) == 0) { Section = "Structure"; } else if (string.Compare(Section, "railway", StringComparison.OrdinalIgnoreCase) == 0) { Section = "Track"; } SectionAlwaysPrefix = true; } else { // find equals if (IsRW) { Expressions[j].ConvertRwToCsv(Section, SectionAlwaysPrefix); } // separate command and arguments string Command, ArgumentSequence; Expressions[j].SeparateCommandsAndArguments(out Command, out ArgumentSequence, Culture, false, IsRW, Section); // process command bool NumberCheck = !IsRW || string.Compare(Section, "track", StringComparison.OrdinalIgnoreCase) == 0; if (NumberCheck && NumberFormats.IsValidDouble(Command, UnitOfLength)) { // track position (ignored) } else { string[] Arguments = SplitArguments(ArgumentSequence); // preprocess command if (Command.ToLowerInvariant() == "with") { if (Arguments.Length >= 1) { Section = Arguments[0]; SectionAlwaysPrefix = false; } else { Section = ""; SectionAlwaysPrefix = false; } Command = null; } else { if (Command.StartsWith(".")) { Command = Section + Command; } else if (SectionAlwaysPrefix) { Command = Section + "." + Command; } Command = Command.Replace(".Void", ""); if (Command.StartsWith("structure", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".load", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 5).TrimEnd(new char[] { }); } else if (Command.StartsWith("texture.background", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".load", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 5).TrimEnd(new char[] { }); } else if (Command.StartsWith("texture.background", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".x", StringComparison.OrdinalIgnoreCase)) { Command = "texture.backgroundx" + Command.Substring(18, Command.Length - 20).TrimEnd(new char[] { }); } else if (Command.StartsWith("texture.background", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".aspect", StringComparison.OrdinalIgnoreCase)) { Command = "texture.backgroundaspect" + Command.Substring(18, Command.Length - 25).TrimEnd(new char[] { }); } else if (Command.StartsWith("structure.back", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".x", StringComparison.OrdinalIgnoreCase)) { Command = "texture.backgroundx" + Command.Substring(14, Command.Length - 16).TrimEnd(new char[] { }); } else if (Command.StartsWith("structure.back", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".aspect", StringComparison.OrdinalIgnoreCase)) { Command = "texture.backgroundaspect" + Command.Substring(14, Command.Length - 21).TrimEnd(new char[] { }); } else if (Command.StartsWith("cycle", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".params", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 7).TrimEnd(new char[] { }); } else if (Command.StartsWith("signal", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".load", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 5).TrimEnd(new char[] { }); } else if (Command.StartsWith("train.run", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".set", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 4).TrimEnd(new char[] { }); } else if (Command.StartsWith("train.flange", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".set", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 4).TrimEnd(new char[] { }); } else if (Command.StartsWith("train.timetable", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".day.load", StringComparison.OrdinalIgnoreCase)) { Command = "train.timetable.day" + Command.Substring(15, Command.Length - 24).Trim(new char[] { }); } else if (Command.StartsWith("train.timetable", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".night.load", StringComparison.OrdinalIgnoreCase)) { Command = "train.timetable.night" + Command.Substring(15, Command.Length - 26).Trim(new char[] { }); } else if (Command.StartsWith("train.timetable", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".day", StringComparison.OrdinalIgnoreCase)) { Command = "train.timetable.day" + Command.Substring(15, Command.Length - 19).Trim(new char[] { }); } else if (Command.StartsWith("train.timetable", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".night", StringComparison.OrdinalIgnoreCase)) { Command = "train.timetable.night" + Command.Substring(15, Command.Length - 21).Trim(new char[] { }); } else if (Command.StartsWith("route.signal", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".set", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 4).TrimEnd(new char[] { }); } else if (Command.StartsWith("route.runinterval", StringComparison.OrdinalIgnoreCase)) { Command = "train.interval" + Command.Substring(17, Command.Length - 17); } else if (Command.StartsWith("train.gauge", StringComparison.OrdinalIgnoreCase)) { Command = "route.gauge" + Command.Substring(11, Command.Length - 11); } else if (Command.StartsWith("texture.", StringComparison.OrdinalIgnoreCase)) { Command = "structure." + Command.Substring(8, Command.Length - 8); } //Needed after the initial processing to make the enum parse work Command = Command.Replace("timetable.day", "timetableday"); Command = Command.Replace("timetable.night", "timetablenight"); } int[] commandIndices = FindIndices(ref Command, Expressions[j]); // process command if (!string.IsNullOrEmpty(Command)) { int period = Command.IndexOf('.'); string nameSpace = string.Empty; if (period != -1) { nameSpace = Command.Substring(0, period).ToLowerInvariant(); Command = Command.Substring(period + 1); } Command = Command.ToLowerInvariant(); switch (nameSpace) { case "options": OptionsCommand parsedOptionCommand; if (Enum.TryParse(Command, true, out parsedOptionCommand)) { ParseOptionCommand(parsedOptionCommand, Arguments, UnitOfLength, Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Options namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "route": RouteCommand parsedRouteCommand; if (Enum.TryParse(Command, true, out parsedRouteCommand)) { ParseRouteCommand(parsedRouteCommand, Arguments, commandIndices[0], FileName, UnitOfLength, Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Route namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "train": TrainCommand parsedTrainCommand; if (Enum.TryParse(Command.Split(' ')[0], true, out parsedTrainCommand)) { ParseTrainCommand(parsedTrainCommand, Arguments, commandIndices[0], Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Train namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "structure": case "texture": StructureCommand parsedStructureCommand; if (Enum.TryParse(Command, true, out parsedStructureCommand)) { ParseStructureCommand(parsedStructureCommand, Arguments, commandIndices, Encoding, Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Structure namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "": ParseSignalCommand(Command, Arguments, commandIndices[0], Encoding, Expressions[j], ref Data, PreviewOnly); break; case "cycle": CycleCommand parsedCycleCommand; if (Enum.TryParse(Command, true, out parsedCycleCommand)) { ParseCycleCommand(parsedCycleCommand, Arguments, commandIndices[0], Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Cycle namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "track": break; // ReSharper disable once RedundantEmptySwitchSection default: /* * This needs an unrecognised command at some stage */ break; } } } } } // process track namespace for (int j = 0; j < Expressions.Length; j++) { Plugin.CurrentProgress = 0.3333 + j * progressFactor; if ((j & 255) == 0) { System.Threading.Thread.Sleep(1); if (Plugin.Cancel) { Plugin.IsLoading = false; return; } } if (Data.LineEndingFix) { if (Expressions[j].Text.EndsWith("_")) { Expressions[j].Text = Expressions[j].Text.Substring(0, Expressions[j].Text.Length - 1).Trim(new char[] { }); } } if (Expressions[j].Text.StartsWith("[") && Expressions[j].Text.EndsWith("]")) { Section = Expressions[j].Text.Substring(1, Expressions[j].Text.Length - 2).Trim(new char[] { }); if (string.Compare(Section, "object", StringComparison.OrdinalIgnoreCase) == 0) { Section = "Structure"; } else if (string.Compare(Section, "railway", StringComparison.OrdinalIgnoreCase) == 0) { Section = "Track"; } SectionAlwaysPrefix = true; } else { if (IsRW) { Expressions[j].ConvertRwToCsv(Section, SectionAlwaysPrefix); } // separate command and arguments string Command, ArgumentSequence; Expressions[j].SeparateCommandsAndArguments(out Command, out ArgumentSequence, Culture, false, IsRW, Section); // process command double currentTrackPosition; bool NumberCheck = !IsRW || string.Compare(Section, "track", StringComparison.OrdinalIgnoreCase) == 0; if (NumberCheck && NumberFormats.TryParseDouble(Command, UnitOfLength, out currentTrackPosition)) { // track position if (ArgumentSequence.Length != 0) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "A track position must not contain any arguments at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); if (AllowTrackPositionArguments) { Data.TrackPosition = currentTrackPosition; BlockIndex = (int)Math.Floor(currentTrackPosition / Data.BlockInterval + 0.001); if (Data.FirstUsedBlock == -1) { Data.FirstUsedBlock = BlockIndex; } Data.CreateMissingBlocks(BlockIndex, PreviewOnly); } } else if (currentTrackPosition < 0.0) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Negative track position encountered at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } else { if (Plugin.CurrentOptions.EnableBveTsHacks && IsRW && currentTrackPosition == 4535545100) { //WMATA Red line has an erroneous track position causing an out of memory cascade currentTrackPosition = 45355; } Data.TrackPosition = currentTrackPosition; BlockIndex = (int)Math.Floor(currentTrackPosition / Data.BlockInterval + 0.001); if (Data.FirstUsedBlock == -1) { Data.FirstUsedBlock = BlockIndex; } Data.CreateMissingBlocks(BlockIndex, PreviewOnly); } } else { string[] Arguments = SplitArguments(ArgumentSequence); // preprocess command if (Command.ToLowerInvariant() == "with") { if (Arguments.Length >= 1) { Section = Arguments[0]; SectionAlwaysPrefix = false; } else { Section = ""; SectionAlwaysPrefix = false; } Command = null; } else { if (Command.StartsWith(".")) { Command = Section + Command; } else if (SectionAlwaysPrefix) { Command = Section + "." + Command; } Command = Command.Replace(".Void", ""); } // process command if (!string.IsNullOrEmpty(Command)) { int period = Command.IndexOf('.'); string nameSpace = string.Empty; if (period != -1) { nameSpace = Command.Substring(0, period).ToLowerInvariant(); Command = Command.Substring(period + 1); } if (nameSpace.StartsWith("signal", StringComparison.InvariantCultureIgnoreCase)) { nameSpace = ""; } Command = Command.ToLowerInvariant(); switch (nameSpace) { case "track": TrackCommand parsedCommand; if (Enum.TryParse(Command, true, out parsedCommand)) { ParseTrackCommand(parsedCommand, Arguments, FileName, UnitOfLength, Expressions[j], ref Data, BlockIndex, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Route namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "options": case "route": case "train": case "structure": case "texture": case "": case "cycle": break; default: Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "The command " + Command + " is not supported at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); break; } } } } } }
private void PreprocessSortByTrackPosition(double[] UnitFactors, ref Expression[] Expressions) { PositionedExpression[] p = new PositionedExpression[Expressions.Length]; int n = 0; double a = -1.0; bool NumberCheck = !IsRW; for (int i = 0; i < Expressions.Length; i++) { if (IsRW) { // only check for track positions in the railway section for RW routes if (Expressions[i].Text.StartsWith("[", StringComparison.Ordinal) & Expressions[i].Text.EndsWith("]", StringComparison.Ordinal)) { string s = Expressions[i].Text.Substring(1, Expressions[i].Text.Length - 2).Trim(new char[] { }); NumberCheck = string.Compare(s, "Railway", StringComparison.OrdinalIgnoreCase) == 0; } } double x; if (NumberCheck && NumberFormats.TryParseDouble(Expressions[i].Text, UnitFactors, out x)) { x += Expressions[i].TrackPositionOffset; if (x >= 0.0) { if (Plugin.CurrentOptions.EnableBveTsHacks) { switch (System.IO.Path.GetFileName(Expressions[i].File.ToLowerInvariant())) { case "balloch - dumbarton central special nighttime run.csv": case "balloch - dumbarton central summer 2004 morning run.csv": if (x != 0 || a != 4125) { //Misplaced comma in the middle of the line causes this to be interpreted as a track position a = x; } break; default: a = x; break; } } else { a = x; } } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Negative track position encountered at line " + Expressions[i].Line.ToString(Culture) + ", column " + Expressions[i].Column.ToString(Culture) + " in file " + Expressions[i].File); } } else { p[n].TrackPosition = a; p[n].Expression = Expressions[i]; int j = n; n++; while (j > 0) { if (p[j].TrackPosition < p[j - 1].TrackPosition) { PositionedExpression t = p[j]; p[j] = p[j - 1]; p[j - 1] = t; j--; } else { break; } } } } a = -1.0; Expression[] e = new Expression[Expressions.Length]; int m = 0; for (int i = 0; i < n; i++) { if (p[i].TrackPosition != a) { a = p[i].TrackPosition; e[m] = new Expression(string.Empty, (a / UnitFactors[UnitFactors.Length - 1]).ToString(Culture), -1, -1, -1); m++; } e[m] = p[i].Expression; m++; } Array.Resize(ref e, m); Expressions = e; }
public static bool ReadMarkerXML(string fileName, ref CsvRwRouteParser.Marker marker) { //The current XML file to load XmlDocument currentXML = new XmlDocument(); //Load the marker's XML file currentXML.Load(fileName); string Path = System.IO.Path.GetDirectoryName(fileName); if (currentXML.DocumentElement != null) { bool iM = false; XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/TextMarker"); if (DocumentNodes == null || DocumentNodes.Count == 0) { DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/ImageMarker"); iM = true; } if (DocumentNodes == null || DocumentNodes.Count == 0) { Interface.AddMessage(Interface.MessageType.Error, false, "No marker nodes defined in XML file " + fileName); return(false); } marker = new CsvRwRouteParser.Marker(); foreach (XmlNode n in DocumentNodes) { if (n.HasChildNodes) { bool EarlyDefined = false, LateDefined = false; string EarlyText = null, Text = null, LateText = null; string[] Trains = null; Textures.Texture EarlyTexture = null, Texture = null, LateTexture = null; double EarlyTime = 0.0, LateTime = 0.0, TimeOut = Double.PositiveInfinity, EndingPosition = Double.PositiveInfinity; OpenBveApi.Colors.MessageColor EarlyColor = MessageColor.White, OnTimeColor = MessageColor.White, LateColor = MessageColor.White; foreach (XmlNode c in n.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "early": if (!c.HasChildNodes) { Interface.AddMessage(Interface.MessageType.Error, false, "No paramaters defined for the early message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": EarlyText = cc.InnerText; break; case "texture": var f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); if (System.IO.File.Exists(f)) { if (!Textures.RegisterTexture(f, out EarlyTexture)) { Interface.AddMessage(Interface.MessageType.Error, false, "Loading MessageEarlyTexture " + f + " failed."); } } else { Interface.AddMessage(Interface.MessageType.Error, false, "MessageEarlyTexture " + f + " does not exist."); } break; case "time": if (!Interface.TryParseTime(cc.InnerText, out EarlyTime)) { Interface.AddMessage(Interface.MessageType.Error, false, "Early message time invalid in " + fileName); } EarlyDefined = true; break; case "color": EarlyColor = ParseColor(cc.InnerText, fileName); break; } } break; case "ontime": if (!c.HasChildNodes) { Interface.AddMessage(Interface.MessageType.Error, false, "No paramaters defined for the on-time message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": Text = cc.InnerText; break; case "texture": var f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); if (System.IO.File.Exists(f)) { if (!Textures.RegisterTexture(f, out Texture)) { Interface.AddMessage(Interface.MessageType.Error, false, "Loading MessageTexture " + f + " failed."); } } else { Interface.AddMessage(Interface.MessageType.Error, false, "MessageTexture " + f + " does not exist."); } break; case "color": OnTimeColor = ParseColor(cc.InnerText, fileName); break; } } break; case "late": if (!c.HasChildNodes) { Interface.AddMessage(Interface.MessageType.Error, false, "No paramaters defined for the late message in " + fileName); } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "text": LateText = cc.InnerText; break; case "texture": var f = OpenBveApi.Path.CombineFile(Path, cc.InnerText); if (System.IO.File.Exists(f)) { if (!Textures.RegisterTexture(f, out LateTexture)) { Interface.AddMessage(Interface.MessageType.Error, false, "Loading MessageLateTexture " + f + " failed."); } } else { Interface.AddMessage(Interface.MessageType.Error, false, "MessageLateTexture " + f + " does not exist."); } break; case "time": if (!Interface.TryParseTime(cc.InnerText, out LateTime)) { Interface.AddMessage(Interface.MessageType.Error, false, "Early message time invalid in " + fileName); } LateDefined = true; break; case "color": LateColor = ParseColor(cc.InnerText, fileName); break; } } break; case "timeout": if (!NumberFormats.TryParseDouble(c.InnerText, new[] { 1.0 }, out TimeOut)) { Interface.AddMessage(Interface.MessageType.Error, false, "Marker timeout invalid in " + fileName); } break; case "distance": if (!NumberFormats.TryParseDouble(c.InnerText, new[] { 1.0 }, out EndingPosition)) { Interface.AddMessage(Interface.MessageType.Error, false, "Marker distance invalid in " + fileName); } break; case "trains": Trains = c.InnerText.Split(';'); break; } } //Check this marker is valid if (TimeOut == Double.PositiveInfinity && EndingPosition == Double.PositiveInfinity) { Interface.AddMessage(Interface.MessageType.Error, false, "No marker timeout or distance defined in marker XML " + fileName); return(false); } if (EndingPosition != Double.PositiveInfinity) { marker.EndingPosition = EndingPosition; } MessageManager.TextureMessage t = new MessageManager.TextureMessage(); MessageManager.GeneralMessage m = new MessageManager.GeneralMessage(); //Add variants if (EarlyDefined) { if (iM) { if (EarlyTexture != null) { t.MessageEarlyTime = EarlyTime; t.MessageEarlyTexture = EarlyTexture; } else { Interface.AddMessage(Interface.MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } else { if (EarlyText != null) { m.MessageEarlyTime = EarlyTime; m.MessageEarlyText = EarlyText; m.MessageColor = EarlyColor; } else { Interface.AddMessage(Interface.MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } } if (LateDefined) { if (iM) { if (LateTexture != null) { t.MessageLateTime = LateTime; t.MessageLateTexture = LateTexture; } else { Interface.AddMessage(Interface.MessageType.Warning, false, "A late time was defined, but no message was specified in MarkerXML " + fileName); } } else { if (LateText != null) { m.MessageLateTime = LateTime; m.MessageLateText = LateText; m.MessageLateColor = LateColor; } else { Interface.AddMessage(Interface.MessageType.Warning, false, "An early time was defined, but no message was specified in MarkerXML " + fileName); } } } //Final on-time message if (iM) { t.Trains = Trains; if (Texture != null) { t.MessageOnTimeTexture = Texture; } } else { m.Trains = Trains; if (Text != null) { m.MessageOnTimeText = Text; m.Color = OnTimeColor; } } if (iM) { marker.Message = t; } else { marker.Message = m; } } } } return(true); }