From 39b1df7c6d6c1468d07465b9b944ecb3c0a73e62 Mon Sep 17 00:00:00 2001
From: miku-666 <74728189+NessieHax@users.noreply.github.com>
Date: Sun, 9 Nov 2025 09:48:13 +0100
Subject: [PATCH] Initial work
---
PCK-Studio/Controls/PckEditor.cs | 4 +-
.../CreateTexturePackPrompt.Designer.cs | 10 -
.../CreateTexturePackPrompt.cs | 2 +
.../CreateTexturePackPrompt.resx | 27 --
PCK-Studio/MainForm.cs | 8 +-
PckStudio.Core/ConsolePlatform.cs | 14 +
PckStudio.Core/DLCBattlePackage.cs | 28 ++
PckStudio.Core/DLCManager.cs | 268 ++++++++++++++++++
PckStudio.Core/DLCMashUpPackage.cs | 60 ++++
PckStudio.Core/DLCPackage.cs | 35 +++
PckStudio.Core/DLCPackageType.cs | 15 +
PckStudio.Core/DLCSkinPackage.cs | 51 ++++
PckStudio.Core/DLCTexturePackage.cs | 142 ++++++++++
PckStudio.Core/Interfaces/IDLCPackage.cs | 17 ++
.../Interfaces/IDLCPackageLocationInfo.cs | 7 +
PckStudio.Core/InvalidDLCPackage.cs | 28 ++
PckStudio.Core/MapData.cs | 47 +++
PckStudio.Core/PckStudio.Core.csproj | 26 +-
PckStudio.Core/ResourceLocation.cs | 44 +--
Vendor/OMI-Lib | 2 +-
20 files changed, 765 insertions(+), 70 deletions(-)
create mode 100644 PckStudio.Core/ConsolePlatform.cs
create mode 100644 PckStudio.Core/DLCBattlePackage.cs
create mode 100644 PckStudio.Core/DLCManager.cs
create mode 100644 PckStudio.Core/DLCMashUpPackage.cs
create mode 100644 PckStudio.Core/DLCPackage.cs
create mode 100644 PckStudio.Core/DLCPackageType.cs
create mode 100644 PckStudio.Core/DLCSkinPackage.cs
create mode 100644 PckStudio.Core/DLCTexturePackage.cs
create mode 100644 PckStudio.Core/Interfaces/IDLCPackage.cs
create mode 100644 PckStudio.Core/Interfaces/IDLCPackageLocationInfo.cs
create mode 100644 PckStudio.Core/InvalidDLCPackage.cs
create mode 100644 PckStudio.Core/MapData.cs
diff --git a/PCK-Studio/Controls/PckEditor.cs b/PCK-Studio/Controls/PckEditor.cs
index dc461bac..c29e6f84 100644
--- a/PCK-Studio/Controls/PckEditor.cs
+++ b/PCK-Studio/Controls/PckEditor.cs
@@ -722,9 +722,9 @@ namespace PckStudio.Controls
if (EditorValue is not null &&
TryGetLocFile(out LOCFile locfile) &&
locfile.HasLocEntry("IDS_DISPLAY_NAME") &&
- locfile.Languages.Contains("en-EN"))
+ locfile.Languages.Contains(DLCManager.Default.PreferredLanguage))
{
- RPC.SetPresence("Editing a Pack:", $" > {locfile.GetLocEntry("IDS_DISPLAY_NAME", "en-EN")}");
+ RPC.SetPresence("Editing a Pack:", $" > {locfile.GetLocEntry("IDS_DISPLAY_NAME", DLCManager.Default.PreferredLanguage)}");
return;
}
// default
diff --git a/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.Designer.cs b/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.Designer.cs
index 9dbc2d42..a9a14734 100644
--- a/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.Designer.cs
+++ b/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.Designer.cs
@@ -86,16 +86,6 @@
//
this.resolutionComboBox.FormattingEnabled = true;
resources.ApplyResources(this.resolutionComboBox, "resolutionComboBox");
- this.resolutionComboBox.Items.AddRange(new object[] {
- resources.GetString("resolutionComboBox.Items"),
- resources.GetString("resolutionComboBox.Items1"),
- resources.GetString("resolutionComboBox.Items2"),
- resources.GetString("resolutionComboBox.Items3"),
- resources.GetString("resolutionComboBox.Items4"),
- resources.GetString("resolutionComboBox.Items5"),
- resources.GetString("resolutionComboBox.Items6"),
- resources.GetString("resolutionComboBox.Items7"),
- resources.GetString("resolutionComboBox.Items8")});
this.resolutionComboBox.Name = "resolutionComboBox";
this.resolutionComboBox.Style = MetroFramework.MetroColorStyle.Silver;
this.resolutionComboBox.Theme = MetroFramework.MetroThemeStyle.Dark;
diff --git a/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.cs b/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.cs
index 52f8fe9d..93272581 100644
--- a/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.cs
+++ b/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.cs
@@ -1,6 +1,7 @@
using System;
using System.Windows.Forms;
using MetroFramework.Forms;
+using PckStudio.Core;
namespace PckStudio
{
@@ -16,6 +17,7 @@ namespace PckStudio
public CreateTexturePackPrompt()
{
InitializeComponent();
+ resolutionComboBox.Items.AddRange(Enum.GetNames(typeof(DLCTexturePackage.TextureResolution)));
}
private void OKBtn_Click(object sender, EventArgs e)
diff --git a/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.resx b/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.resx
index 5c08d9b8..88ebb5e2 100644
--- a/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.resx
+++ b/PCK-Studio/Forms/Additional-Popups/CreateTexturePackPrompt.resx
@@ -213,33 +213,6 @@
23
-
- x8
-
-
- x16
-
-
- x32
-
-
- x48
-
-
- x64
-
-
- x80
-
-
- x96
-
-
- x112
-
-
- x128
-
76, 40
diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs
index 300609d0..8c31c33a 100644
--- a/PCK-Studio/MainForm.cs
+++ b/PCK-Studio/MainForm.cs
@@ -37,8 +37,10 @@ namespace PckStudio
public MainForm()
{
InitializeComponent();
-
- Text = Application.ProductName;
+#if DEBUG
+ DLCManager.Default.Platform = ConsolePlatform.WiiU;
+#endif
+ Text = Application.ProductName;
labelVersion.Text = $"{Application.ProductName}: {ApplicationScope.CurrentVersion}";
@@ -57,6 +59,8 @@ namespace PckStudio
public void LoadPckFromFile(string filepath)
{
+ Core.Interfaces.IDLCPackage dlcPackage = DLCManager.Default.OpenDLCPackage(filepath);
+ Debug.WriteLine(dlcPackage?.GetDLCPackageType());
AddEditorPage(filepath);
}
diff --git a/PckStudio.Core/ConsolePlatform.cs b/PckStudio.Core/ConsolePlatform.cs
new file mode 100644
index 00000000..a727029d
--- /dev/null
+++ b/PckStudio.Core/ConsolePlatform.cs
@@ -0,0 +1,14 @@
+namespace PckStudio.Core
+{
+ public enum ConsolePlatform
+ {
+ Unknown,
+ Xbox360,
+ XboxOne,
+ PS3,
+ PS4,
+ PSVita,
+ WiiU,
+ Switch
+ }
+}
\ No newline at end of file
diff --git a/PckStudio.Core/DLCBattlePackage.cs b/PckStudio.Core/DLCBattlePackage.cs
new file mode 100644
index 00000000..a10a516c
--- /dev/null
+++ b/PckStudio.Core/DLCBattlePackage.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PckStudio.Core.Interfaces;
+
+namespace PckStudio.Core
+{
+ internal sealed class DLCBattlePackage : DLCPackage
+ {
+
+ private List _maps = new List();
+
+ public DLCBattlePackage(string name, int identifier, IDLCPackageLocationInfo packageInfo = null, IDLCPackage parentPackage = null)
+ : base(name, identifier, packageInfo, parentPackage)
+ {
+ }
+
+ public void AddMap(string name, Image thumbnail, MapSize mapSize, NamedData world)
+ {
+ _maps.Add(new MapData(name, thumbnail, MiniGameId.Battle, mapSize, world));
+ }
+
+ public override DLCPackageType GetDLCPackageType() => DLCPackageType.MG01;
+ }
+}
diff --git a/PckStudio.Core/DLCManager.cs b/PckStudio.Core/DLCManager.cs
new file mode 100644
index 00000000..c1952c1d
--- /dev/null
+++ b/PckStudio.Core/DLCManager.cs
@@ -0,0 +1,268 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using OMI.Formats.GameRule;
+using OMI.Formats.Languages;
+using OMI.Formats.Pck;
+using OMI.Workers.GameRule;
+using OMI.Workers.Language;
+using OMI.Workers.Pck;
+using PckStudio.Core.Deserializer;
+using PckStudio.Core.Extensions;
+using PckStudio.Core.Interfaces;
+
+namespace PckStudio.Core
+{
+ public sealed class DLCManager
+ {
+ public static DLCManager Default { get; } = new DLCManager(default, default, AvailableLanguages.English);
+
+ public OMI.ByteOrder ByteOrder { get; set; }
+
+ public ConsolePlatform Platform { get; set; }
+
+ ///
+ /// See for details.
+ ///
+ public string PreferredLanguage { get; set; }
+
+ private const string PackageDisplayNameId = "IDS_DISPLAY_NAME";
+ private readonly IDictionary _openPackages = new Dictionary();
+ private readonly IDictionary _localisationFiles = new Dictionary();
+ private readonly Random _rng = new Random();
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// See for details.
+ public DLCManager(OMI.ByteOrder byteOrder, ConsolePlatform platform, string preferredLanguage)
+ {
+ ByteOrder = byteOrder;
+ Platform = platform;
+ PreferredLanguage = preferredLanguage;
+ }
+
+ public IDLCPackage CreateNewPackage(string name, DLCPackageType packageType)
+ {
+ int identifier = _rng.Next(8000, GameConstants.MAX_PACK_ID);
+ IDLCPackage package = packageType switch
+ {
+ DLCPackageType.SkinPack => DLCSkinPackage.CreateEmpty(name, identifier),
+ DLCPackageType.TexturePack => DLCTexturePackage.CreateDefaultPackage(name, "", identifier),
+ DLCPackageType.MashUpPack => new DLCMashUpPackage(name, "", identifier),
+ //! TODO: implemnt minigame dlc packages -null
+ DLCPackageType.MG01 => new DLCBattlePackage(name, identifier),
+ DLCPackageType.MG02 => throw new NotImplementedException(),
+ DLCPackageType.MG03 => throw new NotImplementedException(),
+ DLCPackageType.Invalid => InvalidDLCPackage.Instance,
+ _ => throw new ArgumentException("Unable to create DLC Package of 'Unknown' type."),
+ };
+
+ LOCFile localisation = new LOCFile();
+ localisation.AddLanguage(PreferredLanguage);
+ localisation.AddLocKey(PackageDisplayNameId, name);
+ _localisationFiles.Add(identifier, localisation);
+ _openPackages.Add(identifier, package);
+
+ return package;
+ }
+
+ public IDLCPackage OpenDLCPackage(string filepath) => OpenDLCPackage(new FileInfo(filepath));
+
+ public IDLCPackage OpenDLCPackage(FileInfo fileInfo)
+ {
+ if (!IsValidPckFile(fileInfo))
+ return InvalidDLCPackage.Instance;
+
+ using Stream stream = fileInfo.OpenRead();
+
+ PckFileReader fileReader = new PckFileReader(ByteOrder);
+
+ PckFile pckFile = fileReader.FromStream(stream);
+
+ Debug.Assert(pckFile.TryGetAsset("0", PckAssetType.InfoFile, out PckAsset zeroAsset), "Could not find asset named:'0'.");
+
+ int identifier = (zeroAsset?.HasProperty("PACKID") ?? default) ? zeroAsset.GetProperty("PACKID", int.Parse) : -1;
+ if (identifier <= 0 || identifier > GameConstants.MAX_PACK_ID)
+ {
+ Trace.TraceError($"{nameof(identifier)}({identifier}) was out of range!");
+ return InvalidDLCPackage.Instance;
+ }
+
+ if (_openPackages.ContainsKey(identifier))
+ return _openPackages[identifier];
+
+ LOCFile localisation = pckFile.GetAssetsByType(PckAssetType.LocalisationFile).FirstOrDefault()?.GetData(new LOCFileReader());
+ if (localisation is null)
+ return InvalidDLCPackage.Instance;
+ _localisationFiles.Add(identifier, localisation);
+
+ IDLCPackage package = ScanForPackageType(fileInfo, identifier, pckFile, localisation, fileReader);
+ _openPackages.Add(identifier, package);
+ return package;
+ }
+
+ internal LOCFile GetLocalisation(int identifier)
+ {
+ return _localisationFiles.ContainsKey(identifier) ? _localisationFiles[identifier] : default;
+ }
+
+ private bool IsValidPckFile(FileInfo fileInfo)
+ {
+ if (!fileInfo.Exists)
+ throw new FileNotFoundException(fileInfo.FullName);
+
+ if (fileInfo.Extension != ".pck")
+ throw new FileFormatException("File does not end with '.pck'.");
+ return true;
+ }
+
+ private IDLCPackage ScanForPackageType(FileInfo fileInfo, int identifier, PckFile pckFile, LOCFile localisation, PckFileReader fileReader)
+ {
+ bool hasLanguage = localisation?.Languages?.Contains(PreferredLanguage) ?? default;
+
+ string name = hasLanguage && (localisation?.HasLocEntry(PackageDisplayNameId) ?? default)
+ ? localisation.GetLocEntry(PackageDisplayNameId, PreferredLanguage) : fileInfo.Name;
+
+ string description = hasLanguage && (localisation?.HasLocEntry(DLCTexturePackage.TexturePackDescriptionId) ?? default)
+ ? localisation.GetLocEntry(DLCTexturePackage.TexturePackDescriptionId, PreferredLanguage) : string.Empty;
+
+ bool couldBeTexturePack = fileInfo.Name == "TexturePack.pck";
+
+ bool hasSkins = pckFile.Contains(PckAssetType.SkinFile) || pckFile.Contains(PckAssetType.SkinDataFile);
+
+ DLCPackageType dlcPackageType = hasSkins ? DLCPackageType.SkinPack : DLCPackageType.Unknown;
+
+ IDLCPackage skinPackage = hasSkins ? GetDLCSkinPackage(name, identifier, pckFile, fileReader) : null;
+
+ PckAsset texturePackInfo = pckFile.GetAssetsByType(PckAssetType.TexturePackInfoFile).FirstOrDefault();
+ string dataPath = texturePackInfo is not null ? texturePackInfo.GetProperty("DATAPATH") : string.Empty;
+
+ DirectoryInfo dataDirectoryInfo = fileInfo.Directory.EnumerateDirectories().Where(dirInfo => dirInfo.Name == "Data").FirstOrDefault();
+ bool hasDataFolder = dataDirectoryInfo is not null;
+
+ if (hasDataFolder && !string.IsNullOrWhiteSpace(dataPath))
+ {
+ PckFile infoPck = texturePackInfo.GetData(fileReader);
+ FileInfo texturePackFileInfo = dataDirectoryInfo.EnumerateFiles().Where(fileInfo => fileInfo.Name == dataPath).FirstOrDefault();
+ if (IsValidPckFile(texturePackFileInfo))
+ {
+ using Stream texturePackFileStream = texturePackFileInfo.OpenRead();
+ PckFile texturePackPck = fileReader.FromStream(texturePackFileStream);
+ IDLCPackage texturePackage = GetTexturePackageFromPckFile(infoPck, texturePackPck);
+ dlcPackageType = DLCPackageType.TexturePack;
+ }
+
+ bool hasSavefile = dataDirectoryInfo.EnumerateFiles("*.mcs").Any();
+ PckAsset gameRuleAsset = null;
+ if (Platform == ConsolePlatform.Unknown)
+ throw new Exception($"{nameof(Platform)} is Unknown.");
+ bool hasGameRuleFile = pckFile.Contains("GameRules.grf", PckAssetType.GameRulesFile) && pckFile.TryGetAsset("GameRules.grf", PckAssetType.GameRulesFile, out gameRuleAsset);
+
+ if (hasSavefile && hasGameRuleFile)
+ {
+ GameRuleFile gameRuleFile = gameRuleAsset.GetData(new GameRuleFileReader(GetPlatformCompressionType()));
+ dlcPackageType = DLCPackageType.MashUpPack;
+ }
+ }
+ Debug.WriteLine(dlcPackageType);
+ return InvalidDLCPackage.Instance;
+ }
+
+ private GameRuleFile.CompressionType GetPlatformCompressionType()
+ {
+ switch (Platform)
+ {
+ case ConsolePlatform.Xbox360:
+ return GameRuleFile.CompressionType.XMem;
+
+ case ConsolePlatform.PS3:
+ return GameRuleFile.CompressionType.Deflate;
+
+ case ConsolePlatform.XboxOne:
+ case ConsolePlatform.PS4:
+ case ConsolePlatform.PSVita:
+ case ConsolePlatform.WiiU:
+ case ConsolePlatform.Switch:
+ return GameRuleFile.CompressionType.Zlib;
+
+ case ConsolePlatform.Unknown:
+ default:
+ return GameRuleFile.CompressionType.Unknown;
+ }
+ }
+
+ private IDLCPackage GetTexturePackageFromPckFile(PckFile infoPck, PckFile dataPck)
+ {
+ if (!infoPck.TryGetAsset("comparison.png", PckAssetType.TextureFile, out PckAsset comparisonAsset))
+ {
+ Trace.TraceError($"Could not find 'comparison.png'.");
+ return InvalidDLCPackage.Instance;
+ }
+ if (!infoPck.TryGetAsset("icon.png", PckAssetType.TextureFile, out PckAsset iconnAsset))
+ {
+ Trace.TraceError($"Could not find 'icon.png'.");
+ return InvalidDLCPackage.Instance;
+ }
+
+ Image comparisonImg = comparisonAsset.GetTexture();
+ Image iconImg = iconnAsset.GetTexture();
+ DLCTexturePackage.MetaData metaData = new DLCTexturePackage.MetaData(comparisonImg, iconImg);
+
+
+ bool a = TryGetAtlasFromResourceCategory(dataPck, ResourceCategory.BlockAtlas, out Atlas terrainAtlas);
+ bool b = TryGetAtlasFromResourceCategory(dataPck, ResourceCategory.ItemAtlas, out Atlas itemAtlas);
+
+ string itemAnimationResourcePath = ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation);
+ if (dataPck != null &&
+ dataPck.TryGetAsset(itemAnimationResourcePath + "/compass.png", PckAssetType.TextureFile, out PckAsset compassAsset) &&
+ dataPck.TryGetAsset(itemAnimationResourcePath + "/clock.png", PckAssetType.TextureFile, out PckAsset clockAsset))
+ {
+
+ }
+ return null;
+ }
+
+ private bool TryGetAtlasFromResourceCategory(PckFile pck, ResourceCategory resourceCategory, out Atlas atlas)
+ {
+ ResourceLocation resourceLocation = ResourceLocation.GetFromCategory(resourceCategory);
+ if (!pck.TryGetAsset(resourceLocation.ToString(), PckAssetType.TextureFile, out PckAsset asset))
+ {
+ Trace.TraceWarning($"Could not find '{resourceLocation}'.");
+ atlas = null;
+ return false;
+ }
+ atlas = asset.GetDeserializedData(new AtlasDeserializer(resourceLocation));
+ return true;
+ }
+
+ private IDLCPackage GetDLCSkinPackage(string name, int identifier, PckFile pck, PckFileReader fileReader, IDLCPackage parentPackage = null)
+ {
+ Skin.Skin GetSkinWithCape(PckAsset skinAsset)
+ {
+ Skin.Skin skin = skinAsset.GetSkin();
+ if (skinAsset.TryGetProperty("CAPEPATH", out string capeAssetPath) && pck.TryGetAsset(capeAssetPath, PckAssetType.CapeFile, out PckAsset capeAsset))
+ skin.CapeTexture = capeAsset.GetTexture();
+ return skin;
+ }
+
+ IEnumerable skins = pck.GetAssetsByType(PckAssetType.SkinFile).Select(GetSkinWithCape);
+
+ skins = skins.Concat(pck.GetAssetsByType(PckAssetType.SkinDataFile)
+ .Select(asset => asset.GetData(fileReader))
+ .SelectMany(pck => pck.GetAssetsByType(PckAssetType.SkinFile))
+ .Select(GetSkinWithCape)
+ );
+
+ return new DLCSkinPackage(name, identifier, skins, null, parentPackage);
+ }
+ }
+}
\ No newline at end of file
diff --git a/PckStudio.Core/DLCMashUpPackage.cs b/PckStudio.Core/DLCMashUpPackage.cs
new file mode 100644
index 00000000..385b48d4
--- /dev/null
+++ b/PckStudio.Core/DLCMashUpPackage.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using OMI.Formats.GameRule;
+using PckStudio.Core.Interfaces;
+
+namespace PckStudio.Core
+{
+ public sealed class DLCMashUpPackage : DLCPackage
+ {
+ public override string Description { get; }
+
+ private IDLCPackage _skinPackage;
+ private IDLCPackage _texturePackage;
+ private GameRuleFile _gameRule;
+ private IList> _audioData;
+ private NamedData _savegameData;
+
+ internal DLCMashUpPackage(string name, string description, int identifier, IDLCPackageLocationInfo packageInfo, GameRuleFile gameRule, IDLCPackage parentPackage, IDLCPackage skinPackage = null, IDLCPackage texturePackage = null)
+ : base(name, identifier, packageInfo, parentPackage)
+ {
+ Description = description;
+ _gameRule = gameRule;
+ _skinPackage = skinPackage;
+ _texturePackage = texturePackage;
+ }
+
+ internal DLCMashUpPackage(string name, string description, int identifier)
+ : this(name, description, identifier, null, new GameRuleFile(), null)
+ {
+ _skinPackage = DLCSkinPackage.CreateEmpty(this);
+ _texturePackage = DLCTexturePackage.CreateDefaultPackage(this);
+ _savegameData = new NamedData("world.mcs", Array.Empty());
+ _audioData = new List>();
+
+ _gameRule.AddRule("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")
+ .AddRule("UpdatePlayer",
+ new GameRuleFile.FloatParameter("yRot", 0f),
+ new GameRuleFile.FloatParameter("xRot", 0f),
+ new GameRuleFile.IntParameter("spawnX", 0),
+ new GameRuleFile.IntParameter("spawnY", 0),
+ new GameRuleFile.IntParameter("spawnZ", 0)
+ );
+ }
+
+ public IDLCPackage GetSkinPackage() => _skinPackage;
+ public IDLCPackage GetTexturePackage() => _texturePackage;
+
+ public override DLCPackageType GetDLCPackageType() => DLCPackageType.MashUpPack;
+ }
+}
diff --git a/PckStudio.Core/DLCPackage.cs b/PckStudio.Core/DLCPackage.cs
new file mode 100644
index 00000000..5549c213
--- /dev/null
+++ b/PckStudio.Core/DLCPackage.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PckStudio.Core.Interfaces;
+
+namespace PckStudio.Core
+{
+ public abstract class DLCPackage : IDLCPackage
+ {
+ protected DLCPackage(string name, int identifier, IDLCPackageLocationInfo packageInfo, IDLCPackage parentPackage)
+ {
+ Name = name;
+ Identifier = identifier;
+ PackageInfo = packageInfo;
+ ParentPackage = parentPackage;
+ }
+
+ public int Identifier { get; }
+
+ public IDLCPackageLocationInfo PackageInfo { get; }
+
+ public string Name { get; } = string.Empty;
+
+ public virtual string Description { get; } = string.Empty;
+
+ public abstract DLCPackageType GetDLCPackageType();
+
+ public IDLCPackage ParentPackage { get; }
+
+ public bool IsRootPackage => ParentPackage is null;
+ }
+}
diff --git a/PckStudio.Core/DLCPackageType.cs b/PckStudio.Core/DLCPackageType.cs
new file mode 100644
index 00000000..333cf391
--- /dev/null
+++ b/PckStudio.Core/DLCPackageType.cs
@@ -0,0 +1,15 @@
+namespace PckStudio.Core
+{
+ public enum DLCPackageType
+ {
+ Unknown = -1,
+ Invalid,
+ SkinPack,
+ TexturePack,
+ MashUpPack,
+ //! TODO: Add DLCPackage class for minigames... -null
+ MG01,
+ MG02,
+ MG03,
+ }
+}
\ No newline at end of file
diff --git a/PckStudio.Core/DLCSkinPackage.cs b/PckStudio.Core/DLCSkinPackage.cs
new file mode 100644
index 00000000..bff1bbeb
--- /dev/null
+++ b/PckStudio.Core/DLCSkinPackage.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using PckStudio.Core.Interfaces;
+using PckStudio.Core.Skin;
+
+namespace PckStudio.Core
+{
+ public enum DLCSkinPackageOrder
+ {
+ ById,
+ CapesFirst,
+ SkinsFirst
+ }
+
+ public sealed class DLCSkinPackage : DLCPackage
+ {
+ public DLCSkinPackageOrder SkinPackageOrder { get; set; } = DLCSkinPackageOrder.CapesFirst;
+
+ private readonly Dictionary _skins;
+
+ internal DLCSkinPackage(string name, int identifier, IEnumerable skins, IDLCPackageLocationInfo packageInfo, IDLCPackage parentPackage)
+ : base(name, identifier, packageInfo, parentPackage)
+ {
+ _skins = skins.ToDictionary(skin => skin.Identifier);
+ }
+
+ internal DLCSkinPackage(string name, int identifier, IDLCPackage parentPackage = null)
+ : this(name, identifier, Enumerable.Empty(), null, parentPackage)
+ {
+ }
+
+ internal static IDLCPackage CreateEmpty(string name, int identifier, IDLCPackage parentPackage = null) => new DLCSkinPackage(name, identifier, parentPackage);
+ internal static IDLCPackage CreateEmpty(IDLCPackage parentPackage) => CreateEmpty(parentPackage.Name, parentPackage.Identifier, parentPackage);
+
+ public bool TryGetSkin(SkinIdentifier skinIdentifier, out Skin.Skin skin) => _skins.TryGetValue(skinIdentifier, out skin);
+
+ public bool ContainsSkin(SkinIdentifier skinIdentifier) => _skins.ContainsKey(skinIdentifier);
+
+ public void AddSkin(Skin.Skin skin) => _skins.Add(skin.Identifier, skin);
+
+ public bool RemoveSkin(SkinIdentifier skinIdentifier) => _skins.Remove(skinIdentifier);
+
+ public Skin.Skin GetSkin(SkinIdentifier skinIdentifier) => _skins[skinIdentifier];
+
+ public IReadOnlyCollection GetSkins() => _skins.Values.Cast().ToArray();
+
+ public override DLCPackageType GetDLCPackageType() => DLCPackageType.SkinPack;
+ }
+}
\ No newline at end of file
diff --git a/PckStudio.Core/DLCTexturePackage.cs b/PckStudio.Core/DLCTexturePackage.cs
new file mode 100644
index 00000000..24957a2a
--- /dev/null
+++ b/PckStudio.Core/DLCTexturePackage.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using OMI.Formats.Color;
+using OMI.Formats.Material;
+using OMI.Formats.Model;
+using OMI.Formats.Pck;
+using OMI.Workers.Color;
+using PckStudio.Core.Interfaces;
+using PckStudio.Core.Properties;
+
+namespace PckStudio.Core
+{
+ public sealed class DLCTexturePackage : DLCPackage
+ {
+ public enum TextureResolution
+ {
+ x8,
+ x16,
+ x32,
+ x48,
+ x64,
+ x80,
+ x96,
+ x112,
+ x128
+ }
+
+ public override string Description { get; }
+ internal const string TexturePackDescriptionId = "IDS_TP_DESCRIPTION";
+
+ private TextureResolution _resolution;
+
+ //! Data for x{_resolution}Info.pck
+ public sealed class MetaData
+ {
+ public Image ComparisonImg { get; }
+ public Image IconImg { get; }
+
+ public MetaData(Image comparisonImg, Image iconImg)
+ {
+ ComparisonImg = comparisonImg;
+ IconImg = iconImg;
+ }
+ }
+
+ public MetaData Info { get; }
+
+ //! Data for x{16}Data.pck
+ //! => colours.col
+ private IDictionary _colors;
+ private IDictionary _waterColors;
+ private ModelContainer _customModels; //! => models.bin
+ private MaterialContainer _materials;
+
+ //! terrain mipmaps will be generated automatically. Add mipmap option to settings menu ? -null
+ private Atlas _terrainAtlas;
+ private Atlas _itemsAtlas;
+ private Atlas _particlesAtlas;
+ private Atlas _paintingAtlas;
+
+ private Image[] _blockEntityBreakImages; //! max = 10!
+ private IDictionary _itemAnimations;
+ private IDictionary _blockAnimations;
+
+ internal DLCTexturePackage(
+ string name,
+ string description,
+ int identifier,
+ MetaData metaData,
+ TextureResolution resolution,
+ Atlas terrainAtlas,
+ Atlas itemsAtlas,
+ Atlas particlesAtlas,
+ Atlas paintingAtlas,
+ IDictionary colors,
+ IDictionary waterColors,
+ ModelContainer customModels,
+ MaterialContainer materials,
+ Image[] blockEntityBreakImages,
+ IDictionary itemAnimations,
+ IDictionary blockAnimations,
+ IDLCPackageLocationInfo packageInfo,
+ IDLCPackage parentPackage
+ )
+ : base(name, identifier, packageInfo, parentPackage)
+ {
+ Description = description;
+ Info = metaData;
+ _resolution = resolution;
+ _terrainAtlas = terrainAtlas;
+ _itemsAtlas = itemsAtlas;
+ _particlesAtlas = particlesAtlas;
+ _paintingAtlas = paintingAtlas;
+ _colors = colors;
+ _waterColors = waterColors;
+ _customModels = customModels;
+ _materials = materials;
+ _blockEntityBreakImages = blockEntityBreakImages;
+ _itemAnimations = itemAnimations;
+ _blockAnimations = blockAnimations;
+ }
+
+ public TextureResolution GetResolution() => _resolution;
+
+ public override DLCPackageType GetDLCPackageType() => DLCPackageType.TexturePack;
+
+ internal static IDLCPackage CreateDefaultPackage(IDLCPackage parentPackage)
+ => CreateDefaultPackage(parentPackage.Name, parentPackage.Description, parentPackage.Identifier, parentPackage);
+
+ internal static IDLCPackage CreateDefaultPackage(string name, string description, int identifier, IDLCPackage parentPackage = null)
+ {
+ TextureResolution resolution = TextureResolution.x16;
+ MetaData metadata = new MetaData(Resources.Comparison, Resources.TexturePackIcon);
+
+ Atlas terrain = Atlas.FromResourceLocation(Resources.terrain_atlas , ResourceLocation.GetFromCategory(ResourceCategory.BlockAtlas));
+ Atlas items = Atlas.FromResourceLocation(Resources.items_atlas , ResourceLocation.GetFromCategory(ResourceCategory.ItemAtlas));
+ Atlas particles = Atlas.FromResourceLocation(Resources.particles_atlas, ResourceLocation.GetFromCategory(ResourceCategory.ParticleAtlas));
+ Atlas painting = Atlas.FromResourceLocation(Resources.paintings_atlas, ResourceLocation.GetFromCategory(ResourceCategory.PaintingAtlas));
+ //ColorContainer colors = new COLFileReader().FromStream(new MemoryStream());
+ IDictionary colors = null;
+ IDictionary waterColors = null;
+ Image[] blockEntityBreakImages = terrain.GetRange(0, 15, 10, ImageLayoutDirection.Horizontal).Select(t => t.Texture).ToArray();
+
+ return new DLCTexturePackage(
+ name, description, identifier, metadata, resolution,
+ terrain, items, particles, painting,
+ colors, waterColors,
+ new ModelContainer(),
+ new MaterialContainer(),
+ blockEntityBreakImages,
+ null, null,
+ null, parentPackage
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/PckStudio.Core/Interfaces/IDLCPackage.cs b/PckStudio.Core/Interfaces/IDLCPackage.cs
new file mode 100644
index 00000000..82ec6910
--- /dev/null
+++ b/PckStudio.Core/Interfaces/IDLCPackage.cs
@@ -0,0 +1,17 @@
+namespace PckStudio.Core.Interfaces
+{
+ public interface IDLCPackage
+ {
+ string Name { get; }
+ string Description { get; }
+ int Identifier { get; }
+
+ bool IsRootPackage { get; }
+
+ IDLCPackageLocationInfo PackageInfo { get; }
+
+ DLCPackageType GetDLCPackageType();
+
+ IDLCPackage ParentPackage { get; }
+ }
+}
diff --git a/PckStudio.Core/Interfaces/IDLCPackageLocationInfo.cs b/PckStudio.Core/Interfaces/IDLCPackageLocationInfo.cs
new file mode 100644
index 00000000..01425d20
--- /dev/null
+++ b/PckStudio.Core/Interfaces/IDLCPackageLocationInfo.cs
@@ -0,0 +1,7 @@
+namespace PckStudio.Core.Interfaces
+{
+ public interface IDLCPackageLocationInfo
+ {
+
+ }
+}
diff --git a/PckStudio.Core/InvalidDLCPackage.cs b/PckStudio.Core/InvalidDLCPackage.cs
new file mode 100644
index 00000000..e4456f21
--- /dev/null
+++ b/PckStudio.Core/InvalidDLCPackage.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PckStudio.Core.Interfaces;
+
+namespace PckStudio.Core
+{
+ // Dummy class
+ internal sealed class InvalidDLCPackage : DLCPackage
+ {
+ internal static IDLCPackage Instance { get; } = new InvalidDLCPackage();
+
+ private InvalidDLCPackage(string name, int identifier, IDLCPackageLocationInfo packageInfo, IDLCPackage parentPackage)
+ : base(name, identifier, packageInfo, parentPackage)
+ {
+ }
+
+ private InvalidDLCPackage()
+ : this(nameof(InvalidDLCPackage), -1, null, null)
+ {
+
+ }
+
+ public override DLCPackageType GetDLCPackageType() => DLCPackageType.Invalid;
+ }
+}
diff --git a/PckStudio.Core/MapData.cs b/PckStudio.Core/MapData.cs
new file mode 100644
index 00000000..61d92776
--- /dev/null
+++ b/PckStudio.Core/MapData.cs
@@ -0,0 +1,47 @@
+using System.Drawing;
+using OMI.Formats.GameRule;
+
+namespace PckStudio.Core
+{
+ public enum MiniGameId : int
+ {
+ None,
+ Battle,
+ Tumble,
+ Glide
+ }
+
+ public enum MapSize : int
+ {
+ Small,
+ Large,
+ Huge
+ }
+
+ public class MapData
+ {
+ public string Name { get; }
+ public Image Thumbnail { get; }
+ public GameRuleFile Grf { get; }
+ public 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),
+ new GameRuleFile.BoolParameter("flatworld", false),
+ new GameRuleFile.IntParameter("mapSize", (int)mapSize),
+ new GameRuleFile.IntParameter("themeId", 0)
+ );
+ Grf.AddRule("LevelRules", [new GameRuleFile.IntParameter("ruleType", (int)miniGame)]);
+
+ World = world;
+ }
+ }
+}
diff --git a/PckStudio.Core/PckStudio.Core.csproj b/PckStudio.Core/PckStudio.Core.csproj
index 19f40da6..366b2edb 100644
--- a/PckStudio.Core/PckStudio.Core.csproj
+++ b/PckStudio.Core/PckStudio.Core.csproj
@@ -1,7 +1,7 @@
-
+
Debug
AnyCPU
{345EABED-F0D1-4D04-B409-BABDEF747352}
@@ -12,8 +12,8 @@
PckStudio.Core
true
v4.8
- 12
- 512
+ 12
+ 512
true
true
True
@@ -59,11 +59,18 @@
+
+
+
+
+
+
+
@@ -91,12 +98,15 @@
+
+
+
@@ -120,10 +130,12 @@
+
+
@@ -151,10 +163,10 @@
13.0.3
-
- 1.9.2
-
-
+
+ 1.9.2
+
+
diff --git a/PckStudio.Core/ResourceLocation.cs b/PckStudio.Core/ResourceLocation.cs
index d633b8a6..95dbd5d4 100644
--- a/PckStudio.Core/ResourceLocation.cs
+++ b/PckStudio.Core/ResourceLocation.cs
@@ -121,27 +121,7 @@ namespace PckStudio.Core
["misc/additionalmapicons.png"] = new ResourceLocation("misc/additionalmapicons.png", ResourceCategory.AdditionalMapIconsAtlas, 4, tilesInfo: Tiles.AdditionalMapIconTileInfos),
};
- public static string GetPathFromCategory(ResourceCategory category)
- {
- return category switch
- {
- ResourceCategory.ItemAnimation => _categoryLookUp["textures/items"].ToString(),
- ResourceCategory.BlockAnimation => _categoryLookUp["textures/blocks"].ToString(),
- ResourceCategory.MobEntityTextures => _categoryLookUp["mob"].ToString(),
- ResourceCategory.ItemEntityTextures => _categoryLookUp["item"].ToString(),
- ResourceCategory.BlockAtlas => _categoryLookUp["terrain.png"].ToString(),
- ResourceCategory.ItemAtlas => _categoryLookUp["items.png"].ToString(),
- ResourceCategory.ParticleAtlas => _categoryLookUp["particles.png"].ToString(),
- ResourceCategory.BannerAtlas => _categoryLookUp["item/banner/Banner_Atlas.png"].ToString(),
- ResourceCategory.PaintingAtlas => _categoryLookUp["art/kz.png"].ToString(),
- ResourceCategory.ExplosionAtlas => _categoryLookUp["misc/explosion.png"].ToString(),
- ResourceCategory.ExperienceOrbAtlas => _categoryLookUp["item/xporb.png"].ToString(),
- ResourceCategory.MoonPhaseAtlas => _categoryLookUp["terrain/moon_phases.png"].ToString(),
- ResourceCategory.MapIconAtlas => _categoryLookUp["misc/mapicons.png"].ToString(),
- ResourceCategory.AdditionalMapIconsAtlas => _categoryLookUp["misc/additionalmapicons.png"].ToString(),
- _ => string.Empty
- };
- }
+ public static string GetPathFromCategory(ResourceCategory category) => GetFromCategory(category).ToString();
public static ResourceCategory GetCategoryFromPath(string path) => GetFromPath(path).Category;
@@ -204,5 +184,27 @@ namespace PckStudio.Core
{
return "res/" + Path;
}
+
+ internal static ResourceLocation GetFromCategory(ResourceCategory category)
+ {
+ return category switch
+ {
+ ResourceCategory.ItemAnimation => _categoryLookUp["textures/items"],
+ ResourceCategory.BlockAnimation => _categoryLookUp["textures/blocks"],
+ ResourceCategory.MobEntityTextures => _categoryLookUp["mob"],
+ ResourceCategory.ItemEntityTextures => _categoryLookUp["item"],
+ ResourceCategory.BlockAtlas => _categoryLookUp["terrain.png"],
+ ResourceCategory.ItemAtlas => _categoryLookUp["items.png"],
+ ResourceCategory.ParticleAtlas => _categoryLookUp["particles.png"],
+ ResourceCategory.BannerAtlas => _categoryLookUp["item/banner/Banner_Atlas.png"],
+ ResourceCategory.PaintingAtlas => _categoryLookUp["art/kz.png"],
+ ResourceCategory.ExplosionAtlas => _categoryLookUp["misc/explosion.png"],
+ ResourceCategory.ExperienceOrbAtlas => _categoryLookUp["item/xporb.png"],
+ ResourceCategory.MoonPhaseAtlas => _categoryLookUp["terrain/moon_phases.png"],
+ ResourceCategory.MapIconAtlas => _categoryLookUp["misc/mapicons.png"],
+ ResourceCategory.AdditionalMapIconsAtlas => _categoryLookUp["misc/additionalmapicons.png"],
+ _ => Unknown
+ };
+ }
}
}
diff --git a/Vendor/OMI-Lib b/Vendor/OMI-Lib
index 384aad45..0c8f3717 160000
--- a/Vendor/OMI-Lib
+++ b/Vendor/OMI-Lib
@@ -1 +1 @@
-Subproject commit 384aad45b3b4979ba21d42c97463006d34c06ae9
+Subproject commit 0c8f37177fb25b72b9a7c30a377f89a58b123084