mirror of
https://github.com/Wincent01/InfectedRose.git
synced 2025-12-30 08:49:32 -06:00
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
23
InfectedRose.Interface/Configuration.cs
Normal file
23
InfectedRose.Interface/Configuration.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
168
InfectedRose.Interface/Interface.cs
Normal file
168
InfectedRose.Interface/Interface.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
170
InfectedRose.Interface/README.md
Normal file
170
InfectedRose.Interface/README.md
Normal 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>
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
95
InfectedRose.Interface/ZoneManager.cs
Normal file
95
InfectedRose.Interface/ZoneManager.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ namespace InfectedRose.Lvl
|
||||
{
|
||||
if (OldLevelHeader == default)
|
||||
{
|
||||
LevelInfo.LvlVersion = LvlVersion;
|
||||
|
||||
SerializeNew(writer);
|
||||
|
||||
return;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user