diff --git a/EDPlayerJournal/CommanderContext/CommanderContext.cs b/EDPlayerJournal/CommanderContext/CommanderContext.cs new file mode 100644 index 0000000..4b2e230 --- /dev/null +++ b/EDPlayerJournal/CommanderContext/CommanderContext.cs @@ -0,0 +1,56 @@ +using EDPlayerJournal.Entries; + +namespace EDPlayerJournal.CommanderContext; + +/// +/// A class that uses various journal entries to provide a (hopefully) +/// up to date summary of the current commander in game. +/// +/// Data in this context may be null, in which case the current status of +/// that information is not yet known. For example if the player died, but +/// they have't respawned yet, their location might be null. +/// +public class CommanderContext { + private static Dictionary parsers = new() { + { Events.Commander, new CommanderParser() }, + { Events.Docked, new DockedParser() }, + { Events.FSDJump, new FSDJumpParser() }, + { Events.Location, new LocationParser() }, + { Events.Undocked, new UndockedParser() }, + }; + + /// + /// Name of the commander. + /// + public string? Name { get; set; } = null; + + /// + /// Whether the commander is currently docked. + /// + public bool IsDocked { get; set; } = false; + + /// + /// Current station + /// + public Station? Station { get; set; } = null; + + /// + /// Current star system + /// + public StarSystem? System { get; set; } = null; + + public void Update(Entry entry) { + if (string.IsNullOrEmpty(entry.Event)) { + throw new CommanderParserException("invalid or empty event given"); + } + + string ev = entry.Event; + + if (!parsers.ContainsKey(ev)) { + return; + } + + ICommanderParser parser = parsers[ev]; + parser.Parse(entry, this); + } +} diff --git a/EDPlayerJournal/CommanderContext/CommanderParser.cs b/EDPlayerJournal/CommanderContext/CommanderParser.cs new file mode 100644 index 0000000..91d857d --- /dev/null +++ b/EDPlayerJournal/CommanderContext/CommanderParser.cs @@ -0,0 +1,15 @@ +using EDPlayerJournal.Entries; + +namespace EDPlayerJournal.CommanderContext; + +internal class CommanderParser : ICommanderParser { + public void Parse(Entry entry, CommanderContext ctx) { + CommanderEntry? e = entry as CommanderEntry; + + if (e == null) { + throw new CommanderParserException("invalid entry"); + } + + ctx.Name = e.Name; + } +} diff --git a/EDPlayerJournal/CommanderContext/DockedParser.cs b/EDPlayerJournal/CommanderContext/DockedParser.cs new file mode 100644 index 0000000..14a29b9 --- /dev/null +++ b/EDPlayerJournal/CommanderContext/DockedParser.cs @@ -0,0 +1,16 @@ +using EDPlayerJournal.Entries; + +namespace EDPlayerJournal.CommanderContext; + +internal class DockedParser : ICommanderParser { + public void Parse(Entry entry, CommanderContext ctx) { + DockedEntry? e = entry as DockedEntry; + + if (e == null) { + throw new CommanderParserException("invalid entry"); + } + + ctx.Station = Station.ParseEntry(e); + ctx.IsDocked = true; + } +} diff --git a/EDPlayerJournal/CommanderContext/FSDJumpParser.cs b/EDPlayerJournal/CommanderContext/FSDJumpParser.cs new file mode 100644 index 0000000..a95d164 --- /dev/null +++ b/EDPlayerJournal/CommanderContext/FSDJumpParser.cs @@ -0,0 +1,15 @@ +using EDPlayerJournal.Entries; + +namespace EDPlayerJournal.CommanderContext; + +internal class FSDJumpParser : ICommanderParser { + public void Parse(Entry entry, CommanderContext ctx) { + FSDJumpEntry? e = entry as FSDJumpEntry; + + if (e == null) { + throw new CommanderParserException("invalid entry"); + } + + ctx.System = StarSystem.ParseEntry(e); + } +} diff --git a/EDPlayerJournal/CommanderContext/ICommanderParser.cs b/EDPlayerJournal/CommanderContext/ICommanderParser.cs new file mode 100644 index 0000000..112c39d --- /dev/null +++ b/EDPlayerJournal/CommanderContext/ICommanderParser.cs @@ -0,0 +1,19 @@ +using EDPlayerJournal; +using EDPlayerJournal.Entries; + +namespace EDPlayerJournal.CommanderContext; + +public class CommanderParserException : ApplicationException { + public CommanderParserException() { + } + + public CommanderParserException(string message) : base(message) { + } + + public CommanderParserException(string message, params object?[] args) : base(string.Format(message, args)) { + } +} + +internal interface ICommanderParser { + void Parse(Entry entry, CommanderContext ctx); +} diff --git a/EDPlayerJournal/CommanderContext/LocationParser.cs b/EDPlayerJournal/CommanderContext/LocationParser.cs new file mode 100644 index 0000000..79955df --- /dev/null +++ b/EDPlayerJournal/CommanderContext/LocationParser.cs @@ -0,0 +1,17 @@ +using EDPlayerJournal.Entries; + +namespace EDPlayerJournal.CommanderContext; + +internal class LocationParser : ICommanderParser { + public void Parse(Entry entry, CommanderContext ctx) { + LocationEntry? e = entry as LocationEntry; + + if (e == null) { + throw new CommanderParserException("invalid entry"); + } + + ctx.Station = Station.ParseEntry(e); + ctx.System = StarSystem.ParseEntry(e); + ctx.IsDocked = e.Docked; + } +} \ No newline at end of file diff --git a/EDPlayerJournal/CommanderContext/UndockedParser.cs b/EDPlayerJournal/CommanderContext/UndockedParser.cs new file mode 100644 index 0000000..5e7591a --- /dev/null +++ b/EDPlayerJournal/CommanderContext/UndockedParser.cs @@ -0,0 +1,16 @@ +using EDPlayerJournal.Entries; + +namespace EDPlayerJournal.CommanderContext; + +internal class UndockedParser : ICommanderParser { + public void Parse(Entry entry, CommanderContext ctx) { + UndockedEntry? e = entry as UndockedEntry; + + if (e == null) { + throw new CommanderParserException("invalid entry"); + } + + ctx.Station = null; + ctx.IsDocked = false; + } +} diff --git a/EDPlayerJournal/Entries/Entry.cs b/EDPlayerJournal/Entries/Entry.cs index 9bb0c01..a4ca767 100644 --- a/EDPlayerJournal/Entries/Entry.cs +++ b/EDPlayerJournal/Entries/Entry.cs @@ -59,6 +59,7 @@ public class Entry { { Events.SupercruiseEntry, typeof(SupercruiseEntryEntry) }, { Events.SupercruiseExit, typeof(SupercruiseExitEntry) }, { Events.UnderAttack, typeof(UnderAttackEntry) }, + { Events.Undocked, typeof(UndockedEntry) }, }; private string? eventtype = null; diff --git a/EDPlayerJournal/Entries/Events.cs b/EDPlayerJournal/Entries/Events.cs index 6ec3909..c85ad70 100644 --- a/EDPlayerJournal/Entries/Events.cs +++ b/EDPlayerJournal/Entries/Events.cs @@ -50,4 +50,5 @@ public class Events { public static readonly string SupercruiseEntry = "SupercruiseEntry"; public static readonly string SupercruiseExit = "SupercruiseExit"; public static readonly string UnderAttack = "UnderAttack"; + public static readonly string Undocked = "Undocked"; } diff --git a/EDPlayerJournal/Entries/UndockedEntry.cs b/EDPlayerJournal/Entries/UndockedEntry.cs new file mode 100644 index 0000000..11bf90b --- /dev/null +++ b/EDPlayerJournal/Entries/UndockedEntry.cs @@ -0,0 +1,12 @@ +namespace EDPlayerJournal.Entries; + +public class UndockedEntry : Entry { + /// + /// Name of the station + /// + public string? StationName { get; set; } + + protected override void Initialise() { + StationName = JSON.Value("StationName"); + } +} diff --git a/EDPlayerJournal/StarSystem.cs b/EDPlayerJournal/StarSystem.cs new file mode 100644 index 0000000..842ac11 --- /dev/null +++ b/EDPlayerJournal/StarSystem.cs @@ -0,0 +1,40 @@ +using EDPlayerJournal.Entries; +using Newtonsoft.Json.Linq; + +namespace EDPlayerJournal; + +public class StarSystem { + public string Name { get; set; } = string.Empty; + + public double[] Position { get; set; } = new double[3] { 0.0, 0.0, 0.0 }; + + public ulong Address { get; set; } = 0; + + public ulong Population { get; set; } = 0; + + public string Allegiance { get; set; } = string.Empty; + + public static StarSystem? ParseEntry(Entry e) { + if (!(e.Is(Events.Location) || e.Is(Events.FSDJump))) { + return null; + } + return ParseJSON(e.JSON); + } + + public static StarSystem? ParseJSON(JObject obj) { + StarSystem s = new(); + + s.Name = obj.Value("StarSystem") ?? string.Empty; + var pos = obj.Value("StarPos"); + if (pos != null) { + s.Position = pos.Select(x => (double)x).ToArray(); + } + s.Address = obj.Value("SystemAddress") ?? 0; + s.Population = obj.Value("Population") ?? 0; + + // TODO: more info + + return s; + } +} + diff --git a/EDPlayerJournal/Station.cs b/EDPlayerJournal/Station.cs new file mode 100644 index 0000000..1abdbc5 --- /dev/null +++ b/EDPlayerJournal/Station.cs @@ -0,0 +1,65 @@ +using EDPlayerJournal.Entries; +using Newtonsoft.Json.Linq; + +namespace EDPlayerJournal; + +/// +/// Represents a station ingame +/// +public class Station { + public string SystemName { get; set; } = string.Empty; + + public ulong SystemAddress { get; set; } = 0; + + public string Name { get; set; } = string.Empty; + + public string Type { get; set; } = string.Empty; + + public ulong MarketID { get; set; } = 0; + + public string Faction { get; set; } = string.Empty; + + public string Government { get; set; } = string.Empty; + + public string GovernmentLocalised { get; set; } = string.Empty; + + public List Services { get; set; } = new(); + + public static Station? ParseEntry(Entry e) { + if (!(e.Is(Events.Docked) || e.Is(Events.Location))) { + return null; + } + + var s = ParseJSON(e.JSON); + return s; + } + + public static Station? ParseJSON(JObject obj) { + Station s = new(); + + s.Name = obj.Value("StationName") ?? string.Empty; + s.Type = obj.Value("StationType") ?? string.Empty; + s.MarketID = obj.Value("MarketID") ?? 0; + + var faction = obj.Value("StationFaction"); + if (faction != null) { + s.Faction = faction.Value("Name") ?? string.Empty; + } + + s.Government = obj.Value("StationGovernment") ?? string.Empty; + s.GovernmentLocalised = obj.Value("StationGovernment_Localised") ?? string.Empty; + + var services = obj.Value("StationServices"); + if (services != null) { + s.Services = services + .Select(x => x.ToString()) + .ToList() + ; + } + + // TODO: more info + + return s; + } +} +