mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-05-23 03:56:15 +00:00
Core - Add ResourcePackImporter.cs
This commit is contained in:
9
PckStudio.Core/IO/Java/IVersion.cs
Normal file
9
PckStudio.Core/IO/Java/IVersion.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace PckStudio.Core.IO.Java
|
||||
{
|
||||
interface IVersion : IEquatable<Version>
|
||||
{
|
||||
string ToString(string seperator);
|
||||
}
|
||||
}
|
||||
@@ -5,32 +5,9 @@ using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace PckStudio.Core.IO.Java
|
||||
{
|
||||
public readonly struct ImportResult<T>(T result, int count)
|
||||
public readonly struct ImportResult<TResult, TStats>(TResult result, TStats stats)
|
||||
{
|
||||
public readonly T Result = result;
|
||||
|
||||
private const int STRIPE = sizeof(uint) * 8;
|
||||
private readonly BitVector32[] _masks = new BitVector32[count / STRIPE +1];
|
||||
private readonly int _count = count;
|
||||
|
||||
public void SetMarked(int i)
|
||||
{
|
||||
if (i >= _count)
|
||||
return;
|
||||
int bitVectorIndex = Math.DivRem(i, STRIPE, out int bit);
|
||||
_masks[bitVectorIndex][bit] = true;
|
||||
}
|
||||
|
||||
// MAGIC
|
||||
private static int CountBits(int i)
|
||||
{
|
||||
i -= ((i >> 1) & 0x55555555);
|
||||
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
|
||||
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
|
||||
}
|
||||
|
||||
public bool Success => _masks.All(m => m.Data == -1);
|
||||
public int RemainingCount => _masks.Select(m => CountBits(m.Data)).Sum();
|
||||
public int ImportCount => _count - RemainingCount;
|
||||
public readonly TResult Result = result;
|
||||
public readonly TStats Stats = stats;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace PckStudio.Core.IO.Java
|
||||
{
|
||||
struct McPackmeta
|
||||
public struct McPackmeta
|
||||
{
|
||||
[JsonProperty("pack")]
|
||||
public McPack Pack;
|
||||
|
||||
@@ -7,7 +7,11 @@ using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Documents;
|
||||
using ICSharpCode.SharpZipLib.GZip;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PckStudio.Core.Deserializer;
|
||||
using PckStudio.Core.DLC;
|
||||
using PckStudio.Core.Extensions;
|
||||
using PckStudio.Core.Properties;
|
||||
@@ -17,71 +21,99 @@ namespace PckStudio.Core.IO.Java
|
||||
public class ResourcePackImporter
|
||||
{
|
||||
internal const int TARGET_FORMAT_VERSION = 4;
|
||||
internal const string JAVA_RESOURCE_PACK_PATH = "assets/minecraft/textures";
|
||||
|
||||
|
||||
static readonly IReadOnlyDictionary<int, string> _formatToVersion = new Dictionary<int, string>()
|
||||
static readonly IReadOnlyDictionary<int, IVersion> _formatToVersion = new Dictionary<int, IVersion>()
|
||||
{
|
||||
[1] = "1.6.1 – 1.8.9",
|
||||
[2] = "1.9 – 1.10.2",
|
||||
[3] = "1.11 – 1.12.2",
|
||||
[1] = new VersionRange("1.6.1", "1.8.9"),
|
||||
[2] = new VersionRange("1.9", "1.10.2"),
|
||||
[3] = new VersionRange("1.11", "1.12.2"),
|
||||
|
||||
// ----- TARGET ----- //
|
||||
[4] = "1.13 – 1.14.4",
|
||||
[4] = new VersionRange("1.13", "1.14.4"),
|
||||
// ------------------ //
|
||||
|
||||
[5] = "1.15 – 1.16.1",
|
||||
[6] = "1.16.2 – 1.16.5",
|
||||
[7] = "1.17 – 1.17.1",
|
||||
[8] = "1.18 – 1.18.2",
|
||||
[9] = "1.19 – 1.19.2",
|
||||
[12] = "1.19.3",
|
||||
[13] = "1.19.4",
|
||||
[15] = "1.20 – 1.20.1",
|
||||
[18] = "1.20.2",
|
||||
[22] = "1.20.3 – 1.20.4",
|
||||
[32] = "1.20.5 – 1.20.6",
|
||||
[34] = "1.21 – 1.21.1",
|
||||
[42] = "1.21.2 – 1.21.3",
|
||||
[46] = "1.21.4",
|
||||
[55] = "1.21.5",
|
||||
[63] = "1.21.6",
|
||||
[64] = "1.21.7 – 1.21.8",
|
||||
[69] = "1.21.9 – 1.21.10",
|
||||
|
||||
[5] = new VersionRange("1.15", "1.16.1"),
|
||||
[6] = new VersionRange("1.16.2", "1.16.5"),
|
||||
[7] = new VersionRange("1.17", "1.17.1"),
|
||||
[8] = new VersionRange("1.18", "1.18.2"),
|
||||
[9] = new VersionRange("1.19", "1.19.2"),
|
||||
[12] = new SingleVersion("1.19.3"),
|
||||
[13] = new SingleVersion("1.19.4"),
|
||||
[15] = new VersionRange("1.20", "1.20.1"),
|
||||
[18] = new SingleVersion("1.20.2"),
|
||||
[22] = new VersionRange("1.20.3", "1.20.4"),
|
||||
[32] = new VersionRange("1.20.5", "1.20.6"),
|
||||
[34] = new VersionRange("1.21", "1.21.1"),
|
||||
[42] = new VersionRange("1.21.2", "1.21.3"),
|
||||
[46] = new SingleVersion("1.21.4"),
|
||||
[55] = new SingleVersion("1.21.5"),
|
||||
[63] = new SingleVersion("1.21.6"),
|
||||
[64] = new VersionRange("1.21.7", "1.21.8"),
|
||||
[69] = new VersionRange("1.21.9", "1.21.10"),
|
||||
};
|
||||
|
||||
public static DLCTexturePackage ImportTexturePack(string zipfilepath, LCEGameVersion gameVersion = default) => ImportTexturePack(new FileInfo(zipfilepath), gameVersion);
|
||||
public static DLCTexturePackage ImportTexturePack(FileInfo zipfile, LCEGameVersion gameVersion = default) => ImportTexturePack(new ZipArchive(zipfile.OpenRead()), gameVersion);
|
||||
public static DLCTexturePackage ImportTexturePack(ZipArchive zip, LCEGameVersion gameVersion = default)
|
||||
public class ImportStats(int maxTextures)
|
||||
{
|
||||
StreamReader packmeta = new StreamReader(zip.GetEntry("pack.mcmeta").Open());
|
||||
int format = JsonConvert.DeserializeObject<McPackmeta>(packmeta.ReadToEnd()).Pack.Format;
|
||||
Debug.WriteLine($"Pack format: {format}");
|
||||
throw new NotImplementedException();
|
||||
public int Animations => animations;
|
||||
public int Textures => textures;
|
||||
public int MissingTextures => _maxTextures - textures;
|
||||
public int MaxTextures => _maxTextures;
|
||||
|
||||
internal int animations = 0;
|
||||
internal int textures = 0;
|
||||
private int _maxTextures = maxTextures;
|
||||
}
|
||||
|
||||
public static ImportResult<Atlas> ImportAtlas(ZipArchive zip, AtlasResource atlasResource, LCEGameVersion gameVersion = default)
|
||||
LCEGameVersion _gameVersion;
|
||||
ZipArchive _zip;
|
||||
McPackmeta.McPack packMeta;
|
||||
|
||||
public ResourcePackImporter(ZipArchive zip, LCEGameVersion gameVersion)
|
||||
{
|
||||
_zip = zip;
|
||||
_gameVersion = gameVersion;
|
||||
packMeta = ReadPackMeta(zip);
|
||||
}
|
||||
|
||||
public static bool IsJavaResourcePack(ZipArchive zip) => zip.GetEntry("pack.mcmeta") is ZipArchiveEntry;
|
||||
|
||||
public McPackmeta.McPack ReadPackMeta(ZipArchive zip)
|
||||
{
|
||||
StreamReader packmeta = new StreamReader(zip.GetEntry("pack.mcmeta").Open());
|
||||
int format = JsonConvert.DeserializeObject<McPackmeta>(packmeta.ReadToEnd()).Pack.Format;
|
||||
Debug.WriteLineIf(format == TARGET_FORMAT_VERSION, "Target format version... less work?");
|
||||
Debug.WriteLine($"Importing textures from resource pack of version: {GetVersionFromFormat(format)}(Format:{format})");
|
||||
McPackmeta.McPack pack = JsonConvert.DeserializeObject<McPackmeta>(packmeta.ReadToEnd()).Pack;
|
||||
Debug.WriteLineIf(pack.Format == TARGET_FORMAT_VERSION, "Target format version... less work?");
|
||||
Debug.WriteLine($"Importing textures from resource pack of version: {GetVersionFromFormat(pack.Format)}(Format:{pack.Format})");
|
||||
return pack;
|
||||
}
|
||||
|
||||
Atlas atlas = Atlas.CreateDefault(atlasResource, gameVersion);
|
||||
string atlasPath = GetAtlasPathFromFormat(format, atlasResource.Type);
|
||||
string path = $"assets/minecraft/textures/{atlasPath}/";
|
||||
public DLCTexturePackage ImportAsTexturePack(ZipArchive zip)
|
||||
{
|
||||
ImportResult<Atlas, ImportStats> blocks = ImportAtlas(ResourceLocations.GetFromCategory(AtlasResource.GetId(AtlasResource.AtlasType.BlockAtlas)) as AtlasResource);
|
||||
ImportResult<Atlas, ImportStats> items = ImportAtlas(ResourceLocations.GetFromCategory(AtlasResource.GetId(AtlasResource.AtlasType.ItemAtlas)) as AtlasResource);
|
||||
|
||||
IReadOnlyDictionary<string, string> lookUpTable = GetVersionLookUpTable(format, atlasResource.Type);
|
||||
return null;
|
||||
}
|
||||
|
||||
public ImportResult<Atlas, ImportStats> ImportAtlas(AtlasResource atlasResource)
|
||||
{
|
||||
Atlas atlas = Atlas.CreateDefault(atlasResource, _gameVersion);
|
||||
string atlasPath = GetAtlasPathFromFormat(packMeta.Format, atlasResource.Type);
|
||||
string path = Path.Combine(JAVA_RESOURCE_PACK_PATH, atlasPath).Replace('\\', '/');
|
||||
|
||||
IReadOnlyDictionary<string, string> lookUpTable = GetVersionLookUpTable(atlasResource.Type);
|
||||
|
||||
IReadOnlyDictionary<string, int> map =
|
||||
atlasResource.TilesInfo.enumerate()
|
||||
.ToDictionary(tileInfo => string.IsNullOrEmpty(tileInfo.value.InternalName) ? $"{Guid.NewGuid()}.{tileInfo.index}" : tileInfo.value.InternalName, it => it.index);
|
||||
|
||||
IEnumerable<ZipArchiveEntry> entries = zip.Entries.Where(e => e.FullName.StartsWith(path) && !e.FullName.EndsWith("/"));
|
||||
IEnumerable<ZipArchiveEntry> entries = _zip.Entries.Where(e => e.FullName.StartsWith(path) && !e.FullName.EndsWith("/"));
|
||||
|
||||
IReadOnlyDictionary<string, ZipArchiveEntry> javaAnimations = entries.Where(e => e.FullName.EndsWith(".mcmeta")).ToDictionary(entry => entry.FullName);
|
||||
|
||||
ImportResult<Atlas> result = new ImportResult<Atlas>(atlas, atlas.TileCount);
|
||||
Size maxTileSize = Size.Empty;
|
||||
int maxWidth = 0;
|
||||
ImportStats stats = new ImportStats(atlas.TileCount);
|
||||
IDictionary<string, Animation> animations = new Dictionary<string, Animation>();
|
||||
foreach (ZipArchiveEntry t in entries)
|
||||
{
|
||||
if (!t.FullName.EndsWith(".png"))
|
||||
@@ -89,28 +121,41 @@ namespace PckStudio.Core.IO.Java
|
||||
string name = Path.GetFileNameWithoutExtension(t.FullName);
|
||||
if (!map.TryGetValue(name, out int i) && !(lookUpTable.TryGetValue(name, out string lceKey) && map.TryGetValue(lceKey, out i)))
|
||||
continue;
|
||||
|
||||
|
||||
if (i >= atlas.TileCount)
|
||||
continue;
|
||||
|
||||
Image img = Image.FromStream(t.Open());
|
||||
if (javaAnimations.ContainsKey(t.FullName + ".mcmeta"))
|
||||
bool isAnimation = false;
|
||||
if ((isAnimation = javaAnimations.TryGetValue(t.FullName + ".mcmeta", out ZipArchiveEntry animationEntry)))
|
||||
{
|
||||
string jsonData = animationEntry.ReadAllText();
|
||||
animations.Add(name, AnimationDeserializer.DefaultDeserializer.DeserializeJavaAnimation(JObject.Parse(jsonData), img));
|
||||
stats.animations++;
|
||||
img = img.GetArea(new Rectangle(Point.Empty, new Size(img.Width, img.Width)));
|
||||
}
|
||||
|
||||
if (img.Size.Width > maxTileSize.Width)
|
||||
maxTileSize = new Size(img.Size.Width, img.Size.Width);
|
||||
if (img.Width > maxWidth)
|
||||
maxWidth = img.Width;
|
||||
atlas[i].Texture = img;
|
||||
result.SetMarked(i);
|
||||
stats.textures++;
|
||||
}
|
||||
atlas.SetTileSize(new Size(maxWidth, maxWidth));
|
||||
ImportResult<Atlas, ImportStats> result = new ImportResult<Atlas, ImportStats>(atlas, stats);
|
||||
Debug.WriteLine("Import Stats");
|
||||
Debug.WriteLine($"Textures: {stats.Textures}/{stats.MaxTextures}({stats.MissingTextures} missing)");
|
||||
Debug.WriteLine($"Animations: {stats.Animations}");
|
||||
foreach (string item in animations.Keys)
|
||||
{
|
||||
Debug.WriteLine(item);
|
||||
}
|
||||
atlas.SetTileSize(maxTileSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
static readonly IReadOnlyDictionary<string, string> latest2lce_blocks = JsonConvert.DeserializeObject<Dictionary<string, string>>(Resources.latest2lce_blocks);
|
||||
static readonly IReadOnlyDictionary<string, string> latest2lce_items = JsonConvert.DeserializeObject<Dictionary<string, string>>(Resources.latest2lce_items);
|
||||
private static IReadOnlyDictionary<string, string> GetVersionLookUpTable(int format, AtlasResource.AtlasType atlasType)
|
||||
private static IReadOnlyDictionary<string, string> GetVersionLookUpTable(AtlasResource.AtlasType atlasType)
|
||||
{
|
||||
_ = format;
|
||||
return atlasType switch
|
||||
{
|
||||
AtlasResource.AtlasType.BlockAtlas => latest2lce_blocks,
|
||||
@@ -119,7 +164,7 @@ namespace PckStudio.Core.IO.Java
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetVersionFromFormat(int format) => _formatToVersion.TryGetValue(format, out string version) ? version : "unknown";
|
||||
private static string GetVersionFromFormat(int format) => _formatToVersion.TryGetValue(format, out IVersion versionRange) ? versionRange.ToString(" - ") : "unknown";
|
||||
|
||||
private static string GetAtlasPathFromFormat(int format, AtlasResource.AtlasType type)
|
||||
{
|
||||
@@ -140,20 +185,5 @@ namespace PckStudio.Core.IO.Java
|
||||
_ => throw new Exception()
|
||||
};
|
||||
}
|
||||
|
||||
private static int GetColumnsFromGameVersion(LCEGameVersion gameVersion, AtlasResource.AtlasType atlasType)
|
||||
{
|
||||
return gameVersion switch
|
||||
{
|
||||
LCEGameVersion._1_13 when atlasType == AtlasResource.AtlasType.BlockAtlas => 34,
|
||||
LCEGameVersion._1_13 when atlasType == AtlasResource.AtlasType.ItemAtlas => 17,
|
||||
|
||||
|
||||
LCEGameVersion._1_14 when atlasType == AtlasResource.AtlasType.BlockAtlas => 39,
|
||||
LCEGameVersion._1_14 when atlasType == AtlasResource.AtlasType.ItemAtlas => 18,
|
||||
_ when atlasType == AtlasResource.AtlasType.PaintingAtlas => 16,
|
||||
_ => throw new ArgumentException(nameof(gameVersion))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
15
PckStudio.Core/IO/Java/SingleVersion.cs
Normal file
15
PckStudio.Core/IO/Java/SingleVersion.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace PckStudio.Core.IO.Java
|
||||
{
|
||||
class SingleVersion(Version version) : IVersion
|
||||
{
|
||||
private readonly Version _version = version;
|
||||
|
||||
public SingleVersion(string version) : this(new Version(version)) { }
|
||||
|
||||
public bool Equals(Version other) => _version.Equals(other);
|
||||
|
||||
public string ToString(string _) => _version.ToString();
|
||||
}
|
||||
}
|
||||
14
PckStudio.Core/IO/Java/SpecificVerions.cs
Normal file
14
PckStudio.Core/IO/Java/SpecificVerions.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using PckStudio.Core.Extensions;
|
||||
|
||||
namespace PckStudio.Core.IO.Java
|
||||
{
|
||||
class SpecificVerions(params Version[] versions) : IVersion
|
||||
{
|
||||
private readonly Version[] _versions = versions;
|
||||
|
||||
public bool Equals(Version other) => other?.EqualsAny(_versions) ?? default;
|
||||
|
||||
public string ToString(string seperator) => _versions.ToString(seperator);
|
||||
}
|
||||
}
|
||||
16
PckStudio.Core/IO/Java/VersionRange.cs
Normal file
16
PckStudio.Core/IO/Java/VersionRange.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace PckStudio.Core.IO.Java
|
||||
{
|
||||
class VersionRange(Version min, Version max) : IVersion
|
||||
{
|
||||
private readonly Version _min = min;
|
||||
private readonly Version _max = max;
|
||||
|
||||
public VersionRange(string min, string max) : this(new Version(min), new Version(max)) { }
|
||||
|
||||
public bool Equals(Version other) => _min <= other && other <= _max;
|
||||
|
||||
public string ToString(string seperator) => $"{_min}{seperator}{_max}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user