diff --git a/PckStudio.Core/MapData.cs b/PckStudio.Core/MapData.cs index 37370f02..e1d60a03 100644 --- a/PckStudio.Core/MapData.cs +++ b/PckStudio.Core/MapData.cs @@ -1,5 +1,11 @@ -using System.Drawing; +using System; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Numerics; +using Cyotek.Data.Nbt; using OMI.Formats.GameRule; +using PckStudio.Core.GameRule; namespace PckStudio.Core { @@ -22,23 +28,31 @@ namespace PckStudio.Core { public string Name { get; } public Image Thumbnail { get; } - public GameRuleFile Grf { get; } - public GameRuleFile.GameRule LevelRules { get; } - public NamedData World { 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) { Name = name; Thumbnail = thumbnail; - Grf = new GameRuleFile(); - Grf.AddRule("MapOptions", - new GameRuleFile.IntParameter("seed", 0), - new GameRuleFile.IntParameter("spawnX", 0), - new GameRuleFile.IntParameter("spawnY", 0), - new GameRuleFile.IntParameter("spawnZ", 0), + Grf = new RootGameRule(); + + 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) + new GameRuleFile.IntParameter("themeId", 0)) ); LevelRules = GameRule.LevelRules.GetMiniGameLevelRules(miniGame); diff --git a/PckStudio.Core/MapReader.cs b/PckStudio.Core/MapReader.cs new file mode 100644 index 00000000..6f2d8411 --- /dev/null +++ b/PckStudio.Core/MapReader.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.IO; +using ICSharpCode.SharpZipLib.Zip.Compression.Streams; +using OMI; + +namespace PckStudio.Core +{ + public class MapReader + { + public static IDictionary OpenSave(Stream stream) + { + EndiannessAwareBinaryReader reader = new EndiannessAwareBinaryReader(stream, ByteOrder.BigEndian); + _ = reader.ReadInt32(); + int bufferSize = reader.ReadInt32(); + byte[] buffer = new byte[bufferSize]; + using Stream decompStream = new InflaterInputStream(stream); + decompStream.Read(buffer, 0, bufferSize); + reader = new EndiannessAwareBinaryReader(new MemoryStream(buffer), System.Text.Encoding.BigEndianUnicode, ByteOrder.BigEndian); + + int fileStartOffset = reader.ReadInt32(); + int fileCount = reader.ReadInt32(); + reader.BaseStream.Seek(fileStartOffset, SeekOrigin.Begin); + Dictionary res = new Dictionary(); + for (int i = 0; i < fileCount; i++) + { + string path = reader.ReadString(64).Replace('\\', '/'); + int size = reader.ReadInt32(); + int offset = reader.ReadInt32(); + long timestemp = reader.ReadInt64(); + + long origin = reader.BaseStream.Position; + reader.BaseStream.Seek(offset, SeekOrigin.Begin); + byte[] data = reader.ReadBytes(size); + reader.BaseStream.Seek(origin, SeekOrigin.Begin); + + res.Add(path, data); + } + return res; + } + } +} diff --git a/PckStudio.Core/PckStudio.Core.csproj b/PckStudio.Core/PckStudio.Core.csproj index f48ed240..569565b7 100644 --- a/PckStudio.Core/PckStudio.Core.csproj +++ b/PckStudio.Core/PckStudio.Core.csproj @@ -104,8 +104,10 @@ + + @@ -142,6 +144,7 @@ + @@ -170,6 +173,9 @@ + + 3.1.1 + 13.0.3