diff --git a/PckStudio.Core/DLC/DLCMashUpPackage.cs b/PckStudio.Core/DLC/DLCMashUpPackage.cs index e2008d49..fadd82cc 100644 --- a/PckStudio.Core/DLC/DLCMashUpPackage.cs +++ b/PckStudio.Core/DLC/DLCMashUpPackage.cs @@ -18,16 +18,14 @@ namespace PckStudio.Core.DLC private IDLCPackage _skinPackage; private IDLCPackage _texturePackage; - private AbstractGameRule _gameRule; + private MapData _mapData; private IDictionary _audioData; private PckAudioFile _pckAudio; - private NamedData _savegameData; internal DLCMashUpPackage(string name, string description, int identifier, IDLCPackageSerialization packageInfo, AbstractGameRule gameRule, IDLCPackage parentPackage, IDLCPackage skinPackage = null, IDLCPackage texturePackage = null) : base(name, identifier, packageInfo, parentPackage) { Description = description; - _gameRule = gameRule; _skinPackage = skinPackage; _texturePackage = texturePackage; } @@ -37,18 +35,8 @@ namespace PckStudio.Core.DLC { _skinPackage = DLCSkinPackage.CreateEmpty(this); _texturePackage = DLCTexturePackage.CreateDefaultPackage(this); - _savegameData = new NamedData("world.mcs", Array.Empty()); _audioData = new Dictionary(); _pckAudio = new PckAudioFile(); - - //! TODO(null): only create grf when adding savefile ?... - _gameRule.AddRule(new NamedRule("MapOptions", - new GameRuleFile.IntParameter("seed", 0), - new GameRuleFile.GameRuleParameter("baseSaveName", _savegameData.Name), - new GameRuleFile.BoolParameter("flatworld", false), - new GameRuleFile.IntParameter("texturePackId", Identifier)) - ); - _gameRule.AddRule(LevelRules.GetDefault(pos: Vector3.Zero, rot: Vector2.Zero)); } public IDLCPackage GetSkinPackage() => _skinPackage; diff --git a/PckStudio.Core/DLC/DLCMiniGamePackage.cs b/PckStudio.Core/DLC/DLCMiniGamePackage.cs index a3c416dc..16e432cf 100644 --- a/PckStudio.Core/DLC/DLCMiniGamePackage.cs +++ b/PckStudio.Core/DLC/DLCMiniGamePackage.cs @@ -23,7 +23,7 @@ namespace PckStudio.Core.DLC public void AddMap(string name, Image thumbnail, MapSize mapSize, NamedData world) { - _maps.Add(new MapData(name, thumbnail, _miniGameId, mapSize, world)); + _maps.Add(new MapData(name, thumbnail, world, _miniGameId, mapSize)); } public override DLCPackageType GetDLCPackageType() => _packageType; diff --git a/PckStudio.Core/GameRule/AbstractGameRule.cs b/PckStudio.Core/GameRule/AbstractGameRule.cs index 8714465c..3a13e851 100644 --- a/PckStudio.Core/GameRule/AbstractGameRule.cs +++ b/PckStudio.Core/GameRule/AbstractGameRule.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Numerics; using OMI.Formats.GameRule; namespace PckStudio.Core.GameRule @@ -10,14 +9,45 @@ namespace PckStudio.Core.GameRule public abstract class AbstractGameRule { private List _gameRules = new List(); + private IDictionary _parameters = new Dictionary(); + + public abstract string Name { get; } + public void AddRule(AbstractGameRule gameRule) => _gameRules.Add(gameRule); public void AddRules(IEnumerable gameRules) => _gameRules.AddRange(gameRules); - protected abstract GameRuleFile.GameRule GetGameRule(); + public void AddParameter(string name, string value) => _parameters.Add(name, value); + public void AddParameter(string name, T value) => AddParameter(name, value.ToString()); + public void AddParameter(string name, bool value) => AddParameter(name, value.ToString().ToLower()); + public void AddParameters(KeyValuePair[] values) + { + foreach (KeyValuePair value in values) + { + AddParameter(value.Key, value.Value); + } + } + + private string GetString(char c, string prefix, string suffix) => $"{prefix}{(string.IsNullOrWhiteSpace(prefix) ? char.ToLower(c) : char.ToUpper(c))}{suffix}"; + + public void AddParameter(Vector2 vec2, string prefix = "", string suffix = "") + { + AddParameter(GetString('x', prefix, suffix), vec2.X); + AddParameter(GetString('y', prefix, suffix), vec2.Y); + } + + + public void AddParameter(Vector3 vec3, string prefix = "", string suffix = "") + { + AddParameter(new Vector2(vec3.X, vec3.Y), prefix, suffix); + AddParameter(GetString('z', prefix, suffix), vec3.Z); + } + private GameRuleFile.GameRule InternalGetGameRule() { + _ = Name ?? throw new ArgumentNullException(nameof(Name)); IEnumerable a = _gameRules.Select(agr => agr.InternalGetGameRule()); - GameRuleFile.GameRule gameRule = GetGameRule(); + GameRuleFile.GameRule gameRule = new GameRuleFile.GameRule(Name); + gameRule.AddParameters(_parameters.Select(kv => new GameRuleFile.GameRuleParameter(kv.Key, kv.Value)).ToArray()); gameRule.AddRules(a); return gameRule; } diff --git a/PckStudio.Core/GameRule/DistributeItems.cs b/PckStudio.Core/GameRule/DistributeItems.cs index e86c70e2..c86b7f31 100644 --- a/PckStudio.Core/GameRule/DistributeItems.cs +++ b/PckStudio.Core/GameRule/DistributeItems.cs @@ -1,14 +1,13 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; namespace PckStudio.Core.GameRule { public sealed class DistributeItems : AbstractGameRule { + public override string Name => "DistributeItems"; + + public void AddPosition(int x, int y, int z) => AddRule(new WorldPosition(x, y, z)); + private static string[] _idStrings = { "StartItems", @@ -22,20 +21,10 @@ namespace PckStudio.Core.GameRule OuterItems, HighValueItems } - private DistributeItemsId _id; - - public void AddPosition(int x, int y, int z) => AddRule(new WorldPosition(x, y, z)); - + internal DistributeItems(DistributeItemsId id) { - _id = id; - } - - protected override GameRuleFile.GameRule GetGameRule() - { - var gameRule = new GameRuleFile.GameRule("DistributeItems"); - gameRule.AddParameter(new GameRuleFile.GameRuleParameter("id", _idStrings[(int)_id])); - return gameRule; + AddParameter("id", _idStrings[(int)id]); } } } diff --git a/PckStudio.Core/GameRule/LevelRules.cs b/PckStudio.Core/GameRule/LevelRules.cs index 3ad79d8c..47caaa85 100644 --- a/PckStudio.Core/GameRule/LevelRules.cs +++ b/PckStudio.Core/GameRule/LevelRules.cs @@ -1,39 +1,30 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; +using System.Collections.Generic; namespace PckStudio.Core.GameRule { public sealed class LevelRules : AbstractGameRule { - private readonly GameRuleFile.GameRuleParameter[] _parameters; - private readonly MiniGameId _miniGameId; + public override string Name => "LevelRules"; + + public MiniGameId MiniGame { get; } public static LevelRules GetDefault(Vector3 pos, Vector2 rot) => new LevelRules([new UpdatePlayer(pos, rot)]); public static LevelRules GetMiniGameLevelRules(MiniGameId miniGame) => new LevelRules(miniGame); - public LevelRules(IEnumerable gameRules, MiniGameId miniGameId, params GameRuleFile.GameRuleParameter[] parameters) + public LevelRules(IEnumerable gameRules, MiniGameId miniGameId, params KeyValuePair[] parameters) { AddRules(gameRules); - _parameters = parameters; - _miniGameId = miniGameId; + MiniGame = miniGameId; + if (miniGameId != MiniGameId.None) + AddParameter("ruleType", (int)miniGameId); + AddParameters(parameters); } - public LevelRules(IEnumerable gameRules, params GameRuleFile.GameRuleParameter[] parameters) : this(gameRules, MiniGameId.None, parameters) { } + public LevelRules(IEnumerable gameRules, params KeyValuePair[] parameters) : this(gameRules, MiniGameId.None, parameters) { } public LevelRules(MiniGameId miniGameId) : this(Enumerable.Empty(), miniGameId) { } - - protected override GameRuleFile.GameRule GetGameRule() - { - var gameRule = new GameRuleFile.GameRule("LevelRules"); - if (_miniGameId != MiniGameId.None) - gameRule.AddParameter(new GameRuleFile.IntParameter("ruleType", (int)_miniGameId)); - gameRule.AddParameters(_parameters); - return gameRule; - } } } diff --git a/PckStudio.Core/GameRule/NamedArea.cs b/PckStudio.Core/GameRule/NamedArea.cs index af115c0c..0f397a91 100644 --- a/PckStudio.Core/GameRule/NamedArea.cs +++ b/PckStudio.Core/GameRule/NamedArea.cs @@ -1,43 +1,25 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Numerics; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; using PckStudio.Core.Extensions; namespace PckStudio.Core.GameRule { internal sealed class NamedArea : AbstractGameRule { - public string Name { get; } + public override string Name => "NamedArea"; public Vector3 Start { get; } public Vector3 End { get; } public NamedArea(string name, Vector3 start, Vector3 end) { - Name = name; + AddParameter("name", name); + AddParameter(start, suffix: "0"); + AddParameter(end, suffix: "1"); Start = start; End = end; } public NamedArea(string name, BoundingBox boundingBox) : this(name, boundingBox.Start.ToNumericsVector(), boundingBox.End.ToNumericsVector()) { } - - protected override GameRuleFile.GameRule GetGameRule() - { - GameRuleFile.GameRule gameRule = new GameRuleFile.GameRule("NamedArea"); - gameRule.AddParameters( - new GameRuleFile.GameRuleParameter("name", Name), - new GameRuleFile.FloatParameter("x0", Start.X), - new GameRuleFile.FloatParameter("y0", Start.Y), - new GameRuleFile.FloatParameter("z0", Start.Z), - new GameRuleFile.FloatParameter("x1", End.X), - new GameRuleFile.FloatParameter("y1", End.Y), - new GameRuleFile.FloatParameter("z1", End.Z) - ); - return gameRule; - } } } diff --git a/PckStudio.Core/GameRule/NamedRule.cs b/PckStudio.Core/GameRule/NamedRule.cs index 0d80382f..19229652 100644 --- a/PckStudio.Core/GameRule/NamedRule.cs +++ b/PckStudio.Core/GameRule/NamedRule.cs @@ -1,28 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; namespace PckStudio.Core.GameRule { - internal sealed class NamedRule : AbstractGameRule + internal sealed class NamedRule(string name) : AbstractGameRule { - private readonly string _name; - private readonly GameRuleFile.GameRuleParameter[] _parameters; - - public NamedRule(string name, params GameRuleFile.GameRuleParameter[] parameters) - { - _name = name; - _parameters = parameters; - } - - protected override GameRuleFile.GameRule GetGameRule() - { - var rule = new GameRuleFile.GameRule(_name); - rule.AddParameters(_parameters); - return rule; - } + public override string Name => name; } } diff --git a/PckStudio.Core/GameRule/OnGameStartSpawnPositions.cs b/PckStudio.Core/GameRule/OnGameStartSpawnPositions.cs index d1eacbd1..ce1763de 100644 --- a/PckStudio.Core/GameRule/OnGameStartSpawnPositions.cs +++ b/PckStudio.Core/GameRule/OnGameStartSpawnPositions.cs @@ -1,23 +1,17 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; namespace PckStudio.Core.GameRule { public sealed class OnGameStartSpawnPositions : AbstractGameRule { + public override string Name => "OnGameStartSpawnPositions"; public SpawnPositionSet OnStart { get; } = new SpawnPositionSet(SpawnPositionSet.SpanPositionMethod.OnStart); public SpawnPositionSet OnRespawn { get; } = new SpawnPositionSet(SpawnPositionSet.SpanPositionMethod.OnRespawn); - protected override GameRuleFile.GameRule GetGameRule() + public OnGameStartSpawnPositions() { AddRule(OnStart); AddRule(OnRespawn); - return new GameRuleFile.GameRule("OnGameStartSpawnPositions"); } } } diff --git a/PckStudio.Core/GameRule/OnInitialiseWorld.cs b/PckStudio.Core/GameRule/OnInitialiseWorld.cs index 8bfaeb0a..0726657c 100644 --- a/PckStudio.Core/GameRule/OnInitialiseWorld.cs +++ b/PckStudio.Core/GameRule/OnInitialiseWorld.cs @@ -1,24 +1,20 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; namespace PckStudio.Core.GameRule { public sealed class OnInitialiseWorld : AbstractGameRule { + public override string Name => "OnInitialiseWorld"; public DistributeItems StartItems { get; } = new DistributeItems(DistributeItems.DistributeItemsId.StartItems); public DistributeItems OuterItems { get; } = new DistributeItems(DistributeItems.DistributeItemsId.OuterItems); public DistributeItems HighValueItems { get; } = new DistributeItems(DistributeItems.DistributeItemsId.HighValueItems); - protected override GameRuleFile.GameRule GetGameRule() + + public OnInitialiseWorld() { AddRule(StartItems); AddRule(OuterItems); AddRule(HighValueItems); - return new GameRuleFile.GameRule("OnInitialiseWorld"); } } } diff --git a/PckStudio.Core/GameRule/RootGameRule.cs b/PckStudio.Core/GameRule/RootGameRule.cs index 7447ef6a..08a7158d 100644 --- a/PckStudio.Core/GameRule/RootGameRule.cs +++ b/PckStudio.Core/GameRule/RootGameRule.cs @@ -1,14 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; namespace PckStudio.Core.GameRule { public sealed class RootGameRule : AbstractGameRule { - protected override GameRuleFile.GameRule GetGameRule() => new GameRuleFile.GameRule("__ROOT__"); //! name is irrelevant + public override string Name => "__ROOT__"; //! name is irrelevant } } diff --git a/PckStudio.Core/GameRule/SpawnPositionSet.cs b/PckStudio.Core/GameRule/SpawnPositionSet.cs index a68b1c8e..70961ab0 100644 --- a/PckStudio.Core/GameRule/SpawnPositionSet.cs +++ b/PckStudio.Core/GameRule/SpawnPositionSet.cs @@ -1,32 +1,20 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Numerics; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; namespace PckStudio.Core.GameRule { public sealed class SpawnPositionSet : AbstractGameRule { + public override string Name => "SpawnPositionSet"; + public void AddSpawnPosition(int x, int y, int z, int xRot, int yRot) => AddRule(new UpdatePlayer(new Vector3(x, y, z), new Vector2(xRot, yRot))); + public void AddSpawnPosition(int x, int y, int z) => AddSpawnPosition(x, y, z, 0, 0); + internal enum SpanPositionMethod { OnStart, OnRespawn } - private SpanPositionMethod _method; - internal SpawnPositionSet(SpanPositionMethod method) => _method = method; - - public void AddSpawnPosition(int x, int y, int z, int xRot, int yRot) => AddRule(new UpdatePlayer(new Vector3(x, y, z), new Vector2(xRot, yRot))); - public void AddSpawnPosition(int x, int y, int z) => AddSpawnPosition(x, y, z, 0, 0); - - protected override GameRuleFile.GameRule GetGameRule() - { - var gameRule = new GameRuleFile.GameRule("SpawnPositionSet"); - gameRule.AddParameter(new GameRuleFile.IntParameter("method", (int)_method)); - return gameRule; - } + internal SpawnPositionSet(SpanPositionMethod method) => AddParameter("method", (int)method); } } diff --git a/PckStudio.Core/GameRule/UpdatePlayer.cs b/PckStudio.Core/GameRule/UpdatePlayer.cs index 7919421b..04bbd870 100644 --- a/PckStudio.Core/GameRule/UpdatePlayer.cs +++ b/PckStudio.Core/GameRule/UpdatePlayer.cs @@ -1,35 +1,16 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Numerics; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; namespace PckStudio.Core.GameRule { - internal sealed class UpdatePlayer : AbstractGameRule + public sealed class UpdatePlayer : AbstractGameRule { - private Vector3 _spawn; - private Vector2 _rot; + public override string Name => "UpdatePlayer"; public UpdatePlayer(Vector3 spawn, Vector2 rot) { - _spawn = spawn; - _rot = rot; - } - - protected override GameRuleFile.GameRule GetGameRule() - { - var gameRule = new GameRuleFile.GameRule("UpdatePlayer"); - gameRule.AddParameters( - new GameRuleFile.FloatParameter("x", _spawn.X), - new GameRuleFile.FloatParameter("y", _spawn.Y), - new GameRuleFile.FloatParameter("z", _spawn.Z), - new GameRuleFile.FloatParameter("xRot", _rot.X), - new GameRuleFile.FloatParameter("yRot", _rot.Y) - ); - return gameRule; + AddParameter(spawn); + AddParameter(rot, suffix: "Rot"); } } } diff --git a/PckStudio.Core/GameRule/WorldPosition.cs b/PckStudio.Core/GameRule/WorldPosition.cs index 10014e21..d902ea27 100644 --- a/PckStudio.Core/GameRule/WorldPosition.cs +++ b/PckStudio.Core/GameRule/WorldPosition.cs @@ -1,26 +1,14 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Numerics; -using System.Text; -using System.Threading.Tasks; -using OMI.Formats.GameRule; - namespace PckStudio.Core.GameRule { - internal sealed class WorldPosition(int x, int y, int z) : AbstractGameRule + internal sealed class WorldPosition : AbstractGameRule { - private Vector3 _pos = new Vector3(x, y, z); - - protected override GameRuleFile.GameRule GetGameRule() + public override string Name => "WorldPosition"; + + public WorldPosition(int x, int y, int z) { - var gameRule = new GameRuleFile.GameRule("WorldPosition"); - gameRule.AddParameters( - new GameRuleFile.IntParameter("x", (int)_pos.X), - new GameRuleFile.IntParameter("y", (int)_pos.Y), - new GameRuleFile.IntParameter("z", (int)_pos.Z) - ); - return gameRule; + AddParameter(new Vector3(x, y, z)); } } } diff --git a/PckStudio.Core/MapData.cs b/PckStudio.Core/MapData.cs index e1d60a03..655c0a0c 100644 --- a/PckStudio.Core/MapData.cs +++ b/PckStudio.Core/MapData.cs @@ -4,7 +4,7 @@ using System.Drawing; using System.IO; using System.Numerics; using Cyotek.Data.Nbt; -using OMI.Formats.GameRule; +using PckStudio.Core.Extensions; using PckStudio.Core.GameRule; namespace PckStudio.Core @@ -24,41 +24,45 @@ namespace PckStudio.Core Huge } +#nullable enable public sealed class MapData { public string Name { get; } - public Image Thumbnail { get; } + public Image? Thumbnail { get; } public AbstractGameRule LevelRules { get; } internal AbstractGameRule Grf { get; } internal NamedData World { get; } - - public MapData(string name, Image thumbnail, MiniGameId miniGame, MapSize mapSize, NamedData world) + + public MapData(string name, Image? thumbnail, NamedData world, MiniGameId miniGame = MiniGameId.None, MapSize mapSize = default) { Name = name; Thumbnail = thumbnail; - Grf = new RootGameRule(); + World = world; var levelData = MapReader.OpenSave(new MemoryStream(world.Value))["level.dat"]; - TagCompound levelDat = NbtDocument.LoadDocument(new MemoryStream(levelData)).DocumentRoot["Data"] as TagCompound; - Vector3 spawn = Vector3.Zero; - if (levelDat is not null) - spawn = new Vector3((int)levelDat["SpawnX"].GetValue(), (int)levelDat["SpawnX"].GetValue(), (int)levelDat["SpawnY"].GetValue()); - - Grf.AddRule(new NamedRule("MapOptions", - new GameRuleFile.GameRuleParameter("seed", levelDat["RandomSeed"].GetValue().ToString()), - new GameRuleFile.FloatParameter("spawnX", spawn.X), - new GameRuleFile.FloatParameter("spawnY", spawn.Y), - new GameRuleFile.FloatParameter("spawnZ", spawn.Z), - new GameRuleFile.BoolParameter("flatworld", false), - new GameRuleFile.GameRuleParameter("baseSaveName", world.Name), - new GameRuleFile.IntParameter("mapSize", (int)mapSize), - new GameRuleFile.IntParameter("themeId", 0)) - ); + TagCompound? levelDat = NbtDocument.LoadDocument(new MemoryStream(levelData))!.DocumentRoot?["Data"] as TagCompound; + _ = levelDat ?? throw new NullReferenceException(nameof(levelDat)); + Vector3 spawn = levelDat.GetVector3("Spawn"); - LevelRules = GameRule.LevelRules.GetMiniGameLevelRules(miniGame); + var mapOptions = new NamedRule("MapOptions"); + mapOptions.AddParameter("seed", levelDat["RandomSeed"].GetValue()); + mapOptions.AddParameter(spawn, prefix: "spawn"); + mapOptions.AddParameter("flatworld", false); + mapOptions.AddParameter("baseSaveName", world.Name); + if (miniGame > MiniGameId.None) + { + mapOptions.AddParameter("mapSize", (int)mapSize); + mapOptions.AddParameter("themeId", 0); + } + + Grf = new RootGameRule(); + + Grf.AddRule(mapOptions); + + LevelRules = miniGame > MiniGameId.None ? GameRule.LevelRules.GetMiniGameLevelRules(miniGame) : GameRule.LevelRules.GetDefault(spawn, Vector2.Zero); Grf.AddRule(LevelRules); - World = world; } +#nullable disable } -} +} \ No newline at end of file