/// <summary>Loads a list of compatibility signal objects</summary> /// <param name="currentHost">The host application interface</param> /// <param name="fileName">The file name of the object list</param> /// <param name="objects">The returned array of speed limits</param> /// <param name="signalPost">Sets the default signal post</param> /// <param name="speedLimits">The array of signal speed limits</param> /// <returns>An array of compatability signal objects</returns> public static void ReadCompatibilitySignalXML(HostInterface currentHost, string fileName, out CompatibilitySignalObject[] objects, out UnifiedObject signalPost, out double[] speedLimits) { signalPost = new StaticObject(currentHost); objects = new CompatibilitySignalObject[9]; //Default Japanese speed limits converted to m/s speedLimits = new[] { 0.0, 6.94444444444444, 15.2777777777778, 20.8333333333333, double.PositiveInfinity, double.PositiveInfinity }; XmlDocument currentXML = new XmlDocument(); currentXML.Load(fileName); string currentPath = System.IO.Path.GetDirectoryName(fileName); if (currentXML.DocumentElement != null) { XmlNode node = currentXML.SelectSingleNode("/openBVE/CompatibilitySignals/SignalSetName"); if (node != null) { currentHost.AddMessage(MessageType.Information, false, "INFO: Using the " + node.InnerText + " compatibility signal set."); } XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/CompatibilitySignals/Signal"); if (DocumentNodes != null) { int index = 0; foreach (XmlNode nn in DocumentNodes) { List <StaticObject> objectList = new List <StaticObject>(); List <int> aspectList = new List <int>(); try { if (nn.HasChildNodes) { foreach (XmlNode n in nn.ChildNodes) { if (n.Name != "Aspect") { continue; } int aspect = 0; if (!NumberFormats.TryParseIntVb6(n.Attributes["Number"].Value, out aspect)) { currentHost.AddMessage(MessageType.Error, true, "Invalid aspect number " + aspect + " in the signal object list in the compatability signal file " + fileName); continue; } aspectList.Add(aspect); StaticObject staticObject = new StaticObject(currentHost); if (n.InnerText.ToLowerInvariant() != "null") { string objectFile = Path.CombineFile(currentPath, n.InnerText); if (File.Exists(objectFile)) { currentHost.LoadStaticObject(objectFile, Encoding.UTF8, false, out staticObject); } else { currentHost.AddMessage(MessageType.Error, true, "Compatibility signal file " + objectFile + " not found in " + fileName); } } objectList.Add(staticObject); } } } catch { currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName); } objects[index] = new CompatibilitySignalObject(aspectList.ToArray(), objectList.ToArray()); index++; } } string signalPostFile = Path.CombineFile(currentPath, "Japanese\\signal_post.csv"); //default plain post try { node = currentXML.SelectSingleNode("/openBVE/CompatibilitySignals/SignalPost"); if (node != null) { string newFile = Path.CombineFile(currentPath, node.InnerText); if (System.IO.File.Exists(newFile)) { signalPostFile = newFile; } } currentHost.LoadObject(signalPostFile, Encoding.UTF8, out signalPost); } catch { currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName); } DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/CompatibilitySignals/SpeedLimits"); if (DocumentNodes != null) { foreach (XmlNode nn in DocumentNodes) { try { if (nn.HasChildNodes) { foreach (XmlNode n in nn.ChildNodes) { if (n.Name != "Aspect") { continue; } int aspect = 0; if (n.Attributes != null) { if (!NumberFormats.TryParseIntVb6(n.Attributes["Number"].Value, out aspect)) { currentHost.AddMessage(MessageType.Error, true, "Invalid aspect number " + aspect + " in the speed limit list in the compatability signal file " + fileName); continue; } } if (aspect <= speedLimits.Length) { int l = speedLimits.Length; Array.Resize(ref speedLimits, aspect + 1); for (int i = l; i < speedLimits.Length; i++) { speedLimits[i] = double.PositiveInfinity; } if (!NumberFormats.TryParseDoubleVb6(n.InnerText, out speedLimits[aspect])) { speedLimits[aspect] = double.MaxValue; if (n.InnerText.ToLowerInvariant() != "unlimited") { currentHost.AddMessage(MessageType.Error, true, "Invalid speed limit provided for aspect " + aspect + " in the compatability signal file " + fileName); } } else { //convert to m/s as that's what we use internally speedLimits[aspect] *= 0.277777777777778; } } } } } catch { currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName); } } } } }
/// <summary>Attempts to load and parse the current train's panel configuration file.</summary> /// <param name="Train">The train</param> /// <param name="Encoding">The selected train encoding</param> internal void ParsePanelConfig(TrainBase Train, Encoding Encoding) { Train.Cars[Train.DriverCar].CarSections = new CarSection[1]; Train.Cars[Train.DriverCar].CarSections[0] = new CarSection(currentHost, ObjectType.Overlay, true); string File = Path.CombineFile(Train.TrainFolder, "panel.xml"); if (!System.IO.File.Exists(File)) { //Try animated variant too File = Path.CombineFile(Train.TrainFolder, "panel.animated.xml"); } if (System.IO.File.Exists(File)) { FileSystem.AppendToLogFile("Loading train panel: " + File); try { /* * First load the XML. We use this to determine * whether this is a 2D or a 3D animated panel */ XDocument CurrentXML = XDocument.Load(File, LoadOptions.SetLineInfo); // Check for null if (CurrentXML.Root != null) { IEnumerable <XElement> DocumentElements = CurrentXML.Root.Elements("PanelAnimated"); if (DocumentElements.Any()) { PanelAnimatedXmlParser.ParsePanelAnimatedXml(System.IO.Path.GetFileName(File), Train, Train.DriverCar); if (Train.Cars[Train.DriverCar].CameraRestrictionMode != CameraRestrictionMode.Restricted3D) { Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.NotAvailable; } return; } DocumentElements = CurrentXML.Root.Elements("Panel"); if (DocumentElements.Any()) { PanelXmlParser.ParsePanelXml(System.IO.Path.GetFileName(File), Train, Train.DriverCar); Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; return; } } } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", "panel.xml"); currentHost.ReportProblem(ProblemType.InvalidData, currentError); Cancel = true; return; } currentHost.AddMessage(MessageType.Error, false, "The panel.xml file " + File + " failed to load. Falling back to legacy panel."); } else { File = Path.CombineFile(Train.TrainFolder, "panel.animated"); if (System.IO.File.Exists(File)) { FileSystem.AppendToLogFile("Loading train panel: " + File); if (System.IO.File.Exists(Path.CombineFile(Train.TrainFolder, "panel2.cfg")) || System.IO.File.Exists(Path.CombineFile(Train.TrainFolder, "panel.cfg"))) { FileSystem.AppendToLogFile("INFO: This train contains both a 2D and a 3D panel. The 3D panel will always take precedence"); } UnifiedObject currentObject; currentHost.LoadObject(File, Encoding, out currentObject); var a = currentObject as AnimatedObjectCollection; if (a != null) { //HACK: If a == null , loading our animated object completely failed (Missing objects?). Fallback to trying the panel2.cfg try { for (int i = 0; i < a.Objects.Length; i++) { currentHost.CreateDynamicObject(ref a.Objects[i].internalObject); } Train.Cars[Train.DriverCar].CarSections[0].Groups[0].Elements = a.Objects; if (Train.Cars[Train.DriverCar].CameraRestrictionMode != CameraRestrictionMode.Restricted3D) { Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.NotAvailable; Renderer.Camera.CurrentRestriction = CameraRestrictionMode.NotAvailable; } return; } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", "panel.animated"); currentHost.ReportProblem(ProblemType.InvalidData, currentError); Cancel = true; return; } } currentHost.AddMessage(MessageType.Error, false, "The panel.animated file " + File + " failed to load. Falling back to 2D panel."); } } var Panel2 = false; try { File = Path.CombineFile(Train.TrainFolder, "panel2.cfg"); if (System.IO.File.Exists(File)) { FileSystem.AppendToLogFile("Loading train panel: " + File); Panel2 = true; Panel2CfgParser.ParsePanel2Config("panel2.cfg", Train.TrainFolder, Train.Cars[Train.DriverCar]); Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; } else { File = Path.CombineFile(Train.TrainFolder, "panel.cfg"); if (System.IO.File.Exists(File)) { FileSystem.AppendToLogFile("Loading train panel: " + File); PanelCfgParser.ParsePanelConfig(Train.TrainFolder, Encoding, Train.Cars[Train.DriverCar]); Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; } else { Renderer.Camera.CurrentRestriction = CameraRestrictionMode.NotAvailable; } } } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", Panel2 ? "panel2.cfg" : "panel.cfg"); currentHost.ReportProblem(ProblemType.InvalidData, currentError); Cancel = true; } }