From 39d2de5956724b29b468c090ceb8ce119d92ceb0 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Sun, 28 Apr 2024 20:03:51 +0200 Subject: [PATCH] feat: Load missions and factions --- Loader/Damage.cs | 4 +- Loader/FactionLoader.cs | 60 ++++++ Loader/MissionLoader.cs | 71 +++++++ Loader/Program.cs | 35 ++++ Loader/RewadLoader.cs | 113 +++++++++++ Loader/scdb.Xml/Factions/Faction.cs | 27 +++ .../scdb.Xml/Missionbroker/Missionbroker.cs | 192 ++++++++++++++++++ .../SReputationMissionRewardBonusParams.cs | 23 +++ .../Reputation/SReputationRewardAmount.cs | 10 + Loader/scdb.Xml/Reputation/Scope.cs | 19 ++ Loader/scdb.Xml/Reputation/Standing.cs | 16 ++ 11 files changed, 569 insertions(+), 1 deletion(-) create mode 100644 Loader/FactionLoader.cs create mode 100644 Loader/MissionLoader.cs create mode 100644 Loader/RewadLoader.cs create mode 100644 Loader/scdb.Xml/Factions/Faction.cs create mode 100644 Loader/scdb.Xml/Missionbroker/Missionbroker.cs create mode 100644 Loader/scdb.Xml/Reputation/SReputationMissionRewardBonusParams.cs create mode 100644 Loader/scdb.Xml/Reputation/SReputationRewardAmount.cs create mode 100644 Loader/scdb.Xml/Reputation/Scope.cs create mode 100644 Loader/scdb.Xml/Reputation/Standing.cs diff --git a/Loader/Damage.cs b/Loader/Damage.cs index 0293c2b62..2d52d891f 100644 --- a/Loader/Damage.cs +++ b/Loader/Damage.cs @@ -1,3 +1,5 @@ +using scdb.Xml.Entities; + namespace Loader { public class Damage @@ -9,7 +11,7 @@ public class Damage public double biochemical; public double stun; - public static Damage FromDamageInfo(scdb.Xml.Entities.DamageInfo info) + public static Damage FromDamageInfo(DamageInfo info) { if (info == null) return null; diff --git a/Loader/FactionLoader.cs b/Loader/FactionLoader.cs new file mode 100644 index 000000000..9c86144a3 --- /dev/null +++ b/Loader/FactionLoader.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using Loader.scdb.Xml.Factions; +using Newtonsoft.Json; +using scdb.Xml.Entities; + +namespace Loader +{ + public class FactionLoader + { + public string OutputFolder { get; set; } + public string DataRoot { get; set; } + + public Dictionary LoadFactions() + { + Directory.CreateDirectory(Path.Combine(OutputFolder, "factions")); + + var output = new Dictionary(); + + + var path = Path.Combine(DataRoot, Path.Join("Data", "Libs", "Foundry", "Records", "factions")); + + foreach (var entityFilename in Directory.EnumerateFiles(path, "*.xml")) + { + var faction = Parse(entityFilename); + output.Add(faction.__ref, faction); + File.WriteAllText(Path.Combine(OutputFolder, "factions", $"{faction.ClassName.ToLower()}.json"), JsonConvert.SerializeObject(faction)); + } + + return output; + } + + T Parse(string xmlFilename) where T : ClassBase + { + string rootNodeName; + using (var reader = XmlReader.Create(new StreamReader(xmlFilename))) + { + reader.MoveToContent(); + rootNodeName = reader.Name; + } + + var split = rootNodeName.Split('.'); + string className = split[split.Length - 1]; + + var xml = File.ReadAllText(xmlFilename); + var doc = new XmlDocument(); + doc.LoadXml(xml); + + var serialiser = new XmlSerializer(typeof(T), new XmlRootAttribute { ElementName = rootNodeName }); + using (var stream = new XmlNodeReader(doc)) + { + var entity = (T)serialiser.Deserialize(stream); + entity.ClassName = className; + return entity; + } + } + } +} diff --git a/Loader/MissionLoader.cs b/Loader/MissionLoader.cs new file mode 100644 index 000000000..14a8010ca --- /dev/null +++ b/Loader/MissionLoader.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using Newtonsoft.Json; +using scdb.Xml.Entities; +using scdb.Xml.Missionbroker; + +namespace Loader +{ + public class MissionLoader + { + public string OutputFolder { get; set; } + public string DataRoot { get; set; } + public LocalisationService locService { get; set; } + + public Dictionary LoadMissions() + { + Directory.CreateDirectory(Path.Combine(OutputFolder, "missions")); + + var output = new Dictionary(); + + + var path = Path.Combine(DataRoot, Path.Join("Data", "Libs", "Foundry", "Records", "missionbroker")); + + foreach (var entityFilename in Directory.EnumerateFiles(path, "*.xml", SearchOption.AllDirectories)) + { + var mission = Parse(entityFilename); + AddTranslations(mission); + output.Add(mission.__ref, mission); + File.WriteAllText(Path.Combine(OutputFolder, "missions", $"{mission.ClassName.ToLower()}.json"), JsonConvert.SerializeObject(mission)); + } + + return output; + } + + T Parse(string xmlFilename) where T : ClassBase + { + string rootNodeName; + using (var reader = XmlReader.Create(new StreamReader(xmlFilename))) + { + reader.MoveToContent(); + rootNodeName = reader.Name; + } + + var split = rootNodeName.Split('.'); + string className = split[split.Length - 1]; + + var xml = File.ReadAllText(xmlFilename); + var doc = new XmlDocument(); + doc.LoadXml(xml); + + var serialiser = new XmlSerializer(typeof(T), new XmlRootAttribute { ElementName = rootNodeName }); + using (var stream = new XmlNodeReader(doc)) + { + var entity = (T)serialiser.Deserialize(stream); + entity.ClassName = className; + return entity; + } + } + + private void AddTranslations(MissionBrokerEntry entity) + { + entity.title = locService.GetText(entity.title, entity.title); + entity.titleHUD = locService.GetText(entity.titleHUD, entity.titleHUD); + entity.description = locService.GetText(entity.description, entity.description); + entity.commsChannelName = locService.GetText(entity.commsChannelName, entity.commsChannelName); + entity.missionGiver = locService.GetText(entity.missionGiver, entity.missionGiver); + } + } +} diff --git a/Loader/Program.cs b/Loader/Program.cs index 0dde70640..0eb55cca1 100644 --- a/Loader/Program.cs +++ b/Loader/Program.cs @@ -19,6 +19,7 @@ static void Main(string[] args) bool doItems = true; bool doShops = true; bool doStarmap = true; + bool doMissions = true; bool noCache = false; string typeFilter = null; string shipFilter = null; @@ -32,6 +33,7 @@ static void Main(string[] args) { "noitems", v => doItems = false }, { "noshops", v => doShops = false }, { "nomap", v => doStarmap = false }, + { "nomissions", v => doMissions = false }, { "nocache", v => noCache = true }, { "types=", v => typeFilter = v }, { "ships=", v=> shipFilter = v } @@ -104,6 +106,15 @@ static void Main(string[] args) var lootTables = lootLoader.LoadTables(); var lootSvc = new LootService(lootArchetypes, lootTables); + // Factions + Console.WriteLine("Load Factions"); + var factionLoader = new FactionLoader + { + OutputFolder = outputRoot, + DataRoot = scDataRoot + }; + var factions = factionLoader.LoadFactions(); + // Ammunition Console.WriteLine("Load Ammunition"); var ammoLoader = new AmmoLoader @@ -124,6 +135,30 @@ static void Main(string[] args) // //var insuranceSvc = new InsuranceService(insurancePrices); // var insuranceSvc = new InsuranceService(null); + + // Missions + if (doMissions) + { + Console.WriteLine("Load Missions"); + var missionLoader = new MissionLoader + { + OutputFolder = outputRoot, + DataRoot = scDataRoot, + locService = localisationSvc + }; + var missions = missionLoader.LoadMissions(); + + var rewardsLoader = new RewardLoader + { + OutputFolder = outputRoot, + DataRoot = scDataRoot, + locService = localisationSvc + }; + rewardsLoader.LoadRewards(); + rewardsLoader.LoadStandings(); + rewardsLoader.LoadScopes(); + } + // PersonalInventories Console.WriteLine("Load PersonalInventories"); var inventoryLoader = new InventoryContainerLoader() diff --git a/Loader/RewadLoader.cs b/Loader/RewadLoader.cs new file mode 100644 index 000000000..ce8ce3d21 --- /dev/null +++ b/Loader/RewadLoader.cs @@ -0,0 +1,113 @@ +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using Loader.scdb.Xml.Reputation; +using Newtonsoft.Json; +using scdb.Xml.Entities; + +namespace Loader +{ + public class RewardLoader + { + public string OutputFolder { get; set; } + public string DataRoot { get; set; } + public LocalisationService locService { get; set; } + + public Dictionary LoadScopes() + { + Directory.CreateDirectory(Path.Combine(OutputFolder, "reputation", "scopes")); + + var output = new Dictionary(); + + + var path = Path.Combine(DataRoot, Path.Join("Data", "Libs", "Foundry", "Records", "reputation", "scopes")); + + foreach (var entityFilename in Directory.EnumerateFiles(path, "*.xml", SearchOption.AllDirectories)) + { + var scope = Parse(entityFilename); + AddScopeTranslations(scope); + output.Add(scope.__ref, scope); + File.WriteAllText(Path.Combine(OutputFolder, "reputation", "scopes", $"{scope.ClassName.ToLower()}.json"), JsonConvert.SerializeObject(scope)); + } + + return output; + } + + public Dictionary LoadStandings() + { + Directory.CreateDirectory(Path.Combine(OutputFolder, "reputation", "standings")); + + var output = new Dictionary(); + + + var path = Path.Combine(DataRoot, Path.Join("Data", "Libs", "Foundry", "Records", "reputation", "standings")); + + foreach (var entityFilename in Directory.EnumerateFiles(path, "*.xml", SearchOption.AllDirectories)) + { + var standing = Parse(entityFilename); + AddStandingTranslations(standing); + output.Add(standing.__ref, standing); + File.WriteAllText(Path.Combine(OutputFolder, "reputation", "standings", $"{standing.ClassName.ToLower()}.json"), JsonConvert.SerializeObject(standing)); + } + + return output; + } + + public void LoadRewards() + { + Directory.CreateDirectory(Path.Combine(OutputFolder, "reputation", "rewards")); + + var path = Path.Combine(DataRoot, Path.Join("Data", "Libs", "Foundry", "Records", "reputation", "rewards")); + + foreach (var entityFilename in Directory.EnumerateFiles(Path.Join(path, "missionrewards_reputation"), "*.xml", SearchOption.AllDirectories)) + { + var reward = Parse(entityFilename); + File.WriteAllText(Path.Combine(OutputFolder, "reputation", "rewards", $"{reward.ClassName.ToLower()}.json"), JsonConvert.SerializeObject(reward)); + } + + foreach (var entityFilename in Directory.EnumerateFiles(Path.Join(path, "missionrewards_bonusuec"), "*.xml", SearchOption.AllDirectories)) + { + var reward = Parse(entityFilename); + File.WriteAllText(Path.Combine(OutputFolder, "reputation", "rewards", $"{reward.ClassName.ToLower()}.json"), JsonConvert.SerializeObject(reward)); + } + } + + T Parse(string xmlFilename) where T : ClassBase + { + string rootNodeName; + using (var reader = XmlReader.Create(new StreamReader(xmlFilename))) + { + reader.MoveToContent(); + rootNodeName = reader.Name; + } + + var split = rootNodeName.Split('.'); + string className = split[split.Length - 1]; + + var xml = File.ReadAllText(xmlFilename); + var doc = new XmlDocument(); + doc.LoadXml(xml); + + var serialiser = new XmlSerializer(typeof(T), new XmlRootAttribute { ElementName = rootNodeName }); + using (var stream = new XmlNodeReader(doc)) + { + var entity = (T)serialiser.Deserialize(stream); + entity.ClassName = className; + return entity; + } + } + + private void AddScopeTranslations(Scope entity) + { + entity.displayName = locService.GetText(entity.displayName, entity.displayName); + entity.description = locService.GetText(entity.description, entity.description); + } + + private void AddStandingTranslations(Standing entity) + { + entity.displayName = locService.GetText(entity.displayName, entity.displayName); + entity.perkDescription = locService.GetText(entity.perkDescription, entity.perkDescription); + } + } +} diff --git a/Loader/scdb.Xml/Factions/Faction.cs b/Loader/scdb.Xml/Factions/Faction.cs new file mode 100644 index 000000000..2ac86cdc4 --- /dev/null +++ b/Loader/scdb.Xml/Factions/Faction.cs @@ -0,0 +1,27 @@ +using System.Xml.Serialization; +using scdb.Xml.Entities; + +namespace Loader.scdb.Xml.Factions; + +public class Faction : ClassBase +{ + [XmlAttribute] public string displayName; + [XmlAttribute] public string description; + [XmlAttribute] public string gameToken; + [XmlAttribute] public string defaultReaction; + + public FriendlyFireReactionOverride[] friendlyFireReactionOverrides; + public FactionRelationship[] factionRelationships; +} + +public class FriendlyFireReactionOverride +{ + [XmlAttribute] public string reactionType; + [XmlAttribute] public bool shouldAllowFriendlyFire; +} + +public class FactionRelationship +{ + [XmlAttribute] public string faction; + [XmlAttribute] public string reactionType; +} diff --git a/Loader/scdb.Xml/Missionbroker/Missionbroker.cs b/Loader/scdb.Xml/Missionbroker/Missionbroker.cs new file mode 100644 index 000000000..02c48d511 --- /dev/null +++ b/Loader/scdb.Xml/Missionbroker/Missionbroker.cs @@ -0,0 +1,192 @@ +using System.Collections.Generic; +using System.Xml.Serialization; +using scdb.Xml.Entities; + +namespace scdb.Xml.Missionbroker +{ + public class MissionBrokerEntry : ClassBase + { + [XmlAttribute] public bool notForRelease; + [XmlAttribute] public string owner; + [XmlAttribute] public string missionModule; + [XmlAttribute] public string title; + [XmlAttribute] public string titleHUD; + [XmlAttribute] public string description; + [XmlAttribute] public string missionGiver; + [XmlAttribute] public string commsChannelName; + [XmlAttribute] public string type; + [XmlAttribute] public string localityAvailable; + [XmlAttribute] public string locationMissionAvailable; + [XmlAttribute] public bool initiallyActive; + [XmlAttribute] public bool notifyOnAvailable; + [XmlAttribute] public bool showAsOffer; + [XmlAttribute] public int missionBuyInAmount; + [XmlAttribute] public int refundBuyInOnWithdraw; + [XmlAttribute] public bool hasCompleteButton; + [XmlAttribute] public bool handlesAbandonRequest; + [XmlAttribute] public int missionModulePerPlayer; + [XmlAttribute] public int maxInstances; + [XmlAttribute] public int maxPlayersPerInstance; + [XmlAttribute] public int maxInstancesPerPlayer; + [XmlAttribute] public bool canBeShared; + [XmlAttribute] public bool onceOnly; + [XmlAttribute] public bool tutorial; + [XmlAttribute] public bool displayAlliedMarkers; + [XmlAttribute] public bool availableInPrison; + [XmlAttribute] public bool failIfSentToPrison; + [XmlAttribute] public bool failIfBecameCriminal; + [XmlAttribute] public bool failIfLeavePrison; + [XmlAttribute] public bool requestOnly; + [XmlAttribute] public int respawnTime; + [XmlAttribute] public double respawnTimeVariation; + [XmlAttribute] public bool instanceHasLifeTime; + [XmlAttribute] public bool showLifeTimeInMobiGlas; + [XmlAttribute] public int instanceLifeTime; + [XmlAttribute] public double instanceLifeTimeVariation; + [XmlAttribute] public bool canReacceptAfterAbandoning; + [XmlAttribute] public int abandonedCooldownTime; + [XmlAttribute] public double abandonedCooldownTimeVariation; + [XmlAttribute] public bool canReacceptAfterFailing; + [XmlAttribute] public bool hasPersonalCooldown; + [XmlAttribute] public int personalCooldownTime; + [XmlAttribute] public double personalCooldownTimeVariation; + [XmlAttribute] public bool moduleHandlesOwnShutdown; + [XmlAttribute] public string linkedMission; + [XmlAttribute] public bool lawfulMission; + [XmlAttribute] public string missionGiverRecord; + [XmlAttribute] public string invitationMission; + [XmlAttribute] public string missionGiverFragmentTags; + + public Reference[] associatedMissions; + public MissionReward missionReward; + public SReputationAmountListParams[] missionResultReputationRewards; + public CompletionTags completionTags; + public Modifiers modifiers; + public Reference[] missionTags; + public ReputationPrerequisites reputationPrerequisites; + public Reference[] requiredMissions; + public RequiredCompletedMissionTags requiredCompletedMissionTags; + } + + public class MissionReward + { + [XmlAttribute] public int reward; + [XmlAttribute] public int max; + [XmlAttribute] public int plusBonusses; + [XmlAttribute] public string currencyType; + [XmlAttribute] public string reputationBonus; + } + + public class SReputationAmountListParams + { + public SReputationAmountParams[] reputationAmounts; + } + + public class SReputationAmountParams + { + [XmlAttribute] public string uniqueEntityClass; + [XmlAttribute] public string reputationScope; + [XmlAttribute] public string reward; + } + + public class MissionDeadline + { + [XmlAttribute] public int missionCompletionTime; + [XmlAttribute] public bool missionAutoEnd; + [XmlAttribute] public string missionResultAfterTimerEnd; + [XmlAttribute] public int remainingTimeToShowTimer; + [XmlAttribute] public string missionEndReason; + } + + public class CompletionTags + { + public Reference[] tags; + } + + [XmlRoot(ElementName = "modifiers")] + public class Modifiers + { + [XmlElement(Type = typeof(MissionModifier_LawLicense), ElementName = "MissionModifier_LawLicense")] + [XmlElement(Type = typeof(MissionModifier_SecurityClearance), ElementName = "MissionModifier_SecurityClearance")] + [XmlElement(Type = typeof(MissionModifier_HostileMission), ElementName = "MissionModifier_HostileMission")] + [XmlElement(Type = typeof(MissionModifier_FactionHostility), ElementName = "MissionModifier_FactionHostility")] + public List modifiers { get; set; } + } + + public class BaseMissionModifier + { + [XmlAttribute] public string __polymorphicType; + } + + public class MissionModifier_SecurityClearance : BaseMissionModifier + { + [XmlAttribute] public string clearanceToken; + [XmlAttribute] public string locationProperty; + } + + public class MissionModifier_LawLicense : BaseMissionModifier + { + [XmlAttribute] public string licenseType; + } + + public class MissionModifier_HostileMission : BaseMissionModifier + { + [XmlAttribute] public string missionBrokerEntry; + [XmlAttribute] public bool legalToAttack; + } + + public class MissionModifier_FactionHostility : BaseMissionModifier + { + [XmlAttribute] public string faction; + [XmlAttribute] public string myReaction; + [XmlAttribute] public string theirReaction; + [XmlAttribute] public bool ignoreCriminalHostility; + } + + public class ReputationPrerequisites + { + [XmlAttribute] public string wantedLevelJurisdictionOverride; + public WantedLevel wantedLevel; + } + + public class WantedLevel + { + [XmlAttribute] public int minValue; + [XmlAttribute] public int maxValue; + } + + public class ReputationRequirements + { + public SReputationAmountListParams SReputationAmountListParams; + } + + public class SReputationMissionRequirementsParams + { + public SReputationMissionRequirementExpressionElement[] expression; + } + + public class SReputationMissionRequirementExpressionElement{} + + public class SReputationMissionRequirementExpression_LeftParenthesis: SReputationMissionRequirementExpressionElement {} + public class SReputationMissionRequirementExpression_And: SReputationMissionRequirementExpressionElement {} + public class SReputationMissionRequirementExpression_RightParenthesis: SReputationMissionRequirementExpressionElement {} + + public class SReputationMissionGiverRequirementParams : SReputationMissionRequirementExpressionElement + { + [XmlAttribute] public string missionGiverEntityClass; + [XmlAttribute] public string reputationScope; + [XmlAttribute] public string comparison; + [XmlAttribute] public string standing; + } + + public class RequiredCompletedMissionTags + { + public TagSearchTerm TagSearchTerm; + } + + public class TagSearchTerm + { + public Reference[] positiveTags; + public Reference[] negativeTags; + } +} diff --git a/Loader/scdb.Xml/Reputation/SReputationMissionRewardBonusParams.cs b/Loader/scdb.Xml/Reputation/SReputationMissionRewardBonusParams.cs new file mode 100644 index 000000000..cf8843add --- /dev/null +++ b/Loader/scdb.Xml/Reputation/SReputationMissionRewardBonusParams.cs @@ -0,0 +1,23 @@ +using System.Xml.Serialization; +using scdb.Xml.Entities; + +namespace Loader.scdb.Xml.Reputation; + +public class SReputationMissionRewardBonusParams : ClassBase +{ + public SReputationMissionGiverRewardBonusParams[] missionGiverBonuses; +} + +public class SReputationMissionGiverRewardBonusParams +{ + [XmlAttribute] public string missionGiverEntityClass; + [XmlAttribute] public string reputationScope; + public SReputationStandingRewardBonusParams[] rewardBonuses; +} + +public class SReputationStandingRewardBonusParams +{ + [XmlAttribute] public string standing; + [XmlAttribute] public double bonusFraction; + +} diff --git a/Loader/scdb.Xml/Reputation/SReputationRewardAmount.cs b/Loader/scdb.Xml/Reputation/SReputationRewardAmount.cs new file mode 100644 index 000000000..07c3fe39e --- /dev/null +++ b/Loader/scdb.Xml/Reputation/SReputationRewardAmount.cs @@ -0,0 +1,10 @@ +using System.Xml.Serialization; +using scdb.Xml.Entities; + +namespace Loader.scdb.Xml.Reputation; + +public class SReputationRewardAmount : ClassBase +{ + [XmlAttribute] public string editorName; + [XmlAttribute] public int reputationAmount; +} diff --git a/Loader/scdb.Xml/Reputation/Scope.cs b/Loader/scdb.Xml/Reputation/Scope.cs new file mode 100644 index 000000000..56d89e3b4 --- /dev/null +++ b/Loader/scdb.Xml/Reputation/Scope.cs @@ -0,0 +1,19 @@ +using System.Xml.Serialization; +using scdb.Xml.Entities; + +namespace Loader.scdb.Xml.Reputation; + +public class Scope : ClassBase +{ + [XmlAttribute] public string scopeName; + [XmlAttribute] public string displayName; + [XmlAttribute] public string description; + public StandingMap standingMap; +} + +public class StandingMap +{ + [XmlAttribute] public int reputationCeiling; + [XmlAttribute] public int initialReputation; + public Reference[] standings; +} diff --git a/Loader/scdb.Xml/Reputation/Standing.cs b/Loader/scdb.Xml/Reputation/Standing.cs new file mode 100644 index 000000000..75e8f0842 --- /dev/null +++ b/Loader/scdb.Xml/Reputation/Standing.cs @@ -0,0 +1,16 @@ +using System.Xml.Serialization; +using scdb.Xml.Entities; + +namespace Loader.scdb.Xml.Reputation; + +public class Standing : ClassBase +{ + [XmlAttribute] public string name; + [XmlAttribute] public string description; + [XmlAttribute] public string displayName; + [XmlAttribute] public string perkDescription; + [XmlAttribute] public int minReputation; + [XmlAttribute] public int driftReputation; + [XmlAttribute] public int driftTimeHours; + [XmlAttribute] public bool gated; +}