InfectedRose.Interface:

* An interface for adding npcs, missions, and zones.
* Emit SQL to run on your server.
* See README for InfectedRose.Interface for more info.
This commit is contained in:
wincent
2020-03-08 17:29:00 +01:00
parent f2e85df457
commit 078de1175a
19 changed files with 603 additions and 281 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<MissionTask> Tasks { get; set; }
[XmlElement] public bool InMotd { get; set; }
public Mission(AccessDatabase database)
{
Database = database;
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()
{

View File

@@ -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;
}
}

View File

@@ -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)
{

View File

@@ -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<int> Items { get; set; } = new List<int>();
public List<MissionEntry> Missions { get; set; } = new List<MissionEntry>();
[XmlIgnore] public AccessDatabase Database { get; set; }
public Npc(AccessDatabase database, int source = 12261)
[XmlElement] public int Lot { get; set; } = 20000;
[XmlElement] public string Name { get; set; } = "npc";
[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 void Build()
{
Database = database;
Source = source;
var table = database["Objects"];
Lot = table.ClaimKey(20000);
}
public int 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 @@ namespace InfectedRose.Builder
{
BuildRender(render.Row);
}
return concept.Row.Key;
}
private void BuildCharacterStyle(Column row)

View File

@@ -78,6 +78,9 @@ namespace InfectedRose.Database.Fdb
var b = (bool) Fields[i].value;
map += b ? 1 : 0;
break;
case DataType.Nothing:
map += 0;
break;
default:
map += Fields[i].value;
break;

View File

@@ -253,7 +253,42 @@ namespace InfectedRose.Database
{
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 @@ namespace InfectedRose.Database
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 @@ namespace InfectedRose.Database
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)
};
}

View File

@@ -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<string> Zones { get; set; } = new List<string>();
[XmlElement("Npc")] public List<string> Npcs { get; set; } = new List<string>();
[XmlElement("Mission")] public List<string> Mission { get; set; } = new List<string>();
}
}

View File

@@ -6,6 +6,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\InfectedRose.Builder\InfectedRose.Builder.csproj" />
<ProjectReference Include="..\InfectedRose.Database\InfectedRose.Database.csproj" />
<ProjectReference Include="..\InfectedRose.World\InfectedRose.World.csproj" />
</ItemGroup>

View File

@@ -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<string> Sql { get; set; }
private static async Task Main()
{
Sql = new List<string>();
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);
}
}
}
}

View File

@@ -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)} <xml-file> <fdb>");
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;
});
}
}
}

View File

@@ -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
<Config>
<CDClient>cdclient.fdb</CDClient>
<Output>/mnt/disk/LEGO Universe/res</Output>
<SqlOutput>output.sql</SqlOutput>
<Release>false</Release>
<Npc>npc.xml</Npc>
<Mission>mission.xml</Mission>
<Zone>zone.xml</Zone>
</Config>
```
###### npc.xml
```xml
<Npc>
<Lot>20000</Lot>
<Name>my npc</Name>
<InteractDistance>5</InteractDistance>
<Style>
<Chest>14</Chest>
<ChestDecal>38</ChestDecal>
<EyeBrowStyle>33</EyeBrowStyle>
<EyesStyle>10</EyesStyle>
<HairColor>2</HairColor>
<HairStyle>6</HairStyle>
<Head>0</Head>
<HeadColor>0</HeadColor>
<LeftHand>0</LeftHand>
<Legs>5</Legs>
<MouthStyle>11</MouthStyle>
<RightHand>0</RightHand>
</Style>
<Item>6938</Item>
<Mission>
<MissionId>30000</MissionId>
<Offers>true</Offers>
<Accepting>true</Accepting>
</Mission>
</Npc>
```
###### mission.xml
```xml
<Mission>
<Id>30000</Id>
<Type>Location</Type>
<SubType>Venture Explorer</SubType>
<UiSortOrder>0</UiSortOrder>
<RewardCurrency>666</RewardCurrency>
<RewardScore>10</RewardScore>
<IsMission>true</IsMission>
<ChoiceRewards>false</ChoiceRewards>
<EmoteRewards>-1</EmoteRewards>
<EmoteRewards>-1</EmoteRewards>
<EmoteRewards>-1</EmoteRewards>
<EmoteRewards>-1</EmoteRewards>
<RewardMaxImagination>0</RewardMaxImagination>
<RewardMaxHealth>4</RewardMaxHealth>
<RewardMaxInventory>4</RewardMaxInventory>
<Repeatable>false</Repeatable>
<RepeatRewardCurrency>0</RepeatRewardCurrency>
<MissionIconId>0</MissionIconId>
<OfferObject>20000</OfferObject>
<TargetObject>20000</TargetObject>
<InMotd>false</InMotd>
<ItemReward>
<Lot>2620</Lot>
<Count>42</Count>
</ItemReward>
<ItemReward>
<Lot>-1</Lot>
<Count>0</Count>
</ItemReward>
<ItemReward>
<Lot>-1</Lot>
<Count>0</Count>
</ItemReward>
<ItemReward>
<Lot>-1</Lot>
<Count>0</Count>
</ItemReward>
<RepeatItemReward>
<Lot>-1</Lot>
<Count>0</Count>
</RepeatItemReward>
<RepeatItemReward>
<Lot>-1</Lot>
<Count>0</Count>
</RepeatItemReward>
<RepeatItemReward>
<Lot>-1</Lot>
<Count>0</Count>
</RepeatItemReward>
<RepeatItemReward>
<Lot>-1</Lot>
<Count>0</Count>
</RepeatItemReward>
<EmoteReward>-1</EmoteReward>
<EmoteReward>-1</EmoteReward>
<EmoteReward>-1</EmoteReward>
<EmoteReward>-1</EmoteReward>
<Task>
<TaskType>0</TaskType>
<Target>4712</Target>
<TargetGroup>6351,8088,8089,9744</TargetGroup>
<TargetValue>3</TargetValue>
<Parameters>
</Parameters>
<IconId>2908</IconId>
<LargeIcon>..\..\textures\ui\missioncomics\Wonderland\Avant_Gardens\Task_Icons\Battle_Maelstrom_Task.dds</LargeIcon>
<LargeIconId>2908</LargeIconId>
</Task>
</Mission>
```
###### zone.xml
Note: creating new zones is still work in progress. Terrain files can be created via code using InfectedRose.Terrain.
```xml
<Zone>
<Name>my_maps/zone/zone.luz</Name>
<Id>60000</Id>
<Revision>1</Revision>
<GhostDistance>500</GhostDistance>
<Description>amazing zone</Description>
<Scene Name="Global Scene" Id="0" Layer="0" Revision="1">
<SkyBox>mesh\env\NG_NinjaGo\env_nj_mon_sky.nif</SkyBox>
<Object Lot="31" AssetType="1">
<Position>
<X>0</X>
<Y>30</Y>
<Z>0</Z>
</Position>
<Rotation>
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<W>1</W>
</Rotation>
<Scale>1</Scale>
<Info />
</Object>
</Scene>
<SpawnPosition>
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</SpawnPosition>
<SpawnRotation>
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<W>1</W>
</SpawnRotation>
<Terrain>
<FileName>terrain.raw</FileName>
<Name>terrain</Name>
<Description>terrain file</Description>
</Terrain>
</Zone>
```

View File

@@ -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
}
}

View File

@@ -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");
}
}
}
}

View File

@@ -1,4 +1,3 @@
using System;
using InfectedRose.Core;
using RakDotNet.IO;
@@ -48,8 +47,6 @@ namespace InfectedRose.Lvl
AddressChunk2001 = reader.Read<uint>();
AddressChunk2002 = reader.Read<uint>();
Console.WriteLine($"{AddressChunk2000} | {AddressChunk2001} | {AddressChunk2002}");
}
}
}

View File

@@ -29,6 +29,8 @@ namespace InfectedRose.Lvl
{
if (OldLevelHeader == default)
{
LevelInfo.LvlVersion = LvlVersion;
SerializeNew(writer);
return;

View File

@@ -26,7 +26,7 @@ namespace InfectedRose.World
public LuzScene LuzScene => new LuzScene
{
FileName = $"{Name.Replace(" ", "_")}.lvl",
FileName = $"{Name.Replace(" ", "_").ToLower()}.lvl",
SceneName = Name,
SceneId = Id,
LayerId = Layer

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -22,28 +23,7 @@ namespace InfectedRose.World
[XmlElement] public string Description { get; set; } = "amazing zone";
[XmlElement("Scene")] public List<Scene> Scenes { get; set; } = new List<Scene>
{
new Scene
{
Id = 0,
Layer = 0,
Name = "global scene",
Objects = new List<WorldObject>
{
new WorldObject
{
AssetType = 1,
Lot = 31,
Scale = 1,
Info = "",
Rotation = Quaternion.Identity
}
},
Revision = 1,
SkyBox = "SkyBox"
}
};
[XmlElement("Scene")] public List<Scene> Scenes { get; set; } = new List<Scene>();
[XmlElement] public Vector3 SpawnPosition { get; set; }
@@ -66,7 +46,16 @@ namespace InfectedRose.World
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 @@ namespace InfectedRose.World
foreach (var scene in Scenes)
{
await scene.SaveAsync(path);
await scene.SaveAsync(Path.Combine(path, Path.GetDirectoryName(Name)));
}
}
}