public Triggers(STFReader stf) { stf.MustMatch("("); int count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("dist_travelled_trigger", () => { Add(new Dist_Travelled_Trigger(stf)); }), new STFReader.TokenProcessor("discrete_trigger", () => { Add(new Discrete_Trigger(stf)); }), new STFReader.TokenProcessor("random_trigger", () => { Add(new Random_Trigger(stf)); }), new STFReader.TokenProcessor("variable_trigger", () => { Add(new Variable_Trigger(stf)); }), new STFReader.TokenProcessor("initial_trigger", () => { Add(new Initial_Trigger(stf)); }), }); foreach (Trigger trigger in this) { if (trigger.SoundCommand == null) { STFException.TraceWarning(stf, "Trigger lacks a sound command"); } } }
static IList <SignalDrawLight> ReadDrawLights(STFReader stf) { stf.MustMatch("("); int count = stf.ReadInt(null); List <SignalDrawLight> drawLights = new List <SignalDrawLight>(count); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("drawlight", () => { if (drawLights.Count >= drawLights.Capacity) { STFException.TraceWarning(stf, "Skipped extra DrawLight"); } else { drawLights.Add(new SignalDrawLight(stf)); } }), }); return(drawLights); }
public Traffic_Service_Definition(STFReader stf) { var arrivalTime = 0; var departTime = 0; var skipCount = 0; var distanceDownPath = 0F; var platformStartID = 0; stf.MustMatch("("); Service_Definition = stf.ReadString(); Time = stf.ReadInt(null); // Cannot use stt.ReadFloat(STFReader.UNITS.Time, null) as number will be followed by "arrivaltime" stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("arrivaltime", () => { arrivalTime = (int)stf.ReadFloatBlock(STFReader.UNITS.Time, null); }), new STFReader.TokenProcessor("departtime", () => { departTime = (int)stf.ReadFloatBlock(STFReader.UNITS.Time, null); }), new STFReader.TokenProcessor("skipcount", () => { skipCount = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("distancedownpath", () => { distanceDownPath = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }), new STFReader.TokenProcessor("platformstartid", () => { platformStartID = stf.ReadIntBlock(null); TrafficDetails.Add(new Traffic_Traffic_Item(arrivalTime, departTime, skipCount, distanceDownPath, platformStartID)); }), }); }
internal ServiceTraffics(STFReader stf) { int arrivalTime = 0; int departTime = 0; int skipCount = 0; float distanceDownPath = 0f; int platformStartID = 0; stf.MustMatchBlockStart(); Name = stf.ReadString(); Time = stf.ReadInt(null); // Cannot use stt.ReadFloat(STFReader.Units.Time, null) as number will be followed by "arrivaltime" stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("arrivaltime", () => { arrivalTime = (int)stf.ReadFloatBlock(STFReader.Units.Time, null); }), new STFReader.TokenProcessor("departtime", () => { departTime = (int)stf.ReadFloatBlock(STFReader.Units.Time, null); }), new STFReader.TokenProcessor("skipcount", () => { skipCount = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("distancedownpath", () => { distanceDownPath = stf.ReadFloatBlock(STFReader.Units.Distance, null); }), new STFReader.TokenProcessor("platformstartid", () => { platformStartID = stf.ReadIntBlock(null); Add(new ServiceTrafficItem(arrivalTime, departTime, skipCount, distanceDownPath, platformStartID, this)); }), }); }
public Light(int index, STFReader stf) { Index = index; stf.MustMatch("("); stf.ParseBlock(new[] { new STFReader.TokenProcessor("type", () => { Type = (LightType)stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("conditions", () => { stf.MustMatch("("); stf.ParseBlock(new[] { new STFReader.TokenProcessor("headlight", () => { Headlight = (LightHeadlightCondition)stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("unit", () => { Unit = (LightUnitCondition)stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("penalty", () => { Penalty = (LightPenaltyCondition)stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("control", () => { Control = (LightControlCondition)stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("service", () => { Service = (LightServiceCondition)stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("timeofday", () => { TimeOfDay = (LightTimeOfDayCondition)stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("weather", () => { Weather = (LightWeatherCondition)stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("coupling", () => { Coupling = (LightCouplingCondition)stf.ReadIntBlock(null); }), }); }), new STFReader.TokenProcessor("cycle", () => { Cycle = 0 != stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("fadein", () => { FadeIn = stf.ReadFloatBlock(STFReader.UNITS.None, null); }), new STFReader.TokenProcessor("fadeout", () => { FadeOut = stf.ReadFloatBlock(STFReader.UNITS.None, null); }), new STFReader.TokenProcessor("states", () => { stf.MustMatch("("); var count = stf.ReadInt(null); stf.ParseBlock(new[] { new STFReader.TokenProcessor("state", () => { if (States.Count >= count) { STFException.TraceWarning(stf, "Skipped extra State"); } else { States.Add(new LightState(stf)); } }), }); if (States.Count < count) { STFException.TraceWarning(stf, (count - States.Count).ToString() + " missing State(s)"); } }), }); }
private static void ReadOrtsSignalFunctionTypes(STFReader stf) { stf.MustMatchBlockStart(); int count = stf.ReadInt(null); int tokensRead = 0; stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("ortssignalfunctiontype", () => { stf.MustMatchBlockStart(); if (tokensRead >= count) { STFException.TraceWarning(stf, "Skipped extra ORTSFunctionType"); } else { string functionType = stf.ReadString(); // check agains default types if (EnumExtension.GetValue(functionType, out SignalFunction result)) { STFException.TraceWarning(stf, "Invalid definition of ORTSFunctionType, type is equal to MSTS defined type : " + functionType); } else if (functionType.StartsWith("OR_", StringComparison.OrdinalIgnoreCase) || functionType.StartsWith("ORTS", StringComparison.OrdinalIgnoreCase)) { STFException.TraceWarning(stf, "Invalid definition of ORTSFunctionType, using reserved type name : " + functionType); } else { if (OrSignalTypes.Instance.FunctionTypes.Contains(functionType, StringComparer.OrdinalIgnoreCase)) { STFException.TraceWarning(stf, "Skipped duplicate ORTSSignalFunction definition : " + functionType); } else { OrSignalTypes.Instance.FunctionTypes.Add(functionType); tokensRead++; } } } stf.SkipRestOfBlock(); }), });
public LightCollection(STFReader stf) { stf.MustMatch("("); stf.ReadInt(null); // count; ignore this because its not always correct stf.ParseBlock(new[] { new STFReader.TokenProcessor("light", () => { Lights.Add(new Light(Lights.Count, stf)); }), }); if (Lights.Count == 0) { throw new InvalidDataException("lights with no lights"); } // MSTSBin created reverse headlight cones automatically, so we shall do so too. foreach (var light in Lights.ToArray()) { if (light.Type == LightType.Cone) { Lights.Add(new Light(light, true)); } } }
public TurntableFile(string filePath, string shapePath, List <MovingTable> movingTables, Simulator simulator) { if (!File.Exists(filePath)) { return; } Trace.Write(" TURNTBL"); using (STFReader stf = new STFReader(filePath, false)) { var count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("turntable", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra Turntable"); } else { movingTables.Add(new Turntable(stf, simulator)); } }), new STFReader.TokenProcessor("transfertable", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra Transfertable"); } else { movingTables.Add(new Transfertable(stf, simulator)); } }), }); if (count > 0) { STFException.TraceWarning(stf, count + " missing Turntable(s)"); } } }
public SMSStreams(STFReader stf) { stf.MustMatch("("); var count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("stream", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra Stream"); } else { Add(new SMSStream(stf)); } }), }); if (count > 0) { STFException.TraceWarning(stf, count + " missing Stream(s)"); } }
private void TryModify(int category, STFReader stf) { ActivityEvent origEvent; bool wrongEventID = false; int modifiedID = -1; try { stf.MustMatchBlockStart(); stf.MustMatch("id"); stf.MustMatchBlockStart(); modifiedID = stf.ReadInt(null); stf.MustMatchBlockEnd(); origEvent = Find(x => x.ID == modifiedID); if (origEvent == null) { wrongEventID = true; Trace.TraceWarning("Skipped event {0} not present in base activity file", modifiedID); stf.SkipRestOfBlock(); } else { wrongEventID = !TestMatch(category, origEvent); if (!wrongEventID) { origEvent.Update(stf); } else { Trace.TraceWarning("Skipped event {0} of event category not matching with base activity file", modifiedID); stf.SkipRestOfBlock(); } } } catch (Exception error) { Trace.WriteLine(new FileLoadException("Error in additional activity file", error)); } }
public TurntableFile(string filePath, string shapePath, List <Turntable> turntables, Simulator simulator) { using (STFReader stf = new STFReader(filePath, false)) { var count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("turntable", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra Turntable"); } else { turntables.Add(new Turntable(stf, simulator)); } }), }); if (count > 0) { STFException.TraceWarning(stf, count + " missing Turntable(s)"); } } }
public TrackTypesFile(string fileName) { using (STFReader stf = new STFReader(fileName, false)) { var count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("tracktype", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra TrackType"); } else { Add(new TrackType(stf)); } }), }); if (count > 0) { STFException.TraceWarning(stf, count + " missing TrackType(s)"); } } }
public CarSpawnerBlock(STFReader stf, string shapePath, List <CarSpawnerList> carSpawnerLists, string listName) { var spawnerDataItems = new List <CarSpawnerItemData>(); { var count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("ignorexrotation", () => { IgnoreXRotation = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("carspawneritem", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra CarSpawnerItem"); } else { var dataItem = new CarSpawnerItemData(stf, shapePath); if (File.Exists(dataItem.name)) { spawnerDataItems.Add(dataItem); } else { STFException.TraceWarning(stf, String.Format("Non-existent shape file {0} referenced", dataItem.name)); } } }), }); if (count > 0) { STFException.TraceWarning(stf, count + " missing CarSpawnerItem(s)"); } } CarSpawnerList carSpawnerList = new CarSpawnerList(spawnerDataItems, listName, IgnoreXRotation); carSpawnerLists.Add(carSpawnerList); }
public CabViewControls(STFReader stf, string basepath) { stf.MustMatch("("); int count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("dial", () => { Add(new CVCDial(stf, basepath)); }), new STFReader.TokenProcessor("gauge", () => { Add(new CVCGauge(stf, basepath)); }), new STFReader.TokenProcessor("lever", () => { Add(new CVCDiscrete(stf, basepath)); }), new STFReader.TokenProcessor("twostate", () => { Add(new CVCDiscrete(stf, basepath)); }), new STFReader.TokenProcessor("tristate", () => { Add(new CVCDiscrete(stf, basepath)); }), new STFReader.TokenProcessor("multistatedisplay", () => { Add(new CVCMultiStateDisplay(stf, basepath)); }), new STFReader.TokenProcessor("cabsignaldisplay", () => { Add(new CVCSignal(stf, basepath)); }), new STFReader.TokenProcessor("digital", () => { Add(new CVCDigital(stf, basepath)); }), new STFReader.TokenProcessor("combinedcontrol", () => { Add(new CVCDiscrete(stf, basepath)); }), new STFReader.TokenProcessor("firebox", () => { Add(new CVCFirebox(stf, basepath)); }), new STFReader.TokenProcessor("digitalclock", () => { Add(new CVCDigitalClock(stf, basepath)); }) }); //TODO Uncomment when parsed all type /* * if (count != this.Count) STFException.ReportWarning(inf, "CabViewControl count mismatch"); */ }
/// <summary> /// Default constructor used during file parsing. /// </summary> /// <param name="stf">The STFreader containing the file stream</param> public SignalDrawLight(STFReader stf) { stf.MustMatchBlockStart(); Index = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("signalflags", () => { stf.MustMatchBlockStart(); while (!stf.EndOfBlock()) { switch (stf.ReadString().ToLower()) { case "flashing": Flashing = true; break; default: stf.StepBackOneItem(); STFException.TraceInformation(stf, "Skipped unknown DrawLight flag " + stf.ReadString()); break; } } }), }); }
public Lights(STFReader stf) { stf.MustMatchBlockStart(); stf.ReadInt(null); // count; ignore this because its not always correct stf.ParseBlock(new[] { new STFReader.TokenProcessor("light", () => { Add(new Light(Count, stf)); }), }); if (Count == 0) { throw new InvalidDataException("lights with no lights"); } // MSTSBin created reverse headlight cones automatically, so we shall do so too. List <Light> reverseLights = new List <Light>(); foreach (var light in this) { if (light.Type == LightType.Cone) { reverseLights.Add(new Light(light, true)); } } this.AddRange(reverseLights); }
} // true for humans public CarSpawners(STFReader stf, string shapePath, string listName) { if (null == stf) { throw new ArgumentNullException(nameof(stf)); } ListName = listName; int count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("ignorexrotation", () => { IgnoreXRotation = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("carspawneritem", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra CarSpawnerItem"); } else { CarSpawner dataItem = new CarSpawner(stf, shapePath); if (File.Exists(dataItem.Name)) { Add(dataItem); } else { STFException.TraceWarning(stf, $"Non-existent shape file {dataItem.Name} referenced"); } } }), }); if (count > 0) { STFException.TraceWarning(stf, count + " missing CarSpawnerItem(s)"); } }
/// <summary> /// Parses all the parameters within the ENG file /// </summary> /// <param name="stf">eference to the ENG file reader</param> public void Parse(STFReader stf, MSTSDieselLocomotive loco) { stf.MustMatch("("); int count = stf.ReadInt(0); for (int i = 0; i < count; i++) { string setting = stf.ReadString().ToLower(); if (setting == "diesel") { DEList.Add(new DieselEngine()); DEList[i].Parse(stf, loco); DEList[i].Initialize(true); } if ((!DEList[i].IsInitialized)) { STFException.TraceWarning(stf, "Diesel engine model has some errors - loading MSTS format"); DEList[i].InitFromMSTS((MSTSDieselLocomotive)Locomotive); DEList[i].Initialize(true); } } }
public void Parse(string lowercasetoken, STFReader stf) { switch (lowercasetoken) { case "engine(trainbrakescontrollermaxsystempressure": case "engine(enginebrakescontrollermaxsystempressure": MaxPressurePSI = stf.ReadFloatBlock(STFReader.Units.PressureDefaultPSI, null); break; case "engine(trainbrakescontrollermaxreleaserate": case "engine(enginebrakescontrollermaxreleaserate": ReleaseRatePSIpS = stf.ReadFloatBlock(STFReader.Units.PressureRateDefaultPSIpS, null); break; case "engine(trainbrakescontrollermaxquickreleaserate": case "engine(enginebrakescontrollermaxquickreleaserate": QuickReleaseRatePSIpS = stf.ReadFloatBlock(STFReader.Units.PressureRateDefaultPSIpS, null); break; case "engine(trainbrakescontrollermaxapplicationrate": case "engine(enginebrakescontrollermaxapplicationrate": ApplyRatePSIpS = stf.ReadFloatBlock(STFReader.Units.PressureRateDefaultPSIpS, null); break; case "engine(trainbrakescontrolleremergencyapplicationrate": case "engine(enginebrakescontrolleremergencyapplicationrate": EmergencyRatePSIpS = stf.ReadFloatBlock(STFReader.Units.PressureRateDefaultPSIpS, null); break; case "engine(trainbrakescontrollerfullservicepressuredrop": case "engine(enginebrakescontrollerfullservicepressuredrop": FullServReductionPSI = stf.ReadFloatBlock(STFReader.Units.PressureDefaultPSI, null); break; case "engine(trainbrakescontrollerminpressurereduction": case "engine(enginebrakescontrollerminpressurereduction": MinReductionPSI = stf.ReadFloatBlock(STFReader.Units.PressureDefaultPSI, null); break; case "engine(enginecontrollers(brake_train": case "engine(enginecontrollers(brake_engine": stf.MustMatch("("); MinimumValue = stf.ReadFloat(STFReader.Units.None, null); MaximumValue = stf.ReadFloat(STFReader.Units.None, null); StepSize = stf.ReadFloat(STFReader.Units.None, null); CurrentValue = stf.ReadFloat(STFReader.Units.None, null); string token = stf.ReadItem(); // s/b numnotches if (string.Compare(token, "NumNotches", true) != 0) // handle error in gp38.eng where extra parameter provided before NumNotches statement { stf.ReadItem(); } stf.MustMatch("("); stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("notch", () => { stf.MustMatch("("); float value = stf.ReadFloat(STFReader.Units.None, null); int smooth = stf.ReadInt(null); string type = stf.ReadString(); Notches.Add(new MSTSNotch(value, smooth, type, stf)); if (type != ")") { stf.SkipRestOfBlock(); } }), }); break; case "engine(ortstrainbrakecontroller": case "engine(ortsenginebrakecontroller": if (Locomotive.Train as AITrain == null) { ScriptName = stf.ReadStringBlock(null); } break; } }
/// <summary> /// Reads RailDriver calibration data from a ModernCalibration.rdm file /// This file is not in the usual STF format, but the STFReader can handle it okay. /// </summary> /// <param name="basePath"></param> void ReadCalibrationData(string basePath) { string file = basePath + "\\ModernCalibration.rdm"; if (!File.Exists(file)) { RegistryKey RK = Registry.LocalMachine.OpenSubKey("SOFTWARE\\PI Engineering\\PIBUS"); if (RK != null) { string dir = (string)RK.GetValue("RailDriver", null, RegistryValueOptions.None); if (dir != null) { file = dir + "\\..\\controller\\ModernCalibration.rdm"; } } if (!File.Exists(file)) { SetLEDs(0, 0, 0); Trace.TraceWarning("Cannot find RailDriver calibration file {0}", file); return; } } // TODO: This is... kinda weird and cool at the same time. STF parsing being used on RailDriver's calebration file. Probably should be a dedicated parser, though. STFReader reader = new STFReader(file, false); while (!reader.Eof) { string token = reader.ReadItem(); if (token == "Position") { string name = reader.ReadItem(); int min = -1; int max = -1; while (token != "}") { token = reader.ReadItem(); if (token == "Min") { min = reader.ReadInt(-1); } else if (token == "Max") { max = reader.ReadInt(-1); } } if (min >= 0 && max >= 0) { float v = .5f * (min + max); switch (name) { case "Full Reversed": FullReversed = v; break; case "Neutral": Neutral = v; break; case "Full Forward": FullForward = v; break; case "Full Throttle": FullThrottle = v; break; case "Throttle Idle": ThrottleIdle = v; break; case "Dynamic Brake": DynamicBrake = v; break; case "Dynamic Brake Setup": DynamicBrakeSetup = v; break; case "Auto Brake Released": AutoBrakeRelease = v; break; case "Full Auto Brake (CS)": FullAutoBrake = v; break; case "Emergency Brake (EMG)": EmergencyBrake = v; break; case "Independent Brake Released": IndependentBrakeRelease = v; break; case "Bail Off Engaged (in Released position)": BailOffEngagedRelease = v; break; case "Independent Brake Full": IndependentBrakeFull = v; break; case "Bail Off Engaged (in Full position)": BailOffEngagedFull = v; break; case "Bail Off Disengaged (in Released position)": BailOffDisengagedRelease = v; break; case "Bail Off Disengaged (in Full position)": BailOffDisengagedFull = v; break; case "Rotary Switch 1-Position 1(OFF)": Rotary1Position1 = v; break; case "Rotary Switch 1-Position 2(SLOW)": Rotary1Position2 = v; break; case "Rotary Switch 1-Position 3(FULL)": Rotary1Position3 = v; break; case "Rotary Switch 2-Position 1(OFF)": Rotary2Position1 = v; break; case "Rotary Switch 2-Position 2(DIM)": Rotary2Position2 = v; break; case "Rotary Switch 2-Position 3(FULL)": Rotary2Position3 = v; break; default: STFException.TraceInformation(reader, "Skipped unknown calibration value " + name); break; } } } } }
/// <summary> /// Parse the wag file parameters required for the simulator and viewer classes /// </summary> public override void Parse(string lowercasetoken, STFReader stf) { switch (lowercasetoken) { case "engine(dieselengineidlerpm": IdleRPM = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "engine(dieselenginemaxrpm": MaxRPM = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "engine(dieselenginemaxrpmchangerate": MaxRPMChangeRate = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "engine(ortsdieselenginemaxpower": MaximumDieselEnginePowerW = stf.ReadFloatBlock(STFReader.UNITS.Power, null); break; case "engine(effects(dieselspecialeffects": ParseEffects(lowercasetoken, stf); break; case "engine(dieselsmokeeffectinitialsmokerate": InitialExhaust = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "engine(dieselsmokeeffectinitialmagnitude": InitialMagnitude = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "engine(dieselsmokeeffectmaxsmokerate": MaxExhaust = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "engine(dieselsmokeeffectmaxmagnitude": MaxMagnitude = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "engine(ortsdieselengines": DieselEngines = new DieselEngines(this, stf); break; case "engine(maxdiesellevel": MaxDieselLevelL = stf.ReadFloatBlock(STFReader.UNITS.Volume, null); break; case "engine(dieselusedperhouratmaxpower": DieselUsedPerHourAtMaxPowerL = stf.ReadFloatBlock(STFReader.UNITS.Volume, null); break; case "engine(dieselusedperhouratidle": DieselUsedPerHourAtIdleL = stf.ReadFloatBlock(STFReader.UNITS.Volume, null); break; case "engine(maxoilpressure": DieselMaxOilPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, 120f); break; case "engine(ortsminoilpressure": DieselMinOilPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, 40f); break; case "engine(maxtemperature": DieselMaxTemperatureDeg = stf.ReadFloatBlock(STFReader.UNITS.TemperatureDifference, 100f); break; case "engine(ortsdieselcooling": DieselEngineCooling = (DieselEngine.Cooling)stf.ReadInt((int)DieselEngine.Cooling.Proportional); break; default: GearBox.Parse(lowercasetoken, stf); base.Parse(lowercasetoken, stf); break; } if (IdleRPM != 0 && MaxRPM != 0 && MaxRPMChangeRate != 0) { PercentChangePerSec = MaxRPMChangeRate / (MaxRPM - IdleRPM); EngineRPM = IdleRPM; } }
internal RouteStart(STFReader stf) { stf.MustMatchBlockStart(); location = new WorldLocation(stf.ReadInt(null), stf.ReadInt(null), stf.ReadFloat(null), 0f, stf.ReadFloat(null)); stf.SkipRestOfBlock(); }
protected virtual void ParseJustification(STFReader stf) { stf.MustMatch("("); Justification = stf.ReadInt(3); stf.SkipRestOfBlock(); }
public ENVFileSkyLayer(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("world_sky_layer_fadein", () => { stf.MustMatch("("); Fadein_Begin_Time = stf.ReadString(); Fadein_End_Time = stf.ReadString(); stf.SkipRestOfBlock(); }), new STFReader.TokenProcessor("world_anim_shader", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("world_anim_shader_frames", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("world_anim_shader_frame", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("world_anim_shader_frame_uvtiles", () => { stf.MustMatch("("); TileX = stf.ReadFloat(STFReader.UNITS.Any, 1.0f); TileY = stf.ReadFloat(STFReader.UNITS.Any, 1.0f); stf.ParseBlock(new STFReader.TokenProcessor[] { }); }), }); }), }); }), new STFReader.TokenProcessor("world_shader", () => { stf.MustMatch("("); TextureMode = stf.ReadString(); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("terrain_texslots", () => { stf.MustMatch("("); stf.ReadInt(null) /*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("terrain_texslot", () => { stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }), }); }), }); }), }); }), }); }
public ENVFileWaterLayer(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("world_water_layer_height", () => { Height = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }), new STFReader.TokenProcessor("world_anim_shader", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("world_shader", () => { stf.MustMatch("("); stf.ReadString() /*TextureMode*/; stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("terrain_texslots", () => { stf.MustMatch("("); stf.ReadInt(null) /*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("terrain_texslot", () => { stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }), }); }), }); }), }); }), }); }
public static Interpolator2D CreateInterpolator2D(this STFReader stf, bool tab) { List <double> xlist = new List <double>(); List <Interpolator> ilist = new List <Interpolator>(); bool errorFound = false; if (tab) { stf.MustMatchBlockStart(); int numOfRows = stf.ReadInt(0); if (numOfRows < 2) { STFException.TraceWarning(stf, "Interpolator must have at least two rows."); errorFound = true; } int numOfColumns = stf.ReadInt(0); string header = stf.ReadString().ToLower(); if (header == "throttle") { stf.MustMatchBlockStart(); int numOfThrottleValues = 0; while (!stf.EndOfBlock()) { xlist.Add(stf.ReadFloat(STFReader.Units.None, 0f)); ilist.Add(new Interpolator(numOfRows)); numOfThrottleValues++; } if (numOfThrottleValues != (numOfColumns - 1)) { STFException.TraceWarning(stf, "Interpolator throttle vs. num of columns mismatch."); errorFound = true; } if (numOfColumns < 3) { STFException.TraceWarning(stf, "Interpolator must have at least three columns."); errorFound = true; } int numofData = 0; string tableLabel = stf.ReadString().ToLower(); if (tableLabel == "table") { stf.MustMatchBlockStart(); for (int i = 0; i < numOfRows; i++) { float x = stf.ReadFloat(STFReader.Units.SpeedDefaultMPH, 0); numofData++; for (int j = 0; j < numOfColumns - 1; j++) { if (j >= ilist.Count) { STFException.TraceWarning(stf, "Interpolator throttle vs. num of columns mismatch. (missing some throttle values)"); errorFound = true; } ilist[j][x] = stf.ReadFloat(STFReader.Units.Force, 0); numofData++; } } stf.SkipRestOfBlock(); } else { STFException.TraceWarning(stf, "Interpolator didn't find a table to load."); errorFound = true; } //check the table for inconsistencies foreach (Interpolator checkMe in ilist) { if (checkMe.Size != numOfRows) { STFException.TraceWarning(stf, "Interpolator has found a mismatch between num of rows declared and num of rows given."); errorFound = true; } double dx = (checkMe.MaxX() - checkMe.MinX()) * 0.1f; if (dx <= 0f) { STFException.TraceWarning(stf, "Interpolator has found X data error - x values must be increasing. (Possible row number mismatch)"); errorFound = true; } else { for (double x = checkMe.MinX(); x <= checkMe.MaxX(); x += dx) { if (double.IsNaN(checkMe[x])) { STFException.TraceWarning(stf, "Interpolator has found X data error - x values must be increasing. (Possible row number mismatch)"); errorFound = true; break; } } } } if (numofData != (numOfRows * numOfColumns)) { STFException.TraceWarning(stf, "Interpolator has found a mismatch: num of data doesn't fit the header information."); errorFound = true; } } else { STFException.TraceWarning(stf, "Interpolator must have a 'throttle' header row."); errorFound = true; } stf.SkipRestOfBlock(); } else { stf.MustMatchBlockStart(); while (!stf.EndOfBlock()) { xlist.Add(stf.ReadFloat(STFReader.Units.Any, null)); ilist.Add(stf.CreateInterpolator()); } } int n = xlist.Count; if (n < 2) { STFException.TraceWarning(stf, "Interpolator must have at least two x values."); errorFound = true; } double[] xArray = new double[n]; Interpolator[] yArray = new Interpolator[n]; for (int i = 0; i < n; i++) { xArray[i] = xlist[i]; yArray[i] = ilist[i]; if (i > 0 && xArray[i - 1] >= xArray[i]) { STFException.TraceWarning(stf, "Interpolator x values must be increasing."); } } if (errorFound) { STFException.TraceWarning(stf, "Errors found in the Interpolator definition!!! The Interpolator will not work correctly!"); } Interpolator2D result = new Interpolator2D(xArray, yArray); return(result); }
public DisableTrigger(STFReader f) { f.MustMatch("("); TriggerID = f.ReadInt(null); f.SkipRestOfBlock(); }
public override int ReadInt() { return(stf.ReadInt(null)); }
public ENVFileSkySatellite(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("world_anim_shader", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("world_shader", () => { stf.MustMatch("("); TextureMode = stf.ReadString(); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("terrain_texslots", () => { stf.MustMatch("("); stf.ReadInt(null) /*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("terrain_texslot", () => { stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }), }); }), }); }), }); }), }); }
public CVCDiscrete(STFReader stf, string basepath) { // try { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("type", () => { ParseType(stf); }), new STFReader.TokenProcessor("position", () => { ParsePosition(stf); }), new STFReader.TokenProcessor("scalerange", () => { ParseScaleRange(stf); }), new STFReader.TokenProcessor("graphic", () => { ParseGraphic(stf, basepath); }), new STFReader.TokenProcessor("style", () => { ParseStyle(stf); }), new STFReader.TokenProcessor("units", () => { ParseUnits(stf); }), new STFReader.TokenProcessor("mousecontrol", () => { MouseControl = stf.ReadBoolBlock(false); }), new STFReader.TokenProcessor("orientation", () => { Orientation = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("dirincrease", () => { Direction = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("numframes", () => { stf.MustMatch("("); FramesCount = stf.ReadInt(null); FramesX = stf.ReadInt(null); FramesY = stf.ReadInt(null); stf.SkipRestOfBlock(); }), // <CJComment> Would like to revise this, as it is difficult to follow and debug. // Can't do that until interaction of ScaleRange, NumFrames, NumPositions and NumValues is more fully specified. // What is needed is samples of data that must be accommodated. // Some decisions appear unwise but they might be a pragmatic solution to a real problem. </CJComment> // // Code accommodates: // - NumValues before NumPositions or the other way round. // - More NumValues than NumPositions and the other way round - perhaps unwise. // - The count of NumFrames, NumValues and NumPositions is ignored - perhaps unwise. // - Abbreviated definitions so that values at intermediate unspecified positions can be omitted. // Strangely, these values are set to 0 and worked out later when drawing. // Max and min NumValues which don't match the ScaleRange are ignored - perhaps unwise. new STFReader.TokenProcessor("numpositions", () => { stf.MustMatch("("); // If Positions are not filled before by Values bool shouldFill = (Positions.Count == 0); numPositions = stf.ReadInt(null); // Number of Positions var minPosition = 0; var positionsRead = 0; while (!stf.EndOfBlock()) { int p = stf.ReadInt(null); minPosition = positionsRead == 0 ? p : Math.Min(minPosition, p); // used to get correct offset positionsRead++; // If Positions are not filled before by Values if (shouldFill) { Positions.Add(p); } } // If positions do not start at 0, add offset to shift them all so they do. // An example of this is RENFE 400 (from http://www.trensim.com/lib/msts/index.php?act=view&id=186) // which has a COMBINED_CONTROL with: // NumPositions ( 21 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 ) // Also handles definitions with position in reverse order, e.g. // NumPositions ( 5 8 7 2 1 0 ) positionsRead++; if (minPosition < 0) { for (int iPos = 0; iPos <= Positions.Count - 1; iPos++) { Positions[iPos] -= minPosition; } } // This is a hack for SLI locomotives which have the positions listed as "1056964608 0 0 0 ...". if (Positions.Any(p => p > 0xFFFF)) { STFException.TraceInformation(stf, "Renumbering cab control positions from zero due to value > 0xFFFF"); for (var i = 0; i < Positions.Count; i++) { Positions[i] = i; } } // Check if eligible for filling if (Positions.Count > 1 && Positions[0] != 0) { canFill = false; } else { for (var iPos = 1; iPos <= Positions.Count - 1; iPos++) { if (Positions[iPos] > Positions[iPos - 1]) { continue; } canFill = false; break; } } // This is a protection against GP40 locomotives that erroneously have positions pointing beyond frame count limit. if (Positions.Count > 1 && canFill && Positions.Count < FramesCount && Positions[Positions.Count - 1] >= FramesCount && Positions[0] == 0) { STFException.TraceInformation(stf, "Some NumPositions entries refer to non-exisiting frames, trying to renumber"); Positions[Positions.Count - 1] = FramesCount - 1; for (var iPos = Positions.Count - 2; iPos >= 1; iPos--) { if ((Positions[iPos] >= FramesCount || Positions[iPos] >= Positions[iPos + 1])) { Positions[iPos] = Positions[iPos + 1] - 1; } else { break; } } } }), new STFReader.TokenProcessor("numvalues", () => { stf.MustMatch("("); var numValues = stf.ReadDouble(null); // Number of Values while (!stf.EndOfBlock()) { double v = stf.ReadDouble(null); // If the Positions are less than expected add new Position(s) while (Positions.Count <= _ValuesRead) { Positions.Add(_ValuesRead); } // Avoid later repositioning, put every value to its Position // But before resize Values if needed if (numValues != numPositions) { while (Values.Count <= Positions[_ValuesRead]) { Values.Add(0); } // Avoid later repositioning, put every value to its Position Values[Positions[_ValuesRead]] = v; } Values.Add(v); _ValuesRead++; } }), }); // If no ACE, just don't need any fixup // Because Values are tied to the image Frame to be shown if (string.IsNullOrEmpty(ACEFile)) { return; } // Now, we have an ACE. // If read any Values, or the control requires Values to control // The twostate, tristate, signal displays are not in these // Need check the Values collection for validity if (_ValuesRead > 0 || ControlStyle == CABViewControlStyles.SPRUNG || ControlStyle == CABViewControlStyles.NOT_SPRUNG || FramesCount > 0 || (FramesX > 0 && FramesY > 0)) { // Check max number of Frames if (FramesCount == 0) { // Check valid Frame information if (FramesX == 0 || FramesY == 0) { // Give up, it won't work // Because later we won't know how to display frames from that Trace.TraceWarning("Invalid Frames information given for ACE {0} in {1}", ACEFile, stf.FileName); ACEFile = ""; return; } // Valid frames info, set FramesCount FramesCount = FramesX * FramesY; } // Now we have an ACE and Frames for it. // Only shuffle data in following cases if (Values.Count != Positions.Count || (Values.Count < FramesCount & canFill) || (Values.Count > 0 && Values[0] == Values[Values.Count - 1] && Values[0] == 0)) { // Fixup Positions and Values collections first // If the read Positions and Values are not match // Or we didn't read Values but have Frames to draw // Do not test if FramesCount equals Values count, we trust in the creator - // maybe did not want to display all Frames // (If there are more Values than Frames it will checked at draw time) // Need to fix the whole Values if (Positions.Count != _ValuesRead || (FramesCount > 0 && (Values.Count == 0 || Values.Count == 1))) { //This if clause covers among others following cases: // Case 1 (e.g. engine brake lever of Dash 9): //NumFrames ( 22 11 2 ) //NumPositions ( 1 0 ) //NumValues ( 1 0 ) //Orientation ( 1 ) //DirIncrease ( 1 ) //ScaleRange ( 0 1 ) // // Case 2 (e.g. throttle lever of Acela): //NumFrames ( 25 5 5 ) //NumPositions ( 0 ) //NumValues ( 0 ) //Orientation ( 1 ) //DirIncrease ( 1 ) //ScaleRange ( 0 1 ) // // Clear existing Positions.Clear(); Values.Clear(); // Add the two sure positions, the two ends Positions.Add(0); // We will need the FramesCount later! // We use Positions only here Positions.Add(FramesCount); // Fill empty Values for (int i = 0; i < FramesCount; i++) { Values.Add(0); } Values[0] = MinValue; Values.Add(MaxValue); } else if (Values.Count == 2 && Values[0] == 0 && Values[1] < MaxValue && Positions[0] == 0 && Positions[1] == 1 && Values.Count < FramesCount) { //This if clause covers among others following cases: // Case 1 (e.g. engine brake lever of gp38): //NumFrames ( 18 2 9 ) //NumPositions ( 2 0 1 ) //NumValues ( 2 0 0.3 ) //Orientation ( 0 ) //DirIncrease ( 0 ) //ScaleRange ( 0 1 ) Positions.Add(FramesCount); // Fill empty Values for (int i = Values.Count; i < FramesCount; i++) { Values.Add(Values[1]); } Values.Add(MaxValue); } else { //This if clause covers among others following cases: // Case 1 (e.g. train brake lever of Acela): //NumFrames ( 12 4 3 ) //NumPositions ( 5 0 1 9 10 11 ) //NumValues ( 5 0 0.2 0.85 0.9 0.95 ) //Orientation ( 1 ) //DirIncrease ( 1 ) //ScaleRange ( 0 1 ) // // Fill empty Values int iValues = 1; for (int i = 1; i < FramesCount && i <= Positions.Count - 1 && Values.Count < FramesCount; i++) { var deltaPos = Positions[i] - Positions[i - 1]; while (deltaPos > 1 && Values.Count < FramesCount) { Values.Insert(iValues, 0); iValues++; deltaPos--; } iValues++; } // Add the maximums to the end, the Value will be removed // We use Positions only here if (Values.Count > 0 && Values[0] <= Values[Values.Count - 1]) { Values.Add(MaxValue); } else if (Values.Count > 0 && Values[0] > Values[Values.Count - 1]) { Values.Add(MinValue); } } // OK, we have a valid size of Positions and Values // Now it is the time for checking holes in the given data if ((Positions.Count < FramesCount - 1 && Values[0] <= Values[Values.Count - 1]) || (Values.Count > 1 && Values[0] == Values[Values.Count - 2] && Values[0] == 0)) { int j = 1; int p = 0; // Skip the 0 element, that is the default MinValue for (int i = 1; i < Positions.Count; i++) { // Found a hole if (Positions[i] != p + 1) { // Iterate to the next valid data and fill the hole for (j = p + 1; j < Positions[i]; j++) { // Extrapolate into the hole Values[j] = MathHelper.Lerp((float)Values[p], (float)Values[Positions[i]], (float)j / (float)Positions[i]); } } p = Positions[i]; } } // Don't need the MaxValue added before, remove it Values.RemoveAt(Values.Count - 1); } } // MSTS ignores/overrides various settings by the following exceptional cases: if (ControlType == CABViewControlTypes.CP_HANDLE) { ControlStyle = CABViewControlStyles.NOT_SPRUNG; } if (ControlType == CABViewControlTypes.PANTOGRAPH || ControlType == CABViewControlTypes.PANTOGRAPH2) { ControlStyle = CABViewControlStyles.ONOFF; } if (ControlType == CABViewControlTypes.HORN || ControlType == CABViewControlTypes.SANDERS || ControlType == CABViewControlTypes.BELL || ControlType == CABViewControlTypes.RESET) { ControlStyle = CABViewControlStyles.WHILE_PRESSED; } if (ControlType == CABViewControlTypes.DIRECTION && Orientation == 0) { Direction = 1 - Direction; } } // catch (Exception error) // { // if (error is STFException) // Parsing error, so pass it on // throw; // else // Unexpected error, so provide a hint // throw new STFException(stf, "Problem with NumPositions/NumValues/NumFrames/ScaleRange"); // } // End of Need check the Values collection for validity } // End of Constructor