public static Track LoadTrack(string trackfile, string trackname) { var ret = new Track(); ret.Filename = trackfile; ret.Name = trackname; ret.Remount = false; var addedlines = new Dictionary <int, StandardLine>(); var location = trackfile; var bytes = File.ReadAllBytes(location); using (var file = new MemoryStream(bytes)) { var br = new BinaryReader(file); int magic = br.ReadInt32(); if (magic != ('T' | 'R' << 8 | 'K' << 16 | 0xF2 << 24)) { throw new TrackIO.TrackLoadException("File was read as .trk but it is not valid"); } byte version = br.ReadByte(); string[] features = ReadString(br).Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); if (version != 1) { throw new TrackIO.TrackLoadException("Unsupported version"); } bool redmultipier = false; bool scenerywidth = false; bool supports61 = false; bool songinfo = false; bool ignorabletrigger = false; for (int i = 0; i < features.Length; i++) { switch (features[i]) { case TrackFeatures.redmultiplier: redmultipier = true; break; case TrackFeatures.scenerywidth: scenerywidth = true; break; case TrackFeatures.six_one: supports61 = true; break; case TrackFeatures.songinfo: songinfo = true; break; case TrackFeatures.ignorable_trigger: ignorabletrigger = true; break; case TrackFeatures.zerostart: ret.ZeroStart = true; break; case TrackFeatures.remount: ret.Remount = true; break; case TrackFeatures.frictionless: ret.frictionless = true; break; default: throw new TrackIO.TrackLoadException("Unsupported feature"); } } if (supports61) { ret.SetVersion(61); } else { ret.SetVersion(62); } if (songinfo) { var song = br.ReadString(); try { var strings = song.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); var fn = Program.UserDirectory + "Songs" + Path.DirectorySeparatorChar + strings[0]; if (File.Exists(fn)) { if (AudioService.LoadFile(ref fn)) { ret.Song = new Song(Path.GetFileName(fn), float.Parse(strings[1], Program.Culture)); } else { Program.NonFatalError("An unknown error occured trying to load the song file"); } } } catch { // ignored } } ret.StartOffset = new Vector2d(br.ReadDouble(), br.ReadDouble()); var lines = br.ReadInt32(); List <LineTrigger> linetriggers = new List <LineTrigger>(); for (var i = 0; i < lines; i++) { GameLine l; byte ltype = br.ReadByte(); var lt = (LineType)(ltype & 0x1F);//we get 5 bits var inv = (ltype >> 7) != 0; var lim = (ltype >> 5) & 0x3; var ID = -1; var prvID = -1; var nxtID = -1; var multiplier = 1; var linewidth = 1f; LineTrigger tr = null; if (redmultipier) { if (lt == LineType.Red) { multiplier = br.ReadByte(); } } if (lt == LineType.Blue || lt == LineType.Red) { if (ignorabletrigger) { tr = new LineTrigger(); bool zoomtrigger = br.ReadBoolean(); if (zoomtrigger) { tr.ZoomTrigger = true; var target = br.ReadSingle(); var frames = br.ReadInt16(); tr.ZoomFrames = frames; tr.ZoomTarget = target; } else { tr = null; } } ID = br.ReadInt32(); if (lim != 0) { prvID = br.ReadInt32(); //ignored nxtID = br.ReadInt32(); //ignored } } if (lt == LineType.Scenery) { if (scenerywidth) { float b = br.ReadByte(); linewidth = b / 10f; } } var x1 = br.ReadDouble(); var y1 = br.ReadDouble(); var x2 = br.ReadDouble(); var y2 = br.ReadDouble(); if (tr != null) { tr.LineID = ID; linetriggers.Add(tr); } switch (lt) { case LineType.Blue: var bl = new StandardLine(new Vector2d(x1, y1), new Vector2d(x2, y2), inv); bl.ID = ID; bl.Extension = (StandardLine.Ext)lim; l = bl; break; case LineType.Red: var rl = new RedLine(new Vector2d(x1, y1), new Vector2d(x2, y2), inv); rl.ID = ID; rl.Extension = (StandardLine.Ext)lim; if (redmultipier) { rl.Multiplier = multiplier; } l = rl; break; case LineType.Scenery: l = new SceneryLine(new Vector2d(x1, y1), new Vector2d(x2, y2)) { Width = linewidth }; break; default: throw new TrackIO.TrackLoadException("Invalid line type at ID " + ID); } if (l is StandardLine) { if (!addedlines.ContainsKey(l.ID)) { addedlines[ID] = (StandardLine)l; ret.AddLine(l); } } else { ret.AddLine(l); } } ret.Triggers = TriggerConverter.ConvertTriggers(linetriggers, ret); if (br.BaseStream.Position != br.BaseStream.Length) { var meta = br.ReadInt32(); if (meta == ('M' | 'E' << 8 | 'T' << 16 | 'A' << 24)) { ParseMetadata(ret, br); } else { throw new TrackIO.TrackLoadException("Expected metadata tag but got " + meta.ToString("X8")); } } } return(ret); }
public static Track LoadTrack(string trackfile) { Track ret = new Track(); ret.Filename = trackfile; track_json trackobj; using (var file = File.OpenRead(trackfile)) { try { trackobj = JsonSerializer.Deserialize <track_json>(file); } catch (Exception ex) { throw new TrackIO.TrackLoadException( "Json parsing error.\n" + ex.Message); } } switch (trackobj.version) { case "6.1": ret.SetVersion(61); break; case "6.2": ret.SetVersion(62); break; default: throw new TrackIO.TrackLoadException( "Unsupported physics."); } ret.Name = trackobj.label; if (trackobj.startZoom != 0) { ret.StartZoom = (float)MathHelper.Clamp( trackobj.startZoom, Utils.Constants.MinimumZoom, Utils.Constants.MaxZoom); } ret.YGravity = trackobj.yGravity; ret.XGravity = trackobj.xGravity; ret.GravityWellSize = trackobj.gravityWellSize; ret.BGColorR = trackobj.bgR; ret.BGColorG = trackobj.bgG; ret.BGColorB = trackobj.bgB; ret.LineColorR = trackobj.lineR; ret.LineColorG = trackobj.lineG; ret.LineColorB = trackobj.lineB; ret.ZeroStart = trackobj.zeroStart; if (trackobj.startPosition != null) { ret.StartOffset = new Vector2d( trackobj.startPosition.x, trackobj.startPosition.y); } if (!string.IsNullOrEmpty(trackobj.linesArrayCompressed)) { var json2 = LZString.decompressBase64(trackobj.linesArrayCompressed); trackobj.linesArray = JsonSerializer.Deserialize <object[][]>(json2); trackobj.linesArrayCompressed = null; } if (trackobj.linesArray?.Length > 0) { ReadLinesArray(ret, trackobj.linesArray); } else if (trackobj.lines != null) { foreach (var line in trackobj.lines) { AddLine(ret, line); } } if (trackobj.triggers != null) { List <LineTrigger> linetriggers = new List <LineTrigger>(); foreach (var trigger in trackobj.triggers) { if (ret.LineLookup.TryGetValue(trigger.ID, out GameLine line)) { if (line is StandardLine stl) { if (trigger.zoom) { linetriggers.Add(new LineTrigger() { ZoomTrigger = trigger.zoom, ZoomTarget = (float)MathHelper.Clamp( trigger.target, Utils.Constants.MinimumZoom, Utils.Constants.MaxZoom), ZoomFrames = trigger.frames, LineID = trigger.ID }); } } } } ret.Triggers = TriggerConverter.ConvertTriggers(linetriggers, ret); } if (trackobj.gameTriggers != null) { foreach (var t in trackobj.gameTriggers) { if (t.start < 1 || t.end < 1 || t.end < t.start) { throw new TrackIO.TrackLoadException( "Trigger timing was outside of range"); } TriggerType ttype; try { ttype = (TriggerType)t.triggerType; } catch { throw new TrackIO.TrackLoadException( "Unsupported trigger type " + t.triggerType); } switch (ttype) { case TriggerType.Zoom: ret.Triggers.Add(new GameTrigger() { Start = t.start, End = t.end, TriggerType = ttype, ZoomTarget = t.zoomTarget, }); break; case TriggerType.BGChange: ret.Triggers.Add(new GameTrigger() { Start = t.start, End = t.end, TriggerType = ttype, backgroundRed = t.backgroundred, backgroundGreen = t.backgroundgreen, backgroundBlue = t.backgroundblue, }); break; case TriggerType.LineColor: ret.Triggers.Add(new GameTrigger() { Start = t.start, End = t.end, TriggerType = ttype, lineRed = t.lineRed, lineGreen = t.lineGreen, lineBlue = t.lineBlue, }); break; } } } return(ret); }