mirror of
https://github.com/Wincent01/InfectedRose.git
synced 2026-01-01 17:59:38 -06:00
645 lines
26 KiB
C#
645 lines
26 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Nodes;
|
|
using System.Xml;
|
|
using System.Xml.Serialization;
|
|
using InfectedRose.Core;
|
|
using InfectedRose.Database;
|
|
using InfectedRose.Interface.Templates.ValueTypes;
|
|
using InfectedRose.Luz;
|
|
using InfectedRose.Lvl;
|
|
using InfectedRose.Triggers;
|
|
using RakDotNet.IO;
|
|
|
|
namespace InfectedRose.Interface.Templates;
|
|
|
|
[ModType("zone")]
|
|
public class ZoneMod : ModType
|
|
{
|
|
public void InsertZone(Mod mod)
|
|
{
|
|
var zoneTable = ModContext.Database["ZoneTable"];
|
|
|
|
Row entry;
|
|
|
|
if (ModContext.TryGetFromLookup(mod, out var key))
|
|
{
|
|
if (!zoneTable.Seek(key, out entry))
|
|
{
|
|
entry = zoneTable.Create(key);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var i = 1000;; i += 100)
|
|
{
|
|
if (zoneTable.ContainsKey(i))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
entry = zoneTable.Create(i);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
mod.Default("ghostdistance_min", 150);
|
|
mod.Default("ghostdistance", 250);
|
|
mod.Default("population_soft_cap", 10);
|
|
mod.Default("population_hard_cap", 15);
|
|
mod.DefaultNull("smashableMinDistance");
|
|
mod.DefaultNull("smashableMaxDistance");
|
|
mod.DefaultNull("zoneControlTemplate");
|
|
mod.DefaultNull("widthInChunks");
|
|
mod.DefaultNull("heightInChunks");
|
|
mod.Default("petsAllowed", true);
|
|
mod.Default("localize", true);
|
|
mod.Default("fZoneWeight", 1);
|
|
mod.Default("PlayersLoseCoinsOnDeath", true);
|
|
mod.DefaultNull("teamRadius");
|
|
mod.Default("mountsAllowed", true);
|
|
|
|
ModContext.RegisterId(mod.Id, entry.Key);
|
|
|
|
ModContext.ApplyValues(mod, entry, zoneTable);
|
|
|
|
if (mod.Locale != null)
|
|
{
|
|
ModContext.AddToLocale($"ZoneTable_{entry.Key}_DisplayDescription", mod.Locale);
|
|
}
|
|
|
|
if (mod.HasValue("zone"))
|
|
{
|
|
entry["zoneName"].Value = ModContext.ParseValue(mod.GetValue<string>("zone"));
|
|
}
|
|
}
|
|
|
|
public void AddZone(Mod mod)
|
|
{
|
|
var zoneTable = ModContext.Database["ZoneTable"];
|
|
|
|
Row entry;
|
|
|
|
if (ModContext.TryGetFromLookup(mod, out var key))
|
|
{
|
|
if (!zoneTable.Seek(key, out entry))
|
|
{
|
|
entry = zoneTable.Create(key);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var i = 1000;; i += 100)
|
|
{
|
|
if (zoneTable.ContainsKey(i))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
entry = zoneTable.Create(i);
|
|
|
|
break;
|
|
}
|
|
}
|
|
mod.Default("ghostdistance_min", 150);
|
|
mod.Default("ghostdistance", 250);
|
|
mod.Default("population_soft_cap", 10);
|
|
mod.Default("population_hard_cap", 15);
|
|
mod.DefaultNull("smashableMinDistance");
|
|
mod.DefaultNull("smashableMaxDistance");
|
|
mod.DefaultNull("zoneControlTemplate");
|
|
mod.DefaultNull("widthInChunks");
|
|
mod.DefaultNull("heightInChunks");
|
|
mod.Default("petsAllowed", true);
|
|
mod.Default("localize", true);
|
|
mod.Default("fZoneWeight", 1);
|
|
mod.Default("PlayersLoseCoinsOnDeath", true);
|
|
mod.DefaultNull("teamRadius");
|
|
mod.Default("mountsAllowed", true);
|
|
|
|
ModContext.RegisterId(mod.Id, entry.Key);
|
|
|
|
ModContext.ApplyValues(mod, entry, zoneTable);
|
|
|
|
var zone = mod.Zone!;
|
|
|
|
var fileName = mod.Id.Replace("-", "_").Replace(":", "_");
|
|
|
|
var root = Path.Combine(ModContext.Root, ModContext.Configuration.ResourceFolder, $"./compiled/{fileName}/");
|
|
|
|
root = new Uri(root).LocalPath;
|
|
|
|
if (!Directory.Exists(root))
|
|
{
|
|
Directory.CreateDirectory(root);
|
|
}
|
|
else
|
|
{
|
|
foreach (var file in Directory.EnumerateFiles(root))
|
|
{
|
|
File.Delete(file);
|
|
}
|
|
}
|
|
|
|
var terrainFile = $"{fileName}.raw";
|
|
|
|
File.Copy(zone.TerrainFile, Path.Combine(root, terrainFile));
|
|
|
|
var luzFile = new LuzFile();
|
|
|
|
luzFile.TerrainFile = terrainFile;
|
|
luzFile.TerrainFileName = terrainFile;
|
|
luzFile.TerrainDescription = Path.GetFileNameWithoutExtension(terrainFile);
|
|
|
|
luzFile.Version = 0x29U;
|
|
|
|
luzFile.RevisionNumber = 1;
|
|
|
|
luzFile.SpawnPoint = zone.SpawnPoint;
|
|
luzFile.SpawnRotation = zone.SpawnRotation;
|
|
|
|
luzFile.WorldId = (uint)entry.Key;
|
|
|
|
luzFile.PathFormatVersion = 1;
|
|
|
|
luzFile.PathData = new LuzPathData[zone.Paths.Length];
|
|
|
|
for (var index = 0; index < zone.Paths.Length; index++)
|
|
{
|
|
var data = zone.Paths[index];
|
|
LuzPathData luzPathData;
|
|
|
|
const uint version = 0x12U;
|
|
|
|
var type = Enum.Parse<PathType>(data.Type);
|
|
|
|
switch (type)
|
|
{
|
|
case PathType.Movement:
|
|
luzPathData = new LuzPathData(version);
|
|
luzPathData.Waypoints = data.Waypoints.Select(w =>
|
|
{
|
|
return (LuzPathWaypoint) new LuzMovementWaypoint(version)
|
|
{
|
|
Position = w.Position,
|
|
Configs = w.Configuration.Select(c => new LuzPathConfig()
|
|
{
|
|
ConfigName = c.Name,
|
|
ConfigTypeAndValue = c.Value.ToString()
|
|
}).ToArray()
|
|
};
|
|
}).ToArray();
|
|
break;
|
|
case PathType.MovingPlatform:
|
|
var movingPlatformPath = new LuzMovingPlatformPath(version);
|
|
luzPathData = movingPlatformPath;
|
|
movingPlatformPath.MovingPlatformSound = data.Sound;
|
|
movingPlatformPath.TimeBased = data.TimeBased!.Value;
|
|
luzPathData.Waypoints = data.Waypoints.Select(w => (LuzPathWaypoint) new LuzMovingPlatformWaypoint(version)
|
|
{
|
|
Position = w.Position,
|
|
Rotation = w.Rotation!.Value,
|
|
LockPlayer = w.LockPlayer!.Value,
|
|
Speed = w.Speed!.Value,
|
|
Wait = w.Wait!.Value,
|
|
DepartSound = w.DepartSound,
|
|
ArriveSound = w.ArriveSound
|
|
}).ToArray();
|
|
break;
|
|
case PathType.Property:
|
|
var propertyPath = new LuzPropertyPath(version);
|
|
luzPathData = propertyPath;
|
|
propertyPath.Price = data.Price!.Value;
|
|
propertyPath.RentalTime = data.RentalTime!.Value;
|
|
propertyPath.AssociatedZone = ulong.Parse(data.AssociativeZone!);
|
|
propertyPath.DisplayName = data.DisplayName;
|
|
propertyPath.DisplayDescription = data.DisplayDescription;
|
|
propertyPath.CloneLimit = data.CloneLimit!.Value;
|
|
propertyPath.ReputationMultiplier = data.ReputationMultiplier!.Value;
|
|
propertyPath.TimeUnit = Enum.Parse<RentalTimeUnit>(data.TimeUnit);
|
|
propertyPath.Achievement = Enum.Parse<AchievementRequired>(data.Achievement);
|
|
propertyPath.PlayerZonePoint = data.PlayerZonePoint!.Value;
|
|
propertyPath.MaxBuildHeight = data.MaxBuildHeight!.Value;
|
|
luzPathData.Waypoints = data.Waypoints.Select(w => (LuzPathWaypoint) new LuzPathWaypoint(version)
|
|
{
|
|
Position = w.Position
|
|
}).ToArray();
|
|
break;
|
|
case PathType.Camera:
|
|
var cameraPath = new LuzCameraPath(version);
|
|
luzPathData = cameraPath;
|
|
cameraPath.NextPath = data.NextPath;
|
|
cameraPath.Waypoints = data.Waypoints.Select(w => (LuzPathWaypoint) new LuzCameraWaypoint(version)
|
|
{
|
|
Position = w.Position,
|
|
Rotation = w.Rotation!.Value,
|
|
Time = w.Time!.Value,
|
|
Tension = w.Tension!.Value,
|
|
Continuity = w.Continuity!.Value,
|
|
Bias = w.Bias!.Value,
|
|
FieldOfView = w.FieldOfView!.Value
|
|
}).ToArray();
|
|
break;
|
|
case PathType.Spawner:
|
|
var spawnerPath = new LuzSpawnerPath(version);
|
|
luzPathData = spawnerPath;
|
|
spawnerPath.SpawnedId = data.SpawnedId;
|
|
spawnerPath.SpawnedLot = (uint)ModContext.AssertId(data.SpawnedId!);
|
|
spawnerPath.RespawnTime = (uint)data.RespawnTime!.Value;
|
|
spawnerPath.MaxSpawnCount = data.MaxSpawnCount!.Value;
|
|
spawnerPath.NumberToMaintain = (uint)data.NumberToMaintain!.Value;
|
|
spawnerPath.SpawnerObject = data.SpawnerObject;
|
|
spawnerPath.SpawnerObjectId = long.Parse(data.SpawnerObject!);
|
|
spawnerPath.ActivateSpawnerNetworkOnLoad = data.ActivateOnLoad!.Value;
|
|
luzPathData.Waypoints = data.Waypoints.Select(w =>
|
|
{
|
|
return (LuzPathWaypoint) new LuzSpawnerWaypoint(version)
|
|
{
|
|
Position = w.Position,
|
|
Configs = w.Configuration.Select(c => new LuzPathConfig()
|
|
{
|
|
ConfigName = c.Name,
|
|
ConfigTypeAndValue = c.Value.ToString()
|
|
}).ToArray()
|
|
};
|
|
}).ToArray();
|
|
break;
|
|
case PathType.Showcase:
|
|
luzPathData = new LuzPathData(version);
|
|
luzPathData.Waypoints = data.Waypoints.Select(w => (LuzPathWaypoint) new LuzPathWaypoint(version)
|
|
{
|
|
Position = w.Position
|
|
}).ToArray();
|
|
break;
|
|
case PathType.Race:
|
|
luzPathData = new LuzPathData(version);
|
|
luzPathData.Waypoints = data.Waypoints.Select(w => (LuzPathWaypoint) new LuzRaceWaypoint(version)
|
|
{
|
|
Position = w.Position,
|
|
Rotation = w.Rotation!.Value
|
|
}).ToArray();
|
|
break;
|
|
case PathType.Rail:
|
|
luzPathData = new LuzPathData(version);
|
|
luzPathData.Waypoints = data.Waypoints.Select(w => (LuzPathWaypoint) new LuzRailWaypoint(version)
|
|
{
|
|
Position = w.Position,
|
|
UnknownQuaternion = w.Rotation!.Value,
|
|
Speed = w.Speed!.Value,
|
|
Configs = w.Configuration.Select(c => new LuzPathConfig()
|
|
{
|
|
ConfigName = c.Name,
|
|
ConfigTypeAndValue = c.Value.ToString()
|
|
}).ToArray()
|
|
}).ToArray();
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
luzPathData.Type = type;
|
|
luzPathData.PathName = data.Name;
|
|
luzPathData.Behavior = (PathBehavior)Enum.Parse(typeof(PathBehavior), data.Behavior);
|
|
|
|
luzFile.PathData[index] = luzPathData;
|
|
}
|
|
|
|
luzFile.Scenes = new LuzScene[zone.Scenes.Length];
|
|
|
|
var objId = 0x38B40AUL;
|
|
|
|
var taken = new HashSet<ulong>();
|
|
|
|
for (var i = 0; i < zone.Scenes.Length; ++i)
|
|
{
|
|
var lvl = new LvlFile();
|
|
var luzScene = luzFile.Scenes[i] = new LuzScene();
|
|
|
|
var scene = zone.Scenes[i];
|
|
|
|
luzScene.LayerId = (uint)scene.Layer;
|
|
luzScene.SceneId = (uint)scene.Id;
|
|
luzScene.SceneName = scene.Name;
|
|
string filename;
|
|
if (scene.Layer == 0)
|
|
{
|
|
filename = Path.Combine(root, $"{fileName}_{scene.Id}_{scene.Name.ToLower().Replace(" ", "_")}.lvl");
|
|
}
|
|
else
|
|
{
|
|
filename = Path.Combine(root, $"{fileName}_{scene.Id}x{scene.Layer}_{scene.Name.ToLower().Replace(" ", "_")}.lvl");
|
|
}
|
|
luzScene.FileName = Path.GetFileName(filename);
|
|
|
|
lvl.LvlVersion = 0x2D;
|
|
|
|
if (scene.Layer == 0)
|
|
{
|
|
var levelSkyConfig = new LevelSkyConfig();
|
|
|
|
levelSkyConfig.Skybox[0] = scene.Skybox;
|
|
|
|
levelSkyConfig.Identifiers = new IdStruct[11]
|
|
{
|
|
new IdStruct(),
|
|
new IdStruct(1, 100, 150),
|
|
new IdStruct(2, 150, 200),
|
|
new IdStruct(3, 200, 250),
|
|
new IdStruct(4, 350, 450),
|
|
new IdStruct(5, 50, 100),
|
|
new IdStruct(6, 40, 40),
|
|
new IdStruct(7, 400, 600),
|
|
new IdStruct(8, 60, 100),
|
|
new IdStruct(9, 50, 100),
|
|
new IdStruct(10, 300, 400)
|
|
};
|
|
|
|
levelSkyConfig.SavedColors = new byte[388]
|
|
{
|
|
32, 0, 0, 0, 141, 140, 12, 62, 141, 140, 12, 62, 193, 192, 64, 62, 255, 254, 126, 63, 0, 0, 128, 63,
|
|
222, 221, 93, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 245, 117, 63, 181, 180, 52,
|
|
62, 0, 0, 0, 0, 181, 180, 180, 62, 161, 160, 160, 62, 0, 0, 0, 0, 184, 183, 55, 63, 227, 226, 98,
|
|
63, 0, 0, 0, 0, 184, 183, 55, 63, 227, 226, 98, 63, 255, 254, 126, 63, 0, 0, 128, 63, 222, 221, 93,
|
|
63, 166, 165, 37, 63, 166, 165, 37, 63, 166, 165, 37, 63, 0, 0, 0, 0, 181, 180, 180, 62, 161, 160,
|
|
160, 62, 0, 0, 0, 0, 181, 180, 52, 62, 161, 160, 32, 62, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
|
|
63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
|
|
128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
|
|
0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
|
|
63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
|
|
128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
|
|
0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
|
|
63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
|
|
128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
|
|
0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
|
|
63
|
|
};
|
|
|
|
levelSkyConfig.LightInformation = new float[25]
|
|
{
|
|
scene.BlendTime,
|
|
scene.AmbientColor.R, scene.AmbientColor.G, scene.AmbientColor.B,
|
|
scene.SpecularColor.R, scene.SpecularColor.G, scene.SpecularColor.B,
|
|
scene.UpperHemiColor.R, scene.UpperHemiColor.G, scene.UpperHemiColor.B,
|
|
scene.LightDirection.X, scene.LightDirection.Y, scene.LightDirection.Z,
|
|
scene.FogNearMin, scene.FogFarMin, scene.PostFogSolidMin, scene.PostFogFadeMin,
|
|
0, 0,
|
|
scene.FogNearMax, scene.FogFarMax, scene.PostFogSolidMax, scene.PostFogFadeMax,
|
|
0, 0
|
|
};
|
|
|
|
levelSkyConfig.FogColor = new[]
|
|
{
|
|
scene.FogColor.R, scene.FogColor.G, scene.FogColor.B
|
|
};
|
|
|
|
levelSkyConfig.DirectionalLightColor = new[]
|
|
{
|
|
scene.DirectionalLightColor.R, scene.DirectionalLightColor.G, scene.DirectionalLightColor.B
|
|
};
|
|
|
|
lvl.LevelSkyConfig = levelSkyConfig;
|
|
}
|
|
|
|
var levelObjects = new LevelObjects(lvl.LvlVersion);
|
|
|
|
levelObjects.Templates = new LevelObjectTemplate[scene.Templates.Length];
|
|
|
|
for (var o = 0; o < scene.Templates.Length; o++)
|
|
{
|
|
var template = scene.Templates[o];
|
|
var levelObjectTemplate = levelObjects.Templates[o] = new LevelObjectTemplate();
|
|
|
|
levelObjectTemplate.Lot = ModContext.AssertId(template.Id);
|
|
levelObjectTemplate.Position = template.Position;
|
|
levelObjectTemplate.Rotation = template.Rotation;
|
|
levelObjectTemplate.Scale = template.Scale ?? 1;
|
|
levelObjectTemplate.AssetType = (uint) (template.Type ?? 1);
|
|
levelObjectTemplate.GlomId = 1;
|
|
|
|
var objectId = template.ObjectId ?? objId++;
|
|
|
|
while (!template.ObjectId.HasValue && taken.Contains(objectId))
|
|
{
|
|
objectId = objId++;
|
|
}
|
|
|
|
taken.Add(objectId);
|
|
|
|
levelObjectTemplate.ObjectId = objectId;
|
|
|
|
var dataString = new StringBuilder();
|
|
foreach (var (dataKey, dataValue) in template.Data)
|
|
{
|
|
var type = dataValue.TypeId;
|
|
var value = dataValue.ObjectValue ?? "";
|
|
|
|
if (value is true) value = 1;
|
|
if (value is false) value = 0;
|
|
if (dataValue.Type == FieldType.Object)
|
|
{
|
|
value = ModContext.AssertId(value.ToString()!);
|
|
type = 1;
|
|
}
|
|
|
|
var strValue = value.ToString()!;
|
|
|
|
if (dataValue.Type == FieldType.Position)
|
|
{
|
|
if (dataValue.Value.TryGetValue(out string? _))
|
|
{
|
|
strValue = strValue.Replace("<", "").Replace(">", "").Replace(" ", "");
|
|
var split = strValue.Split(',');
|
|
strValue = $"{split[0]}\u001F{split[1]}\u001F{split[2]}";
|
|
}
|
|
else
|
|
{
|
|
var obj = dataValue.Value.ToDictionary();
|
|
strValue = $"{obj["X"]}\u001F{obj["Y"]}\u001F{obj["Z"]}";
|
|
}
|
|
}
|
|
else if (dataValue.Type == FieldType.Rotation)
|
|
{
|
|
if (dataValue.Value.TryGetValue(out string? _))
|
|
{
|
|
strValue = strValue.Replace("<", "").Replace(">", "").Replace(" ", "");
|
|
var split = strValue.Split(',');
|
|
strValue = $"{split[0]}\u001F{split[1]}\u001F{split[2]}\u001F{split[3]}";
|
|
}
|
|
else
|
|
{
|
|
var obj = dataValue.Value.ToDictionary();
|
|
strValue = $"{obj["X"]}\u001F{obj["Y"]}\u001F{obj["Z"]}\u001F{obj["W"]}";
|
|
}
|
|
}
|
|
|
|
if (strValue == "True") strValue = "1";
|
|
else if (strValue == "False") strValue = "0";
|
|
|
|
dataString.Append($"{dataKey}={type}:{strValue}\n");
|
|
}
|
|
|
|
if (dataString.Length > 0)
|
|
{
|
|
dataString.Length -= 1;
|
|
|
|
levelObjectTemplate.LegoInfo = LegoDataDictionary.FromString(dataString.ToString());
|
|
}
|
|
else
|
|
{
|
|
levelObjectTemplate.LegoInfo = new LegoDataDictionary();
|
|
}
|
|
}
|
|
|
|
lvl.LevelObjects = levelObjects;
|
|
|
|
if (scene.Particles != null && scene.Particles.Any())
|
|
{
|
|
lvl.LevelEnvironmentConfig = new LevelEnvironmentConfig(lvl.LvlVersion)
|
|
{
|
|
ParticleStructs = scene.Particles.Select(p => new ParticleStruct(lvl.LvlVersion)
|
|
{
|
|
Position = p.Position,
|
|
Rotation = p.Rotation,
|
|
ParticleName = p.Name
|
|
}).ToArray()
|
|
};
|
|
}
|
|
else
|
|
{
|
|
lvl.LevelEnvironmentConfig = null; //new LevelEnvironmentConfig(lvl.LvlVersion) { ParticleStructs = Array.Empty<ParticleStruct>() };
|
|
}
|
|
|
|
var collection = new TriggerCollection();
|
|
|
|
collection.Triggers = new List<Trigger>();
|
|
|
|
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
|
|
|
|
ns.Add("", "");
|
|
|
|
if (scene.Triggers != null && scene.Triggers.Any())
|
|
{
|
|
foreach (var trigger in scene.Triggers)
|
|
{
|
|
collection.Triggers.Add(trigger);
|
|
}
|
|
|
|
// Filename but with .lutriggers extension
|
|
var path = Path.Combine(Path.GetDirectoryName(filename)!, Path.GetFileNameWithoutExtension(filename) + ".lutriggers");
|
|
|
|
// Save as xml
|
|
var xml = new XmlSerializer(typeof(TriggerCollection));
|
|
|
|
using var stream = new StreamWriter(path);
|
|
using var xmlWriter = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true });
|
|
xml.Serialize(xmlWriter, collection, ns);
|
|
}
|
|
|
|
if (scene.SceneAudio != null)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(scene.SceneAudio.Guid2D))
|
|
{
|
|
// Filename but with .aud extension
|
|
var path = Path.Combine(Path.GetDirectoryName(filename)!, Path.GetFileNameWithoutExtension(filename) + ".aud");
|
|
|
|
// Save as xml
|
|
var xml = new XmlSerializer(typeof(SceneAudio));
|
|
|
|
using var stream = new StreamWriter(path);
|
|
using var xmlWriter = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true });
|
|
xml.Serialize(xmlWriter, scene.SceneAudio, ns);
|
|
}
|
|
}
|
|
|
|
lvl.LevelInfo = new LevelInfo();
|
|
|
|
lvl.LevelInfo.RevisionNumber = 1;
|
|
|
|
using var fileStream = File.Create(filename);
|
|
using var writer = new ByteWriter(fileStream);
|
|
|
|
lvl.Serialize(writer);
|
|
}
|
|
|
|
var sceneList = luzFile.Scenes.ToList();
|
|
|
|
sceneList.Sort((a, b) => (int)(a.SceneId * 1000 + a.LayerId) - (int)(b.SceneId * 1000 + b.LayerId));
|
|
|
|
luzFile.Scenes = sceneList.ToArray();
|
|
|
|
luzFile.Transitions = new LuzSceneTransition[zone.Transitions.Length];
|
|
|
|
for (var index = 0; index < zone.Transitions.Length; index++)
|
|
{
|
|
var version = 0x2DU;
|
|
|
|
var data = zone.Transitions[index];
|
|
|
|
var transition = new LuzSceneTransition(version);
|
|
|
|
transition.SceneTransitionName = data.Name;
|
|
|
|
transition.UnknownFloat = 0;
|
|
|
|
transition.TransitionPoints = new LuzSceneTransitionPoint[data.Points.Length];
|
|
|
|
for (var transitionPointIndex = 0; transitionPointIndex < data.Points.Length; transitionPointIndex++)
|
|
{
|
|
var transitionPoint = new LuzSceneTransitionPoint();
|
|
transitionPoint.Point = data.Points[transitionPointIndex].Position;
|
|
transitionPoint.SceneId = luzFile.Scenes.First(s => s.SceneName == data.Points[transitionPointIndex].Scene).SceneId;
|
|
|
|
transition.TransitionPoints[transitionPointIndex] = transitionPoint;
|
|
}
|
|
|
|
luzFile.Transitions[index] = transition;
|
|
}
|
|
|
|
var luzFilename = Path.Combine(root, $"{fileName}.luz");
|
|
|
|
using var zoneFileStream = File.Create(luzFilename);
|
|
using var zoneWriter = new ByteWriter(zoneFileStream);
|
|
|
|
luzFile.Serialize(zoneWriter);
|
|
|
|
if (mod.Locale != null)
|
|
{
|
|
ModContext.AddToLocale($"ZoneTable_{entry.Key}_DisplayDescription", mod.Locale);
|
|
}
|
|
|
|
var relativeTo = Path.Combine(ModContext.Root, "../res", "maps/");
|
|
|
|
var uri = new Uri(relativeTo);
|
|
|
|
var relativePath = uri.MakeRelativeUri(new Uri(luzFilename)).ToString();
|
|
|
|
entry["zoneName"].Value = relativePath;
|
|
}
|
|
|
|
public override void Apply(Mod mod)
|
|
{
|
|
if (mod.Action == "insert")
|
|
{
|
|
InsertZone(mod);
|
|
|
|
return;
|
|
}
|
|
|
|
if (mod.Action == "add")
|
|
{
|
|
AddZone(mod);
|
|
|
|
return;
|
|
}
|
|
|
|
throw new NotSupportedException(
|
|
"Action " + mod.Action + " is not supported for zone mods"
|
|
);
|
|
}
|
|
} |