diff --git a/InfectedRose.Builder/CharacterStyle.cs b/InfectedRose.Builder/CharacterStyle.cs index 7898391..e00150a 100644 --- a/InfectedRose.Builder/CharacterStyle.cs +++ b/InfectedRose.Builder/CharacterStyle.cs @@ -1,29 +1,21 @@ +using System.Xml.Serialization; + namespace InfectedRose.Builder { + [XmlRoot] public class CharacterStyle { - public int Chest { get; set; } - - public int ChestDecal { get; set; } - - public int EyeBrowStyle { get; set; } - - public int EyesStyle { get; set; } - - public int HairColor { get; set; } - - public int HairStyle { get; set; } - - public int Head { get; set; } - - public int HeadColor { get; set; } - - public int LeftHand { get; set; } - - public int Legs { get; set; } - - public int MouthStyle { get; set; } - - public int RightHand { get; set; } + [XmlElement] public int Chest { get; set; } = 0; + [XmlElement] public int ChestDecal { get; set; } = 0; + [XmlElement] public int EyeBrowStyle { get; set; } = 0; + [XmlElement] public int EyesStyle { get; set; } = 0; + [XmlElement] public int HairColor { get; set; } = 0; + [XmlElement] public int HairStyle { get; set; } = 0; + [XmlElement] public int Head { get; set; } = 0; + [XmlElement] public int HeadColor { get; set; } = 0; + [XmlElement] public int LeftHand { get; set; } = 0; + [XmlElement] public int Legs { get; set; } = 0; + [XmlElement] public int MouthStyle { get; set; } = 0; + [XmlElement] public int RightHand { get; set; } = 0; } } \ No newline at end of file diff --git a/InfectedRose.Builder/ItemReward.cs b/InfectedRose.Builder/ItemReward.cs index 87ab8a6..7a08ab6 100644 --- a/InfectedRose.Builder/ItemReward.cs +++ b/InfectedRose.Builder/ItemReward.cs @@ -1,9 +1,12 @@ +using System.Xml.Serialization; + namespace InfectedRose.Builder { + [XmlRoot] public class ItemReward { - public int Lot { get; set; } - - public int Count { get; set; } + [XmlElement] public int Lot { get; set; } = -1; + + [XmlElement] public int Count { get; set; } = 0; } } \ No newline at end of file diff --git a/InfectedRose.Builder/Mission.cs b/InfectedRose.Builder/Mission.cs index 611dec8..ebc89b0 100644 --- a/InfectedRose.Builder/Mission.cs +++ b/InfectedRose.Builder/Mission.cs @@ -1,83 +1,59 @@ using System.Collections.Generic; +using System.Xml.Serialization; using InfectedRose.Database; using InfectedRose.Database.Concepts.Tables; using InfectedRose.Database.Fdb; namespace InfectedRose.Builder { + [XmlRoot] public class Mission { - internal AccessDatabase Database { get; } + [XmlIgnore] public AccessDatabase Database { get; set; } - public int Id { get; } + [XmlElement] public int Id { get; set; } - public string Type { get; set; } + [XmlElement] public string Type { get; set; } - public string SubType { get; set; } + [XmlElement] public string SubType { get; set; } - public int UiSortOrder { get; set; } + [XmlElement] public int UiSortOrder { get; set; } - public int RewardCurrency { get; set; } + [XmlElement] public int RewardCurrency { get; set; } - public int RewardScore { get; set; } + [XmlElement] public int RewardScore { get; set; } - public bool IsMission { get; set; } + [XmlElement] public bool IsMission { get; set; } - public bool ChoiceRewards { get; set; } + [XmlElement] public bool ChoiceRewards { get; set; } - public ItemReward[] ItemRewards { get; set; } = new ItemReward[4]; + [XmlElement("ItemReward")] public ItemReward[] ItemRewards { get; set; } = new ItemReward[4]; - public ItemReward[] RepeatItemRewards { get; set; } = new ItemReward[4]; + [XmlElement("RepeatItemReward")] public ItemReward[] RepeatItemRewards { get; set; } = new ItemReward[4]; - public int[] EmoteRewards { get; set; } = new int[4]; + [XmlElement("EmoteReward")] public int[] EmoteRewards { get; set; } = new int[4]; - public int RewardMaxImagination { get; set; } + [XmlElement] public int RewardMaxImagination { get; set; } - public int RewardMaxHealth { get; set; } + [XmlElement] public int RewardMaxHealth { get; set; } - public int RewardMaxInventory { get; set; } + [XmlElement] public int RewardMaxInventory { get; set; } - public bool Repeatable { get; set; } + [XmlElement] public bool Repeatable { get; set; } - public int RepeatRewardCurrency { get; set; } + [XmlElement] public int RepeatRewardCurrency { get; set; } - public int MissionIconId { get; set; } + [XmlElement] public int MissionIconId { get; set; } - public string Prerequisites { get; set; } + [XmlElement] public string Prerequisites { get; set; } - public int OfferObject { get; set; } + [XmlElement] public int OfferObject { get; set; } - public int TargetObject { get; set; } + [XmlElement] public int TargetObject { get; set; } - public bool InMotd { get; set; } - - public List Tasks { get; set; } - - public Mission(AccessDatabase database) - { - Database = database; + [XmlElement] public bool InMotd { get; set; } - var table = database["Missions"]; - - Id = table.ClaimKey(333); - - for (var i = 0; i < 4; i++) - { - ItemRewards[i] = new ItemReward - { - Lot = -1, - Count = 0 - }; - - RepeatItemRewards[i] = new ItemReward - { - Lot = -1, - Count = 0 - }; - - EmoteRewards[i] = -1; - } - } + [XmlElement("Task")] public MissionTask[] Tasks { get; set; } = new MissionTask[1]; public int Build() { diff --git a/InfectedRose.Builder/MissionEntry.cs b/InfectedRose.Builder/MissionEntry.cs index be9e0c9..60f72e3 100644 --- a/InfectedRose.Builder/MissionEntry.cs +++ b/InfectedRose.Builder/MissionEntry.cs @@ -1,11 +1,14 @@ +using System.Xml.Serialization; + namespace InfectedRose.Builder { + [XmlRoot] public class MissionEntry { - public int MissionId { get; set; } - - public bool Offers { get; set; } - - public bool Accepting { get; set; } + [XmlElement] public int MissionId { get; set; } = 300; + + [XmlElement] public bool Offers { get; set; } = true; + + [XmlElement] public bool Accepting { get; set; } = true; } } \ No newline at end of file diff --git a/InfectedRose.Builder/MissionTask.cs b/InfectedRose.Builder/MissionTask.cs index 2310063..6e30e1f 100644 --- a/InfectedRose.Builder/MissionTask.cs +++ b/InfectedRose.Builder/MissionTask.cs @@ -1,27 +1,29 @@ using System.Linq; +using System.Xml.Serialization; using InfectedRose.Database; using InfectedRose.Database.Concepts.Tables; using InfectedRose.Database.Generic; namespace InfectedRose.Builder { + [XmlRoot] public class MissionTask { - public int TaskType { get; set; } + [XmlElement] public int TaskType { get; set; } - public int Target { get; set; } + [XmlElement] public int Target { get; set; } - public string TargetGroup { get; set; } + [XmlElement] public string TargetGroup { get; set; } - public int TargetValue { get; set; } + [XmlElement] public int TargetValue { get; set; } - public string Parameters { get; set; } + [XmlElement] public string Parameters { get; set; } - public int IconId { get; set; } + [XmlElement] public int IconId { get; set; } - public string LargeIcon { get; set; } + [XmlElement] public string LargeIcon { get; set; } - public int LargeIconId { get; set; } + [XmlElement] public int LargeIconId { get; set; } internal void Build(AccessDatabase database, int missionId) { diff --git a/InfectedRose.Builder/Npc.cs b/InfectedRose.Builder/Npc.cs index a22527b..64913f5 100644 --- a/InfectedRose.Builder/Npc.cs +++ b/InfectedRose.Builder/Npc.cs @@ -1,41 +1,30 @@ -using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; using InfectedRose.Database; using InfectedRose.Database.Concepts; namespace InfectedRose.Builder { + [XmlRoot] public class Npc { - internal AccessDatabase Database { get; } - - internal int Source { get; } - - public int Lot { get; } - - public string Name { get; set; } - - public int InteractDistance { get; set; } - - public CharacterStyle Style { get; set; } = new CharacterStyle(); - - public List Items { get; set; } = new List(); - - public List Missions { get; set; } = new List(); + [XmlIgnore] public AccessDatabase Database { get; set; } - public Npc(AccessDatabase database, int source = 12261) - { - Database = database; - Source = source; + [XmlElement] public int Lot { get; set; } = 20000; - var table = database["Objects"]; + [XmlElement] public string Name { get; set; } = "npc"; - Lot = table.ClaimKey(20000); - } + [XmlElement] public int InteractDistance { get; set; } = 5; + + [XmlElement] public CharacterStyle Style { get; set; } = new CharacterStyle(); + + [XmlElement("Item")] public int[] Items { get; set; } = new int[1]; + + [XmlElement("Mission")] public MissionEntry[] Missions { get; set; } = new MissionEntry[1]; - public int Build() + public void Build() { - var concept = Database.CopyObject(Source, Lot); + var concept = Database.CopyObject(12261, Lot); concept.Row["name"].Value = Name; concept.Row["interactionDistance"].Value = InteractDistance; @@ -67,8 +56,6 @@ public int Build() { BuildRender(render.Row); } - - return concept.Row.Key; } private void BuildCharacterStyle(Column row) diff --git a/InfectedRose.Database/Fdb/FdbRowData.cs b/InfectedRose.Database/Fdb/FdbRowData.cs index a04bd33..63a2e4e 100644 --- a/InfectedRose.Database/Fdb/FdbRowData.cs +++ b/InfectedRose.Database/Fdb/FdbRowData.cs @@ -78,6 +78,9 @@ public override void Compile(HashMap map) var b = (bool) Fields[i].value; map += b ? 1 : 0; break; + case DataType.Nothing: + map += 0; + break; default: map += Fields[i].value; break; diff --git a/InfectedRose.Database/Table.cs b/InfectedRose.Database/Table.cs index 37a3576..4b1c759 100644 --- a/InfectedRose.Database/Table.cs +++ b/InfectedRose.Database/Table.cs @@ -253,7 +253,42 @@ public Column Create(object key, object values = null) { var type = Info.Data.Fields[i].type; - column.DataHeader.Data.Fields[i] = (type, GetDefault(type)); + DataType newType; + + switch (type) + { + case DataType.Nothing: + newType = DataType.Nothing; + break; + case DataType.Integer: + newType = DataType.Integer; + break; + case DataType.Unknown1: + newType = DataType.Integer; + break; + case DataType.Float: + newType = DataType.Float; + break; + case DataType.Text: + newType = DataType.Nothing; + break; + case DataType.Boolean: + newType = DataType.Boolean; + break; + case DataType.Bigint: + newType = DataType.Nothing; + break; + case DataType.Unknown2: + newType = DataType.Integer; + break; + case DataType.Varchar: + newType = DataType.Nothing; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + column.DataHeader.Data.Fields[i] = (newType, GetDefault(type)); } var primaryKey = GetKey(key) % (list.Count > 0 ? list.Count : 1); @@ -340,11 +375,14 @@ public void Recalculate(int bucketSize) var data = this.ToArray(); - var sorter = data.ToList(); - - sorter.Sort((column, column1) => column.Key - column1.Key); + if (bucketSize == 1) + { + var sorter = data.ToList(); - data = sorter.ToArray(); + sorter.Sort((column, column1) => column.Key - column1.Key); + + data = sorter.ToArray(); + } foreach (var column in data) column.Data.Linked = default; @@ -466,9 +504,9 @@ private object GetDefault(DataType type) DataType.Float => 0, DataType.Boolean => false, DataType.Unknown2 => 0, - DataType.Varchar => new FdbString(), - DataType.Text => new FdbString(), - DataType.Bigint => new FdbBitInt(), + DataType.Varchar => null, + DataType.Text => null, + DataType.Bigint => null, _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; } diff --git a/InfectedRose.Interface/Configuration.cs b/InfectedRose.Interface/Configuration.cs new file mode 100644 index 0000000..201f7f7 --- /dev/null +++ b/InfectedRose.Interface/Configuration.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace InfectedRose.Interface +{ + [XmlRoot("Config")] + public class Configuration + { + [XmlElement("CDClient")] public string CdClient { get; set; } = "cdclient.fdb"; + + [XmlElement("Output")] public string Output { get; set; } = "/res"; + + [XmlElement("SqlOutput")] public string SqlOutput { get; set; } = "output.sql"; + + [XmlElement("Release")] public bool Release { get; set; } = false; + + [XmlElement("Zone")] public List Zones { get; set; } = new List(); + + [XmlElement("Npc")] public List Npcs { get; set; } = new List(); + + [XmlElement("Mission")] public List Mission { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/InfectedRose.Interface/InfectedRose.Interface.csproj b/InfectedRose.Interface/InfectedRose.Interface.csproj index 978e420..ad89dc5 100644 --- a/InfectedRose.Interface/InfectedRose.Interface.csproj +++ b/InfectedRose.Interface/InfectedRose.Interface.csproj @@ -6,6 +6,7 @@ + diff --git a/InfectedRose.Interface/Interface.cs b/InfectedRose.Interface/Interface.cs new file mode 100644 index 0000000..7b3a6b4 --- /dev/null +++ b/InfectedRose.Interface/Interface.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Xml.Serialization; +using InfectedRose.Builder; +using InfectedRose.Database; + +namespace InfectedRose.Interface +{ + public static class Interface + { + public static Configuration Configuration { get; private set; } + + public static AccessDatabase Database { get; private set; } + + private static List Sql { get; set; } + + private static async Task Main() + { + Sql = new List(); + + await OpenConfig(); + + Database = await AccessDatabase.OpenAsync(Configuration.CdClient); + + Database.OnSql += Sql.Add; + + await BuildZones(); + + await BuildNpcs(); + + await BuildMissions(); + + await FinalizeAsync(); + } + + private static async Task BuildZones() + { + foreach (var zone in Configuration.Zones) + { + await ZoneManager.GenerateZoneAsync(zone); + } + } + + private static async Task BuildNpcs() + { + var serializer = new XmlSerializer(typeof(Npc)); + + foreach (var npc in Configuration.Npcs) + { + if (!File.Exists(npc)) + { + var sample = new Npc(); + + await using (var stream = File.Create(npc)) + { + serializer.Serialize(stream, sample); + } + + Console.WriteLine($"Created \"{npc}\"."); + + return; + } + + Console.WriteLine($"Building {npc}."); + + await using (var stream = File.OpenRead(npc)) + { + var instance = (Npc) serializer.Deserialize(stream); + + instance.Database = Database; + + instance.Build(); + } + } + } + + private static async Task BuildMissions() + { + var serializer = new XmlSerializer(typeof(Mission)); + + foreach (var mission in Configuration.Mission) + { + if (!File.Exists(mission)) + { + var sample = new Mission(); + + await using (var stream = File.Create(mission)) + { + serializer.Serialize(stream, sample); + } + + Console.WriteLine($"Created \"{mission}\"."); + + return; + } + + Console.WriteLine($"Building {mission}."); + + await using (var stream = File.OpenRead(mission)) + { + var instance = (Mission) serializer.Deserialize(stream); + + instance.Database = Database; + + instance.Build(); + } + } + } + + private static async Task FinalizeAsync() + { + if (Sql.Count == 0) + { + Console.WriteLine("No changes to the database have been requested."); + + Environment.Exit(0); + + return; + } + + await File.WriteAllLinesAsync(Configuration.SqlOutput, Sql); + + Console.WriteLine("SQL commands saved."); + + foreach (var table in Database) + { + table.Recalculate(Configuration.Release ? 0 : 1); + } + + if (Configuration.Release) + { + Console.WriteLine("You are hashing the database for release, note that this may take several minutes."); + } + + Console.WriteLine("Hashing database, please wait..."); + + await Database.SaveAsync(Path.Combine(Configuration.Output, "cdclient.fdb")); + } + + private static async Task OpenConfig() + { + var serializer = new XmlSerializer(typeof(Configuration)); + + if (!File.Exists("config.xml")) + { + var sample = new Configuration(); + + await using (var stream = File.Create("config.xml")) + { + serializer.Serialize(stream, sample); + } + + Console.WriteLine("Created config file."); + + Environment.Exit(0); + + return; + } + + await using (var stream = File.OpenRead("config.xml")) + { + Configuration = (Configuration) serializer.Deserialize(stream); + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Interface/Program.cs b/InfectedRose.Interface/Program.cs deleted file mode 100644 index b3ce398..0000000 --- a/InfectedRose.Interface/Program.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.IO; -using System.Reflection; -using System.Threading.Tasks; -using System.Xml.Serialization; -using InfectedRose.Database; -using InfectedRose.Database.Concepts.Tables; -using InfectedRose.World; - -namespace InfectedRose.Interface -{ - internal static class Program - { - private static async Task Main(string[] args) - { - if (args.Length != 2) - { - Console.WriteLine($"Usage: {Path.GetFileName(Assembly.GetEntryAssembly()?.Location)} "); - - Environment.Exit(1); - - return; - } - - var serializer = new XmlSerializer(typeof(Zone)); - - var zone = new Zone(); - - if (File.Exists(args[0])) - { - await using var stream = File.OpenRead(args[0]); - - zone = (Zone) serializer.Deserialize(stream); - } - else - { - await using var stream = File.Create(args[0]); - - serializer.Serialize(stream, zone); - - Console.WriteLine("Created xml file"); - - Environment.Exit(1); - - return; - } - - await zone.SaveAsync(Path.GetDirectoryName(args[0])); - - var database = await AccessDatabase.OpenAsync(args[1]); - - var zones = database["ZoneTable"]; - - foreach (var row in zones) - { - if (Enum.IsDefined(typeof(ZoneId), (ushort) row.Key)) continue; - - zones.Remove(row); - } - - var entry = new ZoneTableTable(zones.Create(zone.Id)); - - entry.zoneName = zone.Name; - entry.zoneID = (int) zone.Id; - entry.ghostdistance = zone.GhostDistance; - entry.scriptID = -1; - entry.locStatus = 0; - entry.DisplayDescription = zone.Description; - - foreach (var table in database) - { - table.Recalculate(); - } - - var pad = 0; - - await database.SaveAsync(args[1], i => - { - if (++pad != 10000) return; - - Console.WriteLine(i); - - pad = 0; - }); - } - } -} \ No newline at end of file diff --git a/InfectedRose.Interface/README.md b/InfectedRose.Interface/README.md new file mode 100644 index 0000000..230be84 --- /dev/null +++ b/InfectedRose.Interface/README.md @@ -0,0 +1,170 @@ +# InfectedRose.Interface +A interface for interacting with the many libraries of InfectedRose. This is done through xml files which can be used to specify new npcs, missions, and zones. + +## Setup +* Run the interface through `dotnet ./InfectedRose.Interface.dll`, this will generate the `config.xml` file. +* In this file you need to specify the `res` directory of your unpacked LEGO Universe client. +* The `cdclient.fdb` should be copied to same folder as this interface. Version control for modifications is not implemented yet, so the interface has to start from a new database each time. +* Create your xml files, see Examples. +* Run the interface again, this will modify the client files and its database. +* A SQL file will be generated which you should run on your server's CDClient. + +## Examples +###### config.xml +```xml + + cdclient.fdb + /mnt/disk/LEGO Universe/res + output.sql + false + npc.xml + mission.xml + zone.xml + +``` +###### npc.xml +```xml + + 20000 + my npc + 5 + + 6938 + + 30000 + true + true + + +``` +###### mission.xml +```xml + + 30000 + Location + Venture Explorer + 0 + 666 + 10 + true + false + -1 + -1 + -1 + -1 + 0 + 4 + 4 + false + 0 + 0 + 20000 + 20000 + false + + 2620 + 42 + + + -1 + 0 + + + -1 + 0 + + + -1 + 0 + + + -1 + 0 + + + -1 + 0 + + + -1 + 0 + + + -1 + 0 + + -1 + -1 + -1 + -1 + + 0 + 4712 + 6351,8088,8089,9744 + 3 + + + 2908 + ..\..\textures\ui\missioncomics\Wonderland\Avant_Gardens\Task_Icons\Battle_Maelstrom_Task.dds + 2908 + + +``` +###### zone.xml +Note: creating new zones is still work in progress. Terrain files can be created via code using InfectedRose.Terrain. +```xml + + my_maps/zone/zone.luz + 60000 + 1 + 500 + amazing zone + + mesh\env\NG_NinjaGo\env_nj_mon_sky.nif + + + 0 + 30 + 0 + + + 0 + 0 + 0 + 1 + + 1 + + + + + 0 + 0 + 0 + + + 0 + 0 + 0 + 1 + + + terrain.raw + terrain + terrain file + + +``` \ No newline at end of file diff --git a/InfectedRose.Interface/ZoneId.cs b/InfectedRose.Interface/ZoneId.cs deleted file mode 100644 index 1f81434..0000000 --- a/InfectedRose.Interface/ZoneId.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace InfectedRose.Interface -{ - public enum ZoneId : ushort - { - VentureExplorerCinematic, - VentureExplorer = 1000, - ReturnToVentureExplorer, - AvantGardens = 1100, - AvantGardensSurvival, - SpiderQueenBattle, - BlockYard = 1150, - AvantGrove, - NimbusStation = 1200, - PetCove, - VertigoLoopRacetrack = 1203, - BattleOfNimbusStation, - NimbusRock = 1250, - NimbusIsle, - FrostBurgh = 1260, - GnarledForest = 1300, - CanyonCove = 1302, - KeelhaulCanyon, - ChanteyShantey = 1350, - ForbiddenValley = 1400, - ForbiddenValleyDragon = 1402, - DragonmawChasm, - RavenBluff = 1450, - Starbase3001 = 1600, - DeepFreeze, - RobotCity, - MoonBase, - Portabello = 1604, - LegoClub = 1700, - CruxPrime = 1800, - NexusTower = 1900, - Ninjago = 2000, - FrakjawBattle, - NimbusStationWinterRacetrack = 1261 - } -} \ No newline at end of file diff --git a/InfectedRose.Interface/ZoneManager.cs b/InfectedRose.Interface/ZoneManager.cs new file mode 100644 index 0000000..a97dec7 --- /dev/null +++ b/InfectedRose.Interface/ZoneManager.cs @@ -0,0 +1,95 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using System.Xml.Serialization; +using InfectedRose.Database.Concepts.Tables; +using InfectedRose.Luz; +using InfectedRose.Lvl; +using InfectedRose.World; +using RakDotNet.IO; + +namespace InfectedRose.Interface +{ + public static class ZoneManager + { + public static async Task GenerateZoneAsync(string file) + { + var serializer = new XmlSerializer(typeof(Zone)); + + var zone = new Zone(); + + if (File.Exists(file)) + { + await using var stream = File.OpenRead(file); + + zone = (Zone) serializer.Deserialize(stream); + } + else + { + await using var stream = File.Create(file); + + serializer.Serialize(stream, zone); + + Console.WriteLine($"Created zone config file: \"{file}\"."); + + return; + } + + await zone.SaveAsync(Path.Combine(Interface.Configuration.Output, "maps")); + + Console.WriteLine("Saved, running through checks."); + + await RunChecksAsync(zone); + + Console.WriteLine("Adding zone to database."); + + var zones = Interface.Database["ZoneTable"]; + + var row = zones.Create(zone.Id); + + var _ = new ZoneTableTable(row) + { + zoneName = zone.Name, + zoneID = (int) zone.Id, + ghostdistance = zone.GhostDistance, + scriptID = -1, + locStatus = 0, + DisplayDescription = zone.Description + }; + } + + private static async Task RunChecksAsync(Zone zone) + { + var name = Path.GetFileName(zone.Name); + + var file = new LuzFile(); + + Console.WriteLine($"Checking: {name}..."); + + await using (var stream = File.OpenRead(name)) + { + using var reader = new BitReader(stream); + + file.Deserialize(reader); + } + + Console.WriteLine("Passed"); + + foreach (var scene in file.Scenes) + { + var lvl = new LvlFile(); + + Console.WriteLine($"Checking: {scene.FileName}..."); + + await using (var stream = File.OpenRead(scene.FileName)) + { + using var reader = new BitReader(stream); + + lvl.Deserialize(reader); + } + + Console.WriteLine("Passed"); + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Lvl/LevelInfo.cs b/InfectedRose.Lvl/LevelInfo.cs index 98b9865..0fe915d 100644 --- a/InfectedRose.Lvl/LevelInfo.cs +++ b/InfectedRose.Lvl/LevelInfo.cs @@ -1,4 +1,3 @@ -using System; using InfectedRose.Core; using RakDotNet.IO; @@ -48,8 +47,6 @@ public override void Deserialize(BitReader reader) AddressChunk2001 = reader.Read(); AddressChunk2002 = reader.Read(); - - Console.WriteLine($"{AddressChunk2000} | {AddressChunk2001} | {AddressChunk2002}"); } } } \ No newline at end of file diff --git a/InfectedRose.Lvl/LvlFile.cs b/InfectedRose.Lvl/LvlFile.cs index 55375ef..60d990f 100644 --- a/InfectedRose.Lvl/LvlFile.cs +++ b/InfectedRose.Lvl/LvlFile.cs @@ -29,6 +29,8 @@ public void Serialize(BitWriter writer) { if (OldLevelHeader == default) { + LevelInfo.LvlVersion = LvlVersion; + SerializeNew(writer); return; diff --git a/InfectedRose.World/Scene.cs b/InfectedRose.World/Scene.cs index eef7cce..80b1069 100644 --- a/InfectedRose.World/Scene.cs +++ b/InfectedRose.World/Scene.cs @@ -26,7 +26,7 @@ public class Scene public LuzScene LuzScene => new LuzScene { - FileName = $"{Name.Replace(" ", "_")}.lvl", + FileName = $"{Name.Replace(" ", "_").ToLower()}.lvl", SceneName = Name, SceneId = Id, LayerId = Layer diff --git a/InfectedRose.World/Zone.cs b/InfectedRose.World/Zone.cs index 2237951..7c4eb2d 100644 --- a/InfectedRose.World/Zone.cs +++ b/InfectedRose.World/Zone.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -22,28 +23,7 @@ public class Zone [XmlElement] public string Description { get; set; } = "amazing zone"; - [XmlElement("Scene")] public List Scenes { get; set; } = new List - { - new Scene - { - Id = 0, - Layer = 0, - Name = "global scene", - Objects = new List - { - new WorldObject - { - AssetType = 1, - Lot = 31, - Scale = 1, - Info = "", - Rotation = Quaternion.Identity - } - }, - Revision = 1, - SkyBox = "SkyBox" - } - }; + [XmlElement("Scene")] public List Scenes { get; set; } = new List(); [XmlElement] public Vector3 SpawnPosition { get; set; } @@ -66,7 +46,16 @@ public async Task SaveAsync(string path) RevisionNumber = Revision }; - await using var stream = File.Create(Path.Combine(path, $"{Path.GetFileName(Name)}")); + var zoneFile = Path.Combine(path, Name); + + var root = Path.GetDirectoryName(zoneFile); + + if (!Directory.Exists(root)) + { + Directory.CreateDirectory(root); + } + + await using var stream = File.Create(zoneFile); using var writer = new BitWriter(stream); @@ -74,7 +63,7 @@ public async Task SaveAsync(string path) foreach (var scene in Scenes) { - await scene.SaveAsync(path); + await scene.SaveAsync(Path.Combine(path, Path.GetDirectoryName(Name))); } } }