From 3be27949f8557dd954276e256ac4d2a1a8496d64 Mon Sep 17 00:00:00 2001 From: Razmoth <12517189-Razmoth@users.noreply.gitlab.com> Date: Thu, 3 Nov 2022 19:32:12 +0400 Subject: [PATCH] v0.18.60 --- .../AssetStudio.PInvoke.csproj | 8 +- AssetStudio/AIVersionManager.cs | 6 +- AssetStudio/AssetStudio.csproj | 24 +--- AssetStudio/BundleFile.cs | 8 +- AssetStudio/CABManager.cs | 16 +-- AssetStudio/Classes/AnimationClip.cs | 10 +- AssetStudio/Classes/Animator.cs | 2 +- AssetStudio/Classes/AssetBundle.cs | 6 +- AssetStudio/Classes/Mesh.cs | 10 +- AssetStudio/Classes/Renderer.cs | 21 +-- AssetStudio/Classes/Shader.cs | 2 +- AssetStudio/Game/GameFile.cs | 58 +++++--- AssetStudio/Game/SR_CB3/BlocksFile.cs | 30 ++++ AssetStudio/GameManager.cs | 119 +++------------ AssetStudioCLI/AssetStudioCLI.csproj | 10 +- AssetStudioCLI/Program.cs | 83 ++++++----- AssetStudioCLI/Studio.cs | 40 ++++-- .../AssetStudioFBXNative.vcxproj | 16 +-- .../AssetStudioFBXWrapper.csproj | 8 +- AssetStudioGUI/AssetStudioGUI.csproj | 23 +-- AssetStudioGUI/AssetStudioGUIForm.Designer.cs | 39 ++--- AssetStudioGUI/AssetStudioGUIForm.cs | 136 +++++++++--------- AssetStudioGUI/Libraries/OpenTK.WinForms.dll | Bin 26624 -> 26112 bytes AssetStudioGUI/Studio.cs | 6 +- AssetStudioUtility/ACL/ACL.cs | 29 ++++ AssetStudioUtility/ACL/SRACL.cs | 35 ----- AssetStudioUtility/AnimationClipConverter.cs | 12 +- AssetStudioUtility/AssetStudioUtility.csproj | 10 +- AssetStudioUtility/ImageExtensions.cs | 4 +- AssetStudioUtility/ModelConverter.cs | 8 +- AssetStudioUtility/ShaderConverter.cs | 2 +- AssetStudioUtility/SpriteHelper.cs | 13 +- AssetStudioUtility/Texture2DExtensions.cs | 9 +- .../Texture2DDecoderWrapper.csproj | 8 +- 34 files changed, 390 insertions(+), 421 deletions(-) create mode 100644 AssetStudio/Game/SR_CB3/BlocksFile.cs delete mode 100644 AssetStudioUtility/ACL/SRACL.cs diff --git a/AssetStudio.PInvoke/AssetStudio.PInvoke.csproj b/AssetStudio.PInvoke/AssetStudio.PInvoke.csproj index 57cc224..9136396 100644 --- a/AssetStudio.PInvoke/AssetStudio.PInvoke.csproj +++ b/AssetStudio.PInvoke/AssetStudio.PInvoke.csproj @@ -1,11 +1,11 @@ - net472;netstandard2.0;net5.0;net6.0 + net6.0 true - 0.18.30 - 0.18.30 - 0.18.30 + 0.18.60 + 0.18.60 + 0.18.60 Copyright © Perfare 2020-2022; Copyright © hozuki 2020 embedded diff --git a/AssetStudio/AIVersionManager.cs b/AssetStudio/AIVersionManager.cs index 982cf45..54e59e9 100644 --- a/AssetStudio/AIVersionManager.cs +++ b/AssetStudio/AIVersionManager.cs @@ -12,8 +12,8 @@ namespace AssetStudio { public static class AIVersionManager { - private const string BaseUrl = "https://raw.githubusercontent.com/radioegor146/gi-asset-indexes/master/"; - private const string CommitsUrl = "https://api.github.com/repos/radioegor146/gi-asset-indexes/commits?path="; + private const string BaseUrl = "https://raw.githubusercontent.com/14eyes/gi-asset-indexes/master/"; + private const string CommitsUrl = "https://api.github.com/repos/14eyes/gi-asset-indexes/commits?path="; private const string VersionIndexName = "version-index.json"; private const string VersionIndexKey = "index"; @@ -220,7 +220,7 @@ namespace AssetStudio return commit; } - internal class VersionIndex + internal record VersionIndex { public string MappedPath = ""; public string RawPath = ""; diff --git a/AssetStudio/AssetStudio.csproj b/AssetStudio/AssetStudio.csproj index 4fd2a90..00d74de 100644 --- a/AssetStudio/AssetStudio.csproj +++ b/AssetStudio/AssetStudio.csproj @@ -1,27 +1,17 @@ - net472;netstandard2.0;net5.0;net6.0 - 0.18.30 - 0.18.30 - 0.18.30 + net6.0 + 0.18.60 + 0.18.60 + 0.18.60 Copyright © Razmoth 2022; Copyright © Perfare 2018-2022 embedded - - - - - - - - - - - - + - + + diff --git a/AssetStudio/BundleFile.cs b/AssetStudio/BundleFile.cs index adb4bd3..09025c6 100644 --- a/AssetStudio/BundleFile.cs +++ b/AssetStudio/BundleFile.cs @@ -77,7 +77,7 @@ namespace AssetStudio m_Header.unityVersion = "5.x.x"; m_Header.unityRevision = "2017.4.18f1"; } - else if (reader.Game.Name == "SR") + else if (reader.Game.Name == "SR_CB2" || reader.Game.Name == "SR_CB3") { var readHeader = m_Header.signature != "ENCR"; @@ -120,7 +120,7 @@ namespace AssetStudio case "UnityFS": case "ENCR": ReadHeader(reader); - if (reader.Game.Name == "ZZZ") + if (reader.Game.Name == "ZZZ_CB1") { reader.AlignStream(0x10); } @@ -282,7 +282,7 @@ namespace AssetStudio private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader) { byte[] blocksInfoBytes; - if (m_Header.version >= 7 && reader.Game.Name != "SR") + if (m_Header.version >= 7 && reader.Game.Name != "SR_CB2" && reader.Game.Name != "SR_CB3") { reader.AlignStream(16); } @@ -341,7 +341,7 @@ namespace AssetStudio } using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompresseddStream)) { - if (reader.Game.Name != "SR" || m_Header.signature != "ENCR") + if ((reader.Game.Name != "SR_CB2" && reader.Game.Name != "SR_CB3") || m_Header.signature != "ENCR") { var uncompressedDataHash = blocksInfoReader.ReadBytes(16); } diff --git a/AssetStudio/CABManager.cs b/AssetStudio/CABManager.cs index 3e0efce..8b21de6 100644 --- a/AssetStudio/CABManager.cs +++ b/AssetStudio/CABManager.cs @@ -12,7 +12,7 @@ namespace AssetStudio public static void BuildMap(List files, Game game) { - Logger.Info(string.Format("Building {0}", game.MapName)); + Logger.Info($"Building {game.Name}Map"); try { int collisions = 0; @@ -50,7 +50,7 @@ namespace AssetStudio } CABMap = CABMap.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value); - var outputFile = new FileInfo($"Maps/{game.MapName}.bin"); + var outputFile = new FileInfo($"Maps/{game.Name}Map.bin"); if (!outputFile.Directory.Exists) outputFile.Directory.Create(); @@ -71,20 +71,20 @@ namespace AssetStudio } } } - Logger.Info($"{game.MapName} build successfully, {collisions} collisions found !!"); + Logger.Info($"{game.Name}Map build successfully, {collisions} collisions found !!"); } catch (Exception e) { - Logger.Warning($"{game.MapName} was not build, {e.Message}"); + Logger.Warning($"{game.Name}Map was not build, {e.Message}"); } } public static void LoadMap(Game game) { - Logger.Info(string.Format("Loading {0}", game.MapName)); + Logger.Info($"Loading {game.Name}Map"); try { CABMap.Clear(); - using (var binaryFile = File.OpenRead($"Maps/{game.MapName}.bin")) + using (var binaryFile = File.OpenRead($"Maps/{game.Name}Map.bin")) using (var reader = new BinaryReader(binaryFile)) { var count = reader.ReadInt32(); @@ -103,11 +103,11 @@ namespace AssetStudio CABMap.Add(cab, new Entry(path, offset, dependencies)); } } - Logger.Info(string.Format("Loaded {0} !!", game.MapName)); + Logger.Info($"Loaded {game.Name}Map !!"); } catch (Exception e) { - Logger.Warning($"{game.Name} was not loaded, {e.Message}"); + Logger.Warning($"{game.Name}Map was not loaded, {e.Message}"); } } diff --git a/AssetStudio/Classes/AnimationClip.cs b/AssetStudio/Classes/AnimationClip.cs index 2eca1b8..305e0a3 100644 --- a/AssetStudio/Classes/AnimationClip.cs +++ b/AssetStudio/Classes/AnimationClip.cs @@ -189,7 +189,7 @@ namespace AssetStudio public uint m_ConstCurveCount; public ACLClip(ObjectReader reader) { - if (reader.Game.Name == "SR") + if (reader.Game.Name == "SR_CB2" || reader.Game.Name == "SR_CB3") { m_ClipDataUint = reader.ReadUInt32Array(); } @@ -201,7 +201,7 @@ namespace AssetStudio m_CurveCount = reader.ReadUInt32(); - if (reader.Game.Name == "SR") + if (reader.Game.Name == "SR_CB2" || reader.Game.Name == "SR_CB3") { m_ConstCurveCount = reader.ReadUInt32(); } @@ -970,7 +970,7 @@ namespace AssetStudio var version = reader.version; m_StreamedClip = new StreamedClip(reader); m_DenseClip = new DenseClip(reader); - if (reader.Game.Name == "SR") + if (reader.Game.Name == "SR_CB2" || reader.Game.Name == "SR_CB3") { m_ACLClip = new ACLClip(reader); } @@ -978,7 +978,7 @@ namespace AssetStudio { m_ConstantClip = new ConstantClip(reader); } - if (reader.Game.Name != "SR" && reader.Game.Name != "TOT") + if (reader.Game.Name != "SR_CB2" && reader.Game.Name != "SR_CB3" && reader.Game.Name != "TOT") { m_ACLClip = new ACLClip(reader); } @@ -1440,7 +1440,7 @@ namespace AssetStudio } if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up { - if (reader.Game.Name == "SR") + if (reader.Game.Name == "SR_CB2" || reader.Game.Name == "SR_CB3") { m_AclClipData = reader.ReadUInt8Array(); var aclBindingsCount = reader.ReadInt32(); diff --git a/AssetStudio/Classes/Animator.cs b/AssetStudio/Classes/Animator.cs index d38f64c..34bd42c 100644 --- a/AssetStudio/Classes/Animator.cs +++ b/AssetStudio/Classes/Animator.cs @@ -15,7 +15,7 @@ namespace AssetStudio { m_Avatar = new PPtr(reader); m_Controller = new PPtr(reader); - if (reader.Game.Name == "GI" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3") { var m_FBIKAvatar = new PPtr(reader); //FBIKAvatar placeholder } diff --git a/AssetStudio/Classes/AssetBundle.cs b/AssetStudio/Classes/AssetBundle.cs index ea587c3..b7e6b78 100644 --- a/AssetStudio/Classes/AssetBundle.cs +++ b/AssetStudio/Classes/AssetBundle.cs @@ -50,7 +50,7 @@ namespace AssetStudio Container[i] = new KeyValuePair(reader.ReadAlignedString(), new AssetInfo(reader)); } - if (reader.Game.Name == "GI" || reader.Game.Name == "CB1" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3") { MainAsset = new AssetInfo(reader); RuntimeComaptability = reader.ReadUInt32(); @@ -63,13 +63,13 @@ namespace AssetStudio { Dependencies[k] = reader.ReadAlignedString(); } - if (reader.Game.Name == "CB1" || reader.Game.Name == "CB2") + if (reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2") { IsStreamedScenessetBundle = reader.ReadBoolean(); reader.AlignStream(); PathFlags = reader.ReadInt32(); } - else if (reader.Game.Name == "CB3") + else if (reader.Game.Name == "GI_CB3") { IsStreamedScenessetBundle = reader.ReadBoolean(); reader.AlignStream(); diff --git a/AssetStudio/Classes/Mesh.cs b/AssetStudio/Classes/Mesh.cs index 043f039..0859eb2 100644 --- a/AssetStudio/Classes/Mesh.cs +++ b/AssetStudio/Classes/Mesh.cs @@ -569,7 +569,7 @@ namespace AssetStudio var m_KeepIndices = reader.ReadBoolean(); } reader.AlignStream(); - if (reader.Game.Name == "GI" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3") { var m_PackSkinDataToUV2UV3 = reader.ReadBoolean(); reader.AlignStream(); @@ -694,7 +694,7 @@ namespace AssetStudio } } - if (reader.Game.Name == "ZZZ") + if (reader.Game.Name == "ZZZ_CB1") { var m_CloseMeshDynamicCompression = reader.ReadBoolean(); reader.AlignStream(); @@ -704,7 +704,7 @@ namespace AssetStudio var m_CompressLevelTexCoordinates = reader.ReadInt32(); } - if (reader.Game.Name == "GI" || reader.Game.Name == "CB1" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3" + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3" || version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up { var m_MeshMetrics = new float[2]; @@ -712,13 +712,13 @@ namespace AssetStudio m_MeshMetrics[1] = reader.ReadSingle(); } - if (reader.Game.Name == "GI" || reader.Game.Name == "CB1" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3") { var m_MetricsDirty = reader.ReadBoolean(); reader.AlignStream(); var m_CloseMeshDynamicCompression = reader.ReadBoolean(); reader.AlignStream(); - if (reader.Game.Name != "CB1") + if (reader.Game.Name != "GI_CB1") { var m_IsStreamingMesh = reader.ReadBoolean(); reader.AlignStream(); diff --git a/AssetStudio/Classes/Renderer.cs b/AssetStudio/Classes/Renderer.cs index ac43772..f157fdb 100644 --- a/AssetStudio/Classes/Renderer.cs +++ b/AssetStudio/Classes/Renderer.cs @@ -52,7 +52,7 @@ namespace AssetStudio { var m_AllowHalfResolution = reader.ReadByte(); } - else if (reader.Game.Name == "CB3") + else if (reader.Game.Name == "GI_CB3") { var m_ReceiveDecals = reader.ReadByte(); var m_EnableShadowCulling = reader.ReadByte(); @@ -88,7 +88,7 @@ namespace AssetStudio { var m_StaticShadowCaster = reader.ReadByte(); } - if (reader.Game.Name == "CB2") + if (reader.Game.Name == "GI_CB2") { var m_ReceiveDecals = reader.ReadByte(); var m_EnableShadowCulling = reader.ReadByte(); @@ -97,7 +97,7 @@ namespace AssetStudio var m_IsRainOccluder = reader.ReadByte(); var m_IsDynamic = reader.ReadByte(); } - if (reader.Game.Name == "CB1") + if (reader.Game.Name == "GI_CB1") { var m_ReceiveDecals = reader.ReadByte(); var m_EnableShadowCulling = reader.ReadByte(); @@ -115,7 +115,7 @@ namespace AssetStudio { var m_RayTraceProcedural = reader.ReadByte(); } - if (reader.Game.Name == "GI" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB3") { var m_MeshShowQuality = reader.ReadByte(); } @@ -142,7 +142,7 @@ namespace AssetStudio var m_LightmapIndex = reader.ReadInt16(); var m_LightmapIndexDynamic = reader.ReadInt16(); - if (reader.Game.Name == "GI" || reader.Game.Name == "CB1" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3") { if (m_LightmapIndex != -1 || m_LightmapIndexDynamic != -1) throw new Exception("Not Supported !! skipping...."); @@ -159,7 +159,7 @@ namespace AssetStudio var m_LightmapTilingOffsetDynamic = reader.ReadVector4(); } - if (reader.Game.Name == "GI" || reader.Game.Name == "CB1" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3") { var m_ViewDistanceRatio = reader.ReadSingle(); var m_ShaderLODDistanceRatio = reader.ReadSingle(); @@ -188,7 +188,7 @@ namespace AssetStudio var m_StaticBatchRoot = new PPtr(reader); } - if (reader.Game.Name == "GI" || reader.Game.Name == "CB1" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3") { var m_MatLayers = reader.ReadInt32(); } @@ -226,11 +226,16 @@ namespace AssetStudio //SInt16 m_SortingLayer 5.6 and up var m_SortingOrder = reader.ReadInt16(); reader.AlignStream(); - if (reader.Game.Name == "GI" || reader.Game.Name == "CB1" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3" || reader.Game.Name == "BH3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3" || reader.Game.Name == "BH3") { var m_UseHighestMip = reader.ReadBoolean(); reader.AlignStream(); } + if (reader.Game.Name == "SR_CB3") + { + var _RenderFlag = reader.ReadUInt32(); + reader.AlignStream(); + } } } diff --git a/AssetStudio/Classes/Shader.cs b/AssetStudio/Classes/Shader.cs index 772ef99..a4ea97b 100644 --- a/AssetStudio/Classes/Shader.cs +++ b/AssetStudio/Classes/Shader.cs @@ -985,7 +985,7 @@ namespace AssetStudio decompressedLengths = reader.ReadUInt32Array().Select(x => new[] { x }).ToArray(); } compressedBlob = reader.ReadUInt8Array(); - if (reader.Game.Name == "GI" || reader.Game.Name == "CB2" || reader.Game.Name == "CB3") + if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3") { if (BitConverter.ToInt32(compressedBlob, 0) == -1) compressedBlob = reader.ReadUInt8Array(); diff --git a/AssetStudio/Game/GameFile.cs b/AssetStudio/Game/GameFile.cs index 3438b5c..25ae3f1 100644 --- a/AssetStudio/Game/GameFile.cs +++ b/AssetStudio/Game/GameFile.cs @@ -27,17 +27,17 @@ namespace AssetStudio var giFile = new GIFile(reader); bundles = giFile.Bundles; break; - case "CB1": - var cb1 = GameManager.GetGame("CB1"); - if (ext != cb1.Extension) + case "GI_CB1": + var gi_cb1 = GameManager.GetGame("GI_CB1"); + if (ext != gi_cb1.Extension) goto default; - var cb1File = new CB1File(reader); - bundles = cb1File.Bundles; + var gi_cb1File = new CB1File(reader); + bundles = gi_cb1File.Bundles; break; - case "CB2": - var cb2 = GameManager.GetGame("CB2"); - if (ext != cb2.Extension) + case "GI_CB2": + var gi_cb2 = GameManager.GetGame("GI_CB2"); + if (ext != gi_cb2.Extension) goto default; Blk.ExpansionKey = Crypto.CBXExpansionKey; @@ -45,12 +45,12 @@ namespace AssetStudio Blk.ConstKey = Crypto.CBXConstKey; Blk.ConstVal = Crypto.CBXConstVal; - var cb2File = new CBXFile(reader); - bundles = cb2File.Bundles; + var gi_cb2File = new CBXFile(reader); + bundles = gi_cb2File.Bundles; break; - case "CB3": - var cb3 = GameManager.GetGame("CB3"); - if (ext != cb3.Extension) + case "GI_CB3": + var gi_cb3 = GameManager.GetGame("GI_CB3"); + if (ext != gi_cb3.Extension) goto default; Blk.ExpansionKey = Crypto.CBXExpansionKey; @@ -58,8 +58,8 @@ namespace AssetStudio Blk.ConstKey = Crypto.CBXConstKey; Blk.ConstVal = Crypto.CBXConstVal; - var cb3File = new CBXFile(reader); - bundles = cb3File.Bundles; + var gi_cb3File = new CBXFile(reader); + bundles = gi_cb3File.Bundles; break; case "BH3": var bh3 = GameManager.GetGame("BH3"); @@ -75,8 +75,8 @@ namespace AssetStudio var wmvFile = new WMVFile(reader); bundles = wmvFile.Bundles; break; - case "ZZZ": - var zzz = GameManager.GetGame("ZZZ"); + case "ZZZ_CB1": + var zzz = GameManager.GetGame("ZZZ_CB1"); if (ext != zzz.Extension) goto default; @@ -89,9 +89,9 @@ namespace AssetStudio var zzzFile = new BundleFile(reader); bundles.Add(0, zzzFile.FileList); break; - case "SR": - var sr = GameManager.GetGame("SR"); - if (ext != sr.Extension) + case "SR_CB2": + var sr_cb2 = GameManager.GetGame("SR_CB2"); + if (ext != sr_cb2.Extension) goto default; Mr0k.ExpansionKey = Crypto.Mr0kExpansionKey; @@ -100,8 +100,22 @@ namespace AssetStudio Mr0k.SBox = null; Mr0k.BlockKey = null; - var srFile = new BundleFile(reader); - bundles.Add(0, srFile.FileList); + var sr_cb2File = new BundleFile(reader); + bundles.Add(0, sr_cb2File.FileList); + break; + case "SR_CB3": + var sr_cb3 = GameManager.GetGame("SR_CB3"); + if (ext != sr_cb3.Extension) + goto default; + + Mr0k.ExpansionKey = Crypto.Mr0kExpansionKey; + Mr0k.Key = Crypto.Mr0kKey; + Mr0k.ConstKey = Crypto.Mr0kConstKey; + Mr0k.SBox = null; + Mr0k.BlockKey = null; + + var sr_cb3File = new BlocksFile(reader); + bundles = sr_cb3File.Bundles; break; case "TOT": var tot = GameManager.GetGame("TOT"); diff --git a/AssetStudio/Game/SR_CB3/BlocksFile.cs b/AssetStudio/Game/SR_CB3/BlocksFile.cs new file mode 100644 index 0000000..288f537 --- /dev/null +++ b/AssetStudio/Game/SR_CB3/BlocksFile.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace AssetStudio +{ + public class BlocksFile + { + public Dictionary Bundles = new Dictionary(); + public BlocksFile(FileReader reader) + { + if (reader.BundlePos.Length != 0) + { + foreach (var pos in reader.BundlePos) + { + reader.Position = pos; + var bundle = new BundleFile(reader); + Bundles.Add(pos, bundle.FileList); + } + } + else + { + while (reader.Position != reader.Length) + { + var pos = reader.Position; + var bundle = new BundleFile(reader); + Bundles.Add(pos, bundle.FileList); + } + } + } + } +} diff --git a/AssetStudio/GameManager.cs b/AssetStudio/GameManager.cs index 6e711a9..eb6cc93 100644 --- a/AssetStudio/GameManager.cs +++ b/AssetStudio/GameManager.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; -using System.Security.Cryptography; namespace AssetStudio { @@ -11,14 +10,16 @@ namespace AssetStudio private static Dictionary Games = new Dictionary(); static GameManager() { - int count = 0; - foreach (Type type in - Assembly.GetAssembly(typeof(Game)).GetTypes() - .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(Game)))) - { - var format = (Game)Activator.CreateInstance(type); - Games.Add(count++, format); - } + int index = 0; + Games.Add(index++, new("GI", ".blk", "GI_Data|YS_Data")); + Games.Add(index++, new("GI_CB1", ".asb", "GS_Data")); + Games.Add(index++, new("GI_CB2", ".blk", "G_Data")); + Games.Add(index++, new("GI_CB3", ".blk", "YS_Data")); + Games.Add(index++, new("BH3", ".wmv", "BH3_Data")); + Games.Add(index++, new("ZZZ_CB1", ".bundle", "Win_Data/StreamingAssets/Bundles")); + Games.Add(index++, new("SR_CB2", ".unity3d", "SR_Data")); + Games.Add(index++, new("SR_CB3", ".block", "SR_Data")); + Games.Add(index++, new("TOT", ".blk", "AssetbundlesCache")); } public static Game GetGame(int index) { @@ -42,106 +43,20 @@ namespace AssetStudio } public static Game[] GetGames() => Games.Values.ToArray(); public static string[] GetGameNames() => Games.Values.Select(x => x.Name).ToArray(); - public static string SupportedGames() => $"Supported Games:\n{string.Join("\n", Games.Values.Select(x => $"{x.Name} ({x.DisplayName})"))}"; + public static string SupportedGames() => $"Supported Games:\n{string.Join("\n", Games.Values.Select(x => x.Name))}"; } - public abstract class Game + public record Game { public string Name; - public string DisplayName; public string Extension; - public string MapName; public string Path; - public override string ToString() => DisplayName; - } - - public class GI : Game - { - public GI() + public Game(string name, string extension, string path) { - Name = "GI"; - DisplayName = "GI"; - MapName = "BLKMap"; - Extension = ".blk"; - Path = "GI_Data|YS_Data"; - } - } - public class CB1 : Game - { - public CB1() - { - Name = "CB1"; - DisplayName = "GI_CB1"; - MapName = "CB1Map"; - Extension = ".asb"; - Path = "GS_Data"; - } - } - public class CB2 : Game - { - public CB2() - { - Name = "CB2"; - DisplayName = "GI_CB2"; - MapName = "CB2Map"; - Extension = ".blk"; - Path = "G_Data"; - } - } - public class CB3 : Game - { - public CB3() - { - Name = "CB3"; - DisplayName = "GI_CB3"; - MapName = "CB3Map"; - Extension = ".blk"; - Path = "YS_Data"; - } - } - public class BH3 : Game - { - public BH3() - { - Name = "BH3"; - DisplayName = "HI3"; - MapName = "WMVMap"; - Extension = ".wmv"; - Path = "BH3_Data"; - } - } - public class ZZZ : Game - { - public ZZZ() - { - Name = "ZZZ"; - DisplayName = "ZZZ"; - MapName = "ZZZMap"; - Extension = ".bundle"; - Path = "Win_Data/StreamingAssets/Bundles"; - } - } - public class SR : Game - { - public SR() - { - Name = "SR"; - DisplayName = "SR"; - MapName = "ENCRMap"; - Extension = ".unity3d"; - Path = "SR_Data"; - } - } - - public class TOT : Game - { - public TOT() - { - Name = "TOT"; - DisplayName = "ToT"; - MapName = "TOTMap"; - Extension = ".blk"; - Path = "AssetbundlesCache"; + Name = name; + Extension = extension; + Path = path; } + public override string ToString() => Name; } } diff --git a/AssetStudioCLI/AssetStudioCLI.csproj b/AssetStudioCLI/AssetStudioCLI.csproj index 39469d2..ced1645 100644 --- a/AssetStudioCLI/AssetStudioCLI.csproj +++ b/AssetStudioCLI/AssetStudioCLI.csproj @@ -2,17 +2,17 @@ Exe - net472;net5.0-windows;net6.0-windows + net6.0-windows Resources\as.ico - 0.18.30 - 0.18.30 - 0.18.30 + 0.18.60 + 0.18.60 + 0.18.60 Copyright © Razmoth 2022 ..\AssetStudioGUI\bin - + diff --git a/AssetStudioCLI/Program.cs b/AssetStudioCLI/Program.cs index cae67ca..a51c25c 100644 --- a/AssetStudioCLI/Program.cs +++ b/AssetStudioCLI/Program.cs @@ -6,6 +6,7 @@ using System.CommandLine.Binding; using System.Text.RegularExpressions; using static AssetStudioCLI.Studio; using AssetStudio; +using System.CommandLine.Parsing; namespace AssetStudioCLI { @@ -23,8 +24,9 @@ namespace AssetStudioCLI var rootCommand = new RootCommand() { optionsBinder.Silent, - optionsBinder.Types, - optionsBinder.Filters, + optionsBinder.TypeFilter, + optionsBinder.NameFilter, + optionsBinder.ContainerFilter, optionsBinder.GameName, optionsBinder.MapOp, optionsBinder.MapType, @@ -74,7 +76,7 @@ namespace AssetStudioCLI } } - if (o.AIFile != null && game.Name == "GI" || game.Name == "CB2" || game.Name == "CB3") + if (o.AIFile != null && game.Name == "GI" || game.Name == "GI_CB2" || game.Name == "GI_CB3") { ResourceIndex.FromFile(o.AIFile.FullName); } @@ -89,7 +91,7 @@ namespace AssetStudioCLI foreach (var file in files) { assetsManager.LoadFiles(file); - BuildAssetData(o.Types, o.Filters, ref i); + BuildAssetData(o.TypeFilter, o.NameFilter, o.ContainerFilter, ref i); ExportAssets(o.Output.FullName, exportableAssets, o.GroupAssetsType); exportableAssets.Clear(); assetsManager.Clear(); @@ -105,7 +107,7 @@ namespace AssetStudioCLI { throw new Exception("Unable to build AssetMap with input_path as a file !!"); } - var assets = BuildAssetMap(files.ToList(), o.Types, o.Filters); + var assets = BuildAssetMap(files.ToList(), o.TypeFilter, o.NameFilter, o.ContainerFilter); if (!o.Output.Exists) { o.Output.Create(); @@ -131,8 +133,9 @@ namespace AssetStudioCLI public class Options { public bool Silent { get; set; } - public ClassIDType[] Types { get; set; } - public Regex[] Filters { get; set; } + public ClassIDType[] TypeFilter { get; set; } + public Regex[] NameFilter { get; set; } + public Regex[] ContainerFilter { get; set; } public string GameName { get; set; } public MapOpType MapOp { get; set; } public ExportListType MapType { get; set; } @@ -149,8 +152,9 @@ namespace AssetStudioCLI public class OptionsBinder : BinderBase { public readonly Option Silent; - public readonly Option Types; - public readonly Option Filters; + public readonly Option TypeFilter; + public readonly Option NameFilter; + public readonly Option ContainerFilter; public readonly Option GameName; public readonly Option MapOp; public readonly Option MapType; @@ -166,8 +170,9 @@ namespace AssetStudioCLI public OptionsBinder() { Silent = new Option("--silent", "Hide log messages."); - Types = new Option("--type", "Specify unity class type(s)") { AllowMultipleArgumentsPerToken = true, ArgumentHelpName = "Texture2D|Sprite|etc.." }; - Filters = new Option("--filter", result => result.Tokens.Select(x => new Regex(x.Value, RegexOptions.IgnoreCase)).ToArray(), false, "Specify regex filter(s).") { AllowMultipleArgumentsPerToken = true }; + TypeFilter = new Option("--types", "Specify unity class type(s)") { AllowMultipleArgumentsPerToken = true, ArgumentHelpName = "Texture2D|Sprite|etc.." }; + NameFilter = new Option("--names", result => result.Tokens.Select(x => new Regex(x.Value, RegexOptions.IgnoreCase)).ToArray(), false, "Specify name regex filter(s).") { AllowMultipleArgumentsPerToken = true }; + ContainerFilter = new Option("--containers", result => result.Tokens.Select(x => new Regex(x.Value, RegexOptions.IgnoreCase)).ToArray(), false, "Specify container regex filter(s).") { AllowMultipleArgumentsPerToken = true }; GameName = new Option("--game", $"Specify Game.") { IsRequired = true }; MapOp = new Option("--map_op", "Specify which map to build."); MapType = new Option("--map_type", "AssetMap output type."); @@ -193,29 +198,9 @@ namespace AssetStudioCLI } }, false, "XOR key to decrypt MiHoYoBinData."); - Filters.AddValidator(result => - { - var values = result.Tokens.Select(x => x.Value).ToArray(); - foreach(var val in values) - { - if (string.IsNullOrWhiteSpace(val)) - { - result.ErrorMessage = "Empty string."; - return; - } - - try - { - Regex.Match("", val, RegexOptions.IgnoreCase); - } - catch (ArgumentException e) - { - result.ErrorMessage = "Invalid Regex.\n" + e.Message; - return; - } - } - }); - + TypeFilter.AddValidator(FilterValidator); + NameFilter.AddValidator(FilterValidator); + ContainerFilter.AddValidator(FilterValidator); XorByte.AddValidator(result => { var value = result.Tokens.Single().Value; @@ -244,12 +229,38 @@ namespace AssetStudioCLI MapType.SetDefaultValue(ExportListType.XML); } + public void FilterValidator(OptionResult result) + { + { + var values = result.Tokens.Select(x => x.Value).ToArray(); + foreach (var val in values) + { + if (string.IsNullOrWhiteSpace(val)) + { + result.ErrorMessage = "Empty string."; + return; + } + + try + { + Regex.Match("", val, RegexOptions.IgnoreCase); + } + catch (ArgumentException e) + { + result.ErrorMessage = "Invalid Regex.\n" + e.Message; + return; + } + } + } + } + protected override Options GetBoundValue(BindingContext bindingContext) => new Options { Silent = bindingContext.ParseResult.GetValueForOption(Silent), - Types = bindingContext.ParseResult.GetValueForOption(Types), - Filters = bindingContext.ParseResult.GetValueForOption(Filters), + TypeFilter = bindingContext.ParseResult.GetValueForOption(TypeFilter), + NameFilter = bindingContext.ParseResult.GetValueForOption(NameFilter), + ContainerFilter = bindingContext.ParseResult.GetValueForOption(ContainerFilter), GameName = bindingContext.ParseResult.GetValueForOption(GameName), MapOp = bindingContext.ParseResult.GetValueForOption(MapOp), MapType = bindingContext.ParseResult.GetValueForOption(MapType), diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 7a288bb..aab6b46 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -143,7 +143,7 @@ namespace AssetStudioCLI return extractedCount; } - public static List BuildAssetMap(List files, ClassIDType[] formats, Regex[] filters) + public static List BuildAssetMap(List files, ClassIDType[] typeFilters, Regex[] nameFilters, Regex[] containerFilters) { var assets = new List(); for (int i = 0; i < files.Count; i++) @@ -195,7 +195,7 @@ namespace AssetStudioCLI var preloadEnd = preloadIndex + preloadSize; for (int k = preloadIndex; k < preloadEnd; k++) { - if (Game.Name == "GI" || Game.Name == "CB2" || Game.Name == "CB3") + if (Game.Name == "GI" || Game.Name == "GI_CB2" || Game.Name == "GI_CB3") { if (long.TryParse(m_Container.Key, out var containerValue)) { @@ -258,8 +258,8 @@ namespace AssetStudioCLI objectAssetItemDic.Add(obj, asset); assetsFile.AddObject(obj); } - var isMatchRegex = filters.Length == 0 || filters.Any(x => x.IsMatch(asset.Name) || asset.Type == ClassIDType.Animator); - var isFilteredType = formats.Length == 0 || formats.Contains(asset.Type) || asset.Type == ClassIDType.Animator; + var isMatchRegex = nameFilters.Length == 0 || nameFilters.Any(x => x.IsMatch(asset.Name) || asset.Type == ClassIDType.Animator); + var isFilteredType = typeFilters.Length == 0 || typeFilters.Contains(asset.Type) || asset.Type == ClassIDType.Animator; if (isMatchRegex && isFilteredType && exportable) { assets.Add(asset); @@ -267,7 +267,7 @@ namespace AssetStudioCLI } foreach (var pair in animators) { - if (pair.Item1.TryGet(out var gameObject) && gameObject is GameObject && (filters.Length == 0 || filters.Any(x => x.IsMatch(gameObject.m_Name))) && (formats.Length == 0 || formats.Contains(pair.Item2.Type))) + if (pair.Item1.TryGet(out var gameObject) && gameObject is GameObject && (nameFilters.Length == 0 || nameFilters.Any(x => x.IsMatch(gameObject.m_Name))) && (typeFilters.Length == 0 || typeFilters.Contains(pair.Item2.Type))) { pair.Item2.Name = gameObject.m_Name; } @@ -280,7 +280,15 @@ namespace AssetStudioCLI { if (pptr.TryGet(out var obj)) { - objectAssetItemDic[obj].Container = container; + var item = objectAssetItemDic[obj]; + if (containerFilters.Length == 0 || containerFilters.Any(x => x.IsMatch(container))) + { + item.Container = container; + } + else + { + assets.Remove(item); + } } } assetsManager.assetsFileList.Clear(); @@ -296,7 +304,7 @@ namespace AssetStudioCLI return assets; } - public static void BuildAssetData(ClassIDType[] formats, Regex[] filters, ref int i) + public static void BuildAssetData(ClassIDType[] typeFilters, Regex[] nameFilters, Regex[] containerFilters, ref int i) { string productName = null; var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count); @@ -373,7 +381,7 @@ namespace AssetStudioCLI var preloadEnd = preloadIndex + preloadSize; for (int k = preloadIndex; k < preloadEnd; k++) { - if (Game.Name == "GI" || Game.Name == "CB2" || Game.Name == "CB3") + if (Game.Name == "GI" || Game.Name == "GI_CB2" || Game.Name == "GI_CB3") { if (long.TryParse(m_Container.Key, out var containerValue)) { @@ -440,8 +448,8 @@ namespace AssetStudioCLI { assetItem.Text = assetItem.TypeString + assetItem.UniqueID; } - var isMatchRegex = filters.Length == 0 || filters.Any(x => x.IsMatch(assetItem.Text)); - var isFilteredType = formats.Length == 0 || formats.Contains(assetItem.Asset.type); + var isMatchRegex = nameFilters.Length == 0 || nameFilters.Any(x => x.IsMatch(assetItem.Text)); + var isFilteredType = typeFilters.Length == 0 || typeFilters.Contains(assetItem.Asset.type); if (isMatchRegex && isFilteredType && exportable) { exportableAssets.Add(assetItem); @@ -453,7 +461,15 @@ namespace AssetStudioCLI { if (pptr.TryGet(out var obj)) { - objectAssetItemDic[obj].Container = container; + var item = objectAssetItemDic[obj]; + if (containerFilters.Length == 0 || containerFilters.Any(x => x.IsMatch(container))) + { + item.Container = container; + } + else + { + exportableAssets.Remove(item); + } } } containers.Clear(); @@ -474,7 +490,7 @@ namespace AssetStudioCLI case AssetGroupOption.ByContainer: //container path if (!string.IsNullOrEmpty(asset.Container)) { - exportPath = Path.HasExtension(asset.Container) ? Path.Combine(savePath, Path.GetDirectoryName(asset.Container)) : Path.Combine(savePath, asset.Container); + exportPath = Path.HasExtension(asset.Container) ? Path.Combine(savePath, Path.GetFileNameWithoutExtension(asset.Container)) : Path.Combine(savePath, asset.Container); } else { diff --git a/AssetStudioFBXNative/AssetStudioFBXNative.vcxproj b/AssetStudioFBXNative/AssetStudioFBXNative.vcxproj index 48b773d..0b57773 100644 --- a/AssetStudioFBXNative/AssetStudioFBXNative.vcxproj +++ b/AssetStudioFBXNative/AssetStudioFBXNative.vcxproj @@ -101,14 +101,14 @@ true _AS_DLL;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\include;%(AdditionalIncludeDirectories) + C:\Program Files\Autodesk\FBX\FBX SDK\2020.3.2\include;%(AdditionalIncludeDirectories) MultiThreadedDebug Console true libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;wininet.lib;%(AdditionalDependencies) - C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\lib\vs2019\x86\debug;%(AdditionalLibraryDirectories) + C:\Program Files\Autodesk\FBX\FBX SDK\2020.3.2\lib\vs2019\x86\debug;%(AdditionalLibraryDirectories) LIBCMT;%(IgnoreSpecificDefaultLibraries) @@ -120,7 +120,7 @@ true _AS_DLL;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\include;%(AdditionalIncludeDirectories) + C:\Program Files\Autodesk\FBX\FBX SDK\2020.3.2\include;%(AdditionalIncludeDirectories) MultiThreaded @@ -129,7 +129,7 @@ true true libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies) - C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\lib\vs2019\x86\release;%(AdditionalLibraryDirectories) + C:\Program Files\Autodesk\FBX\FBX SDK\2020.3.2\lib\vs2019\x86\release;%(AdditionalLibraryDirectories) @@ -138,14 +138,14 @@ true _AS_DLL;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\include;%(AdditionalIncludeDirectories) + C:\Program Files\Autodesk\FBX\FBX SDK\2020.3.2\include;%(AdditionalIncludeDirectories) MultiThreadedDebug Console true libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;wininet.lib;%(AdditionalDependencies) - C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\lib\vs2019\x64\debug;%(AdditionalLibraryDirectories) + C:\Program Files\Autodesk\FBX\FBX SDK\2020.3.2\lib\vs2019\x64\debug;%(AdditionalLibraryDirectories) LIBCMT;%(IgnoreSpecificDefaultLibraries) @@ -157,7 +157,7 @@ true _AS_DLL;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\include;%(AdditionalIncludeDirectories) + C:\Program Files\Autodesk\FBX\FBX SDK\2020.3.2\include;%(AdditionalIncludeDirectories) MultiThreaded @@ -166,7 +166,7 @@ true true libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies) - C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\lib\vs2019\x64\release;%(AdditionalLibraryDirectories) + C:\Program Files\Autodesk\FBX\FBX SDK\2020.3.2\lib\vs2019\x64\release;%(AdditionalLibraryDirectories) diff --git a/AssetStudioFBXWrapper/AssetStudioFBXWrapper.csproj b/AssetStudioFBXWrapper/AssetStudioFBXWrapper.csproj index df9416f..c7079b7 100644 --- a/AssetStudioFBXWrapper/AssetStudioFBXWrapper.csproj +++ b/AssetStudioFBXWrapper/AssetStudioFBXWrapper.csproj @@ -1,11 +1,11 @@ - net472;netstandard2.0;net5.0;net6.0 + net6.0 true - 0.18.30 - 0.18.30 - 0.18.30 + 0.18.60 + 0.18.60 + 0.18.60 Copyright © Perfare 2018-2022; Copyright © hozuki 2020 embedded diff --git a/AssetStudioGUI/AssetStudioGUI.csproj b/AssetStudioGUI/AssetStudioGUI.csproj index 6276f42..aede71e 100644 --- a/AssetStudioGUI/AssetStudioGUI.csproj +++ b/AssetStudioGUI/AssetStudioGUI.csproj @@ -2,12 +2,12 @@ WinExe - net472;net5.0-windows;net6.0-windows + net6.0-windows true Resources\as.ico - 0.18.30 - 0.18.30 - 0.18.30 + 0.18.60 + 0.18.60 + 0.18.60 Copyright © Razmoth 2022; Copyright © Perfare 2018-2022 embedded @@ -74,22 +74,13 @@ - - + + + Libraries\OpenTK.WinForms.dll - - - - - - - - - - diff --git a/AssetStudioGUI/AssetStudioGUIForm.Designer.cs b/AssetStudioGUI/AssetStudioGUIForm.Designer.cs index 2cff246..c5f6e6c 100644 --- a/AssetStudioGUI/AssetStudioGUIForm.Designer.cs +++ b/AssetStudioGUI/AssetStudioGUIForm.Designer.cs @@ -120,7 +120,7 @@ this.FMODpauseButton = new System.Windows.Forms.Button(); this.FMODplayButton = new System.Windows.Forms.Button(); this.fontPreviewBox = new System.Windows.Forms.RichTextBox(); - this.glControl1 = new OpenTK.GLControl(); + this.glControl = new OpenTK.WinForms.GLControl(); this.textPreviewBox = new System.Windows.Forms.TextBox(); this.classTextBox = new System.Windows.Forms.TextBox(); this.tabPage5 = new System.Windows.Forms.TabPage(); @@ -849,7 +849,7 @@ this.previewPanel.Controls.Add(this.assetInfoLabel); this.previewPanel.Controls.Add(this.FMODpanel); this.previewPanel.Controls.Add(this.fontPreviewBox); - this.previewPanel.Controls.Add(this.glControl1); + this.previewPanel.Controls.Add(this.glControl); this.previewPanel.Controls.Add(this.textPreviewBox); this.previewPanel.Controls.Add(this.classTextBox); this.previewPanel.Dock = System.Windows.Forms.DockStyle.Fill; @@ -1008,21 +1008,24 @@ this.fontPreviewBox.WordWrap = false; // // glControl1 - // - this.glControl1.BackColor = System.Drawing.SystemColors.ControlDarkDark; - this.glControl1.Dock = System.Windows.Forms.DockStyle.Fill; - this.glControl1.Location = new System.Drawing.Point(0, 0); - this.glControl1.Name = "glControl1"; - this.glControl1.Size = new System.Drawing.Size(768, 607); - this.glControl1.TabIndex = 4; - this.glControl1.Visible = false; - this.glControl1.VSync = false; - this.glControl1.Load += new System.EventHandler(this.glControl1_Load); - this.glControl1.Paint += new System.Windows.Forms.PaintEventHandler(this.glControl1_Paint); - this.glControl1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseDown); - this.glControl1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseMove); - this.glControl1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseUp); - this.glControl1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseWheel); + // + this.glControl.API = OpenTK.Windowing.Common.ContextAPI.OpenGL; + this.glControl.APIVersion = new System.Version(4, 6, 0, 0); + this.glControl.BackColor = System.Drawing.SystemColors.ControlDarkDark; + this.glControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.glControl.Flags = OpenTK.Windowing.Common.ContextFlags.Default; + this.glControl.IsEventDriven = true; + this.glControl.Location = new System.Drawing.Point(0, 0); + this.glControl.Name = "glControl1"; + this.glControl.Size = new System.Drawing.Size(768, 607); + this.glControl.TabIndex = 4; + this.glControl.Visible = false; + this.glControl.Load += new System.EventHandler(this.glControl1_Load); + this.glControl.Paint += new System.Windows.Forms.PaintEventHandler(this.glControl1_Paint); + this.glControl.MouseDown += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseDown); + this.glControl.MouseMove += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseMove); + this.glControl.MouseUp += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseUp); + this.glControl.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseWheel); // // textPreviewBox // @@ -1260,7 +1263,7 @@ private System.Windows.Forms.TextBox classTextBox; private System.Windows.Forms.ToolStripMenuItem exportClassStructuresMenuItem; private System.Windows.Forms.Label FMODcopyright; - private OpenTK.GLControl glControl1; + private OpenTK.WinForms.GLControl glControl; private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; private System.Windows.Forms.ToolStripMenuItem showOriginalFileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem exportAnimatorwithselectedAnimationClipMenuItem; diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs index cbfffda..c38fad6 100644 --- a/AssetStudioGUI/AssetStudioGUIForm.cs +++ b/AssetStudioGUI/AssetStudioGUIForm.cs @@ -1,6 +1,6 @@ using AssetStudio; using Newtonsoft.Json; -using OpenTK; +using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; using System; using System.Collections.Generic; @@ -20,14 +20,11 @@ using System.Timers; using System.Windows.Forms; using static AssetStudioGUI.Studio; using Font = AssetStudio.Font; -#if NET472 -using Vector3 = OpenTK.Vector3; -using Vector4 = OpenTK.Vector4; -#else using Vector3 = OpenTK.Mathematics.Vector3; using Vector4 = OpenTK.Mathematics.Vector4; using Matrix4 = OpenTK.Mathematics.Matrix4; -#endif +using OpenTK.Mathematics; +using SpirV; namespace AssetStudioGUI { @@ -54,14 +51,14 @@ namespace AssetStudioGUI private bool glControlLoaded; private int mdx, mdy; private bool lmdown, rmdown; - private int pgmID, pgmColorID, pgmBlackID; + private ProgramHandle pgmID, pgmColorID, pgmBlackID; private int attributeVertexPosition; private int attributeNormalDirection; private int attributeVertexColor; private int uniformModelMatrix; private int uniformViewMatrix; private int uniformProjMatrix; - private int vao; + private VertexArrayHandle vao; private Vector3[] vertexData; private Vector3[] normalData; private Vector3[] normal2Data; @@ -137,7 +134,7 @@ namespace AssetStudioGUI Studio.Game = GameManager.GetGame(Properties.Settings.Default.selectedGame); specifyGame.SelectedIndex = Properties.Settings.Default.selectedGame; specifyGame.SelectedIndexChanged += new EventHandler(toolStripComboBox2_SelectedIndexChanged); - Logger.Info($"Target Game is {Studio.Game.DisplayName}"); + Logger.Info($"Target Game is {Studio.Game.Name}"); CABManager.LoadMap(Studio.Game); } @@ -248,7 +245,7 @@ namespace AssetStudioGUI } else { - Text = $"Studio v{Application.ProductVersion} - {Studio.Game.DisplayName} - {Path.GetFileName(assetsManager.assetsFileList[0].originalPath)} - {assetsManager.assetsFileList[0].unityVersion} - {assetsManager.assetsFileList[0].m_TargetPlatform}"; + Text = $"Studio v{Application.ProductVersion} - {Studio.Game.Name} - {Path.GetFileName(assetsManager.assetsFileList[0].originalPath)} - {assetsManager.assetsFileList[0].unityVersion} - {assetsManager.assetsFileList[0].m_TargetPlatform}"; } assetListView.VirtualListSize = visibleAssets.Count; @@ -317,7 +314,7 @@ namespace AssetStudioGUI private void AssetStudioForm_KeyDown(object sender, KeyEventArgs e) { - if (glControl1.Visible) + if (glControl.Visible) { if (e.Control) { @@ -326,18 +323,18 @@ namespace AssetStudioGUI case Keys.W: //Toggle WireFrame wireFrameMode = (wireFrameMode + 1) % 3; - glControl1.Invalidate(); + glControl.Invalidate(); break; case Keys.S: //Toggle Shade shadeMode = (shadeMode + 1) % 2; - glControl1.Invalidate(); + glControl.Invalidate(); break; case Keys.N: //Normal mode normalMode = (normalMode + 1) % 2; CreateVAO(); - glControl1.Invalidate(); + glControl.Invalidate(); break; } } @@ -701,7 +698,7 @@ namespace AssetStudioGUI textPreviewBox.Visible = false; fontPreviewBox.Visible = false; FMODpanel.Visible = false; - glControl1.Visible = false; + glControl.Visible = false; StatusStripUpdate(""); FMODreset(); @@ -734,7 +731,7 @@ namespace AssetStudioGUI textPreviewBox.Visible = false; fontPreviewBox.Visible = false; FMODpanel.Visible = false; - glControl1.Visible = false; + glControl.Visible = false; StatusStripUpdate(""); if (e.IsSelected) { @@ -744,10 +741,10 @@ namespace AssetStudioGUI private void preview_Resize(object sender, EventArgs e) { - if (glControlLoaded && glControl1.Visible) + if (glControlLoaded && glControl.Visible) { - ChangeGLSize(glControl1.Size); - glControl1.Invalidate(); + ChangeGLSize(glControl.Size); + glControl.Invalidate(); } } @@ -1219,7 +1216,7 @@ namespace AssetStudioGUI } } #endregion - glControl1.Visible = true; + glControl.Visible = true; CreateVAO(); StatusStripUpdate("Using OpenGL Version: " + GL.GetString(StringName.Version) + "\n" + "'Mouse Left'=Rotate | 'Mouse Right'=Move | 'Mouse Wheel'=Zoom \n" @@ -1308,7 +1305,7 @@ namespace AssetStudioGUI assetInfoLabel.Text = null; textPreviewBox.Visible = false; fontPreviewBox.Visible = false; - glControl1.Visible = false; + glControl.Visible = false; lastSelectedItem = null; sortColumn = -1; reverseSort = false; @@ -1954,11 +1951,11 @@ namespace AssetStudioGUI #region GLControl private void InitOpenTK() { - ChangeGLSize(glControl1.Size); - GL.ClearColor(System.Drawing.Color.CadetBlue); + ChangeGLSize(glControl.Size); + GL.ClearColor(Color4.Dimgray); pgmID = GL.CreateProgram(); - LoadShader("vs", ShaderType.VertexShader, pgmID, out int vsID); - LoadShader("fs", ShaderType.FragmentShader, pgmID, out int fsID); + LoadShader("vs", ShaderType.VertexShader, pgmID, out var vsID); + LoadShader("fs", ShaderType.FragmentShader, pgmID, out var fsID); GL.LinkProgram(pgmID); pgmColorID = GL.CreateProgram(); @@ -1979,7 +1976,7 @@ namespace AssetStudioGUI uniformProjMatrix = GL.GetUniformLocation(pgmID, "projMatrix"); } - private static void LoadShader(string filename, ShaderType type, int program, out int address) + private static void LoadShader(string filename, ShaderType type, ProgramHandle program, out ShaderHandle address) { address = GL.CreateShader(type); var str = (string)Properties.Resources.ResourceManager.GetObject(filename); @@ -1989,50 +1986,47 @@ namespace AssetStudioGUI GL.DeleteShader(address); } - private static void CreateVBO(out int vboAddress, Vector3[] data, int address) + private static void CreateVBO(out BufferHandle vboAddress, Vector3[] data, int address) { - GL.GenBuffers(1, out vboAddress); - GL.BindBuffer(BufferTarget.ArrayBuffer, vboAddress); - GL.BufferData(BufferTarget.ArrayBuffer, - (IntPtr)(data.Length * Vector3.SizeInBytes), + GL.CreateBuffer(out vboAddress); + GL.BindBuffer(BufferTargetARB.ArrayBuffer, vboAddress); + GL.BufferData(BufferTargetARB.ArrayBuffer, data, - BufferUsageHint.StaticDraw); - GL.VertexAttribPointer(address, 3, VertexAttribPointerType.Float, false, 0, 0); - GL.EnableVertexAttribArray(address); + BufferUsageARB.StaticDraw); + GL.VertexAttribPointer((uint)address, 3, VertexAttribPointerType.Float, false, 0, 0); + GL.EnableVertexAttribArray((uint)address); } - private static void CreateVBO(out int vboAddress, Vector4[] data, int address) + private static void CreateVBO(out BufferHandle vboAddress, Vector4[] data, int address) { - GL.GenBuffers(1, out vboAddress); - GL.BindBuffer(BufferTarget.ArrayBuffer, vboAddress); - GL.BufferData(BufferTarget.ArrayBuffer, - (IntPtr)(data.Length * Vector4.SizeInBytes), + GL.CreateBuffer(out vboAddress); + GL.BindBuffer(BufferTargetARB.ArrayBuffer, vboAddress); + GL.BufferData(BufferTargetARB.ArrayBuffer, data, - BufferUsageHint.StaticDraw); - GL.VertexAttribPointer(address, 4, VertexAttribPointerType.Float, false, 0, 0); - GL.EnableVertexAttribArray(address); + BufferUsageARB.StaticDraw); + GL.VertexAttribPointer((uint)address, 4, VertexAttribPointerType.Float, false, 0, 0); + GL.EnableVertexAttribArray((uint)address); } - private static void CreateVBO(out int vboAddress, Matrix4 data, int address) + private static void CreateVBO(out BufferHandle vboAddress, Matrix4 data, int address) { - GL.GenBuffers(1, out vboAddress); - GL.UniformMatrix4(address, false, ref data); + GL.CreateBuffer(out vboAddress); + GL.UniformMatrix4f(address, false, data); } - private static void CreateEBO(out int address, int[] data) + private static void CreateEBO(out BufferHandle address, int[] data) { - GL.GenBuffers(1, out address); - GL.BindBuffer(BufferTarget.ElementArrayBuffer, address); - GL.BufferData(BufferTarget.ElementArrayBuffer, - (IntPtr)(data.Length * sizeof(int)), + GL.CreateBuffer(out address); + GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, address); + GL.BufferData(BufferTargetARB.ElementArrayBuffer, data, - BufferUsageHint.StaticDraw); + BufferUsageARB.StaticDraw); } private void CreateVAO() { GL.DeleteVertexArray(vao); - GL.GenVertexArrays(1, out vao); + GL.CreateVertexArray(out vao); GL.BindVertexArray(vao); CreateVBO(out var vboPositions, vertexData, attributeVertexPosition); if (normalMode == 0) @@ -2049,8 +2043,8 @@ namespace AssetStudioGUI CreateVBO(out var vboViewMatrix, viewMatrixData, uniformViewMatrix); CreateVBO(out var vboProjMatrix, projMatrixData, uniformProjMatrix); CreateEBO(out var eboElements, indiceData); - GL.BindBuffer(BufferTarget.ArrayBuffer, 0); - GL.BindVertexArray(0); + GL.BindBuffer(BufferTargetARB.ArrayBuffer, BufferHandle.Zero); + GL.BindVertexArray(VertexArrayHandle.Zero); } private void ChangeGLSize(Size size) @@ -2077,7 +2071,7 @@ namespace AssetStudioGUI private void glControl1_Paint(object sender, PaintEventArgs e) { - glControl1.MakeCurrent(); + glControl.MakeCurrent(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Lequal); @@ -2085,11 +2079,11 @@ namespace AssetStudioGUI if (wireFrameMode == 0 || wireFrameMode == 2) { GL.UseProgram(shadeMode == 0 ? pgmID : pgmColorID); - GL.UniformMatrix4(uniformModelMatrix, false, ref modelMatrixData); - GL.UniformMatrix4(uniformViewMatrix, false, ref viewMatrixData); - GL.UniformMatrix4(uniformProjMatrix, false, ref projMatrixData); - GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); - GL.DrawElements(BeginMode.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0); + GL.UniformMatrix4f(uniformModelMatrix, false, modelMatrixData); + GL.UniformMatrix4f(uniformViewMatrix, false, viewMatrixData); + GL.UniformMatrix4f(uniformProjMatrix, false, projMatrixData); + GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Fill); + GL.DrawElements(PrimitiveType.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0); } //Wireframe if (wireFrameMode == 1 || wireFrameMode == 2) @@ -2097,16 +2091,16 @@ namespace AssetStudioGUI GL.Enable(EnableCap.PolygonOffsetLine); GL.PolygonOffset(-1, -1); GL.UseProgram(pgmBlackID); - GL.UniformMatrix4(uniformModelMatrix, false, ref modelMatrixData); - GL.UniformMatrix4(uniformViewMatrix, false, ref viewMatrixData); - GL.UniformMatrix4(uniformProjMatrix, false, ref projMatrixData); - GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); - GL.DrawElements(BeginMode.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0); + GL.UniformMatrix4f(uniformModelMatrix, false, modelMatrixData); + GL.UniformMatrix4f(uniformViewMatrix, false, viewMatrixData); + GL.UniformMatrix4f(uniformProjMatrix, false, projMatrixData); + GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Line); + GL.DrawElements(PrimitiveType.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0); GL.Disable(EnableCap.PolygonOffsetLine); } - GL.BindVertexArray(0); + GL.BindVertexArray(VertexArrayHandle.Zero); GL.Flush(); - glControl1.SwapBuffers(); + glControl.SwapBuffers(); } private void tabControl2_SelectedIndexChanged(object sender, EventArgs e) @@ -2212,7 +2206,7 @@ namespace AssetStudioGUI Properties.Settings.Default.Save(); Studio.Game = GameManager.GetGame(Properties.Settings.Default.selectedGame); - Logger.Info($"Target Game is {Studio.Game.DisplayName}"); + Logger.Info($"Target Game is {Studio.Game.Name}"); ResetForm(); assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text; @@ -2234,10 +2228,10 @@ namespace AssetStudioGUI private void glControl1_MouseWheel(object sender, MouseEventArgs e) { - if (glControl1.Visible) + if (glControl.Visible) { viewMatrixData *= Matrix4.CreateScale(1 + e.Delta / 1000f); - glControl1.Invalidate(); + glControl.Invalidate(); } } @@ -2276,7 +2270,7 @@ namespace AssetStudioGUI dy *= 0.003f; viewMatrixData *= Matrix4.CreateTranslation(-dx, dy, 0); } - glControl1.Invalidate(); + glControl.Invalidate(); } } diff --git a/AssetStudioGUI/Libraries/OpenTK.WinForms.dll b/AssetStudioGUI/Libraries/OpenTK.WinForms.dll index 6b1270610ca731b6736fa86cbf3e08326a18b389..fcdf83a1e02b8b5b54a8d2179313d919a63cd1f4 100644 GIT binary patch literal 26112 zcmeHvd0<=BmG^m1(z7J5^6sokLK5LPPMkp4!Sa$s;4QYYr#OnO#3HtyBgsjeV6a(2 zfkGRmP-sJe(iWJODRc?YVP6X^6sD!qw6qOV%F@yqn4v9ZD15(j?t5AsXglA`e={%9 zdFOZTx#ym{zH{%B)xPO7%k;*nhbm28En22W`ESRr!DBZb25|`aJA* zGBZw8oi@S(>$;h!0PM~Ch{Cq)Z@K%^u8X!Ccy(63`c!mp3izGPAV`zCT7Cn`?_@j58LX;C+lh?YRZDbKF95fi+$6{MXOIB z+OU#H6X}1Q%+dqXh`hDus=How)j2RWztVAN3?`kmr&@ByR0w~awbL%ZSmfJuwlPcJ zj~;Q>&ea`b!a(4%1;U`T8LT;1uL@wG7+@+DW7O6s^C1}*g9&|q9x~2fT)05rj}~;A zZLA%b$(a)lJ%ABn)R(F>huIFK2j;QLu{qC{oU`nlr8zlK*^keOHb$AV?VRN~IYXJ8 zSJ>V<7nCn@1^mb`e{q5Bc?(-P0G}(t1m+;IF70@0#>g^d#GEU|*%s6F?_eujMQ`mh zuvG(CAF%6>34vN1$EM3w&bk71cbM}z3sKopoiIarocQ$fy=cyL%X4c43y`fZuXno zN14!S9p+l3aeFL>?ideA)fD;%#)(KtV)A)Sa9+5`sobWp2+M{NRGBM~ipF94=pbIZ zVgDouy@8WK1E+x06&v%-Q^Cxhx79oiccb=dmA`J9a%ORdS_L*#bILXdjl&$=Ien~%-;kf3;fVseO_QS z1m5|x-!cMUv88THI{QsaSevNT;TtBRcb~NHwqwgVC%c^4Zv}3FHLtU-(g>W5Y(xGJ zKm71dy>V6CqH=Trv)@{CMm1 zs@edSH*eK)aJqNVEQ1#`9u#snG4(~sFfq@)USsjE^ykr}TA&NiTw|pMFnYaa4@ly6 zG|P0JOUgFJu-9D236F9@0FzA;Dr>)l*|Y)38e98$uJGc-cOF89UM};eHg1hZr13B} zH*%(OnGm&S>w!&x7vM?ebeM3=J4J-3Kt!M5OlrPj(i*i_WMwqZMdHXTe)KHX7u4zw zvzK!nmeGqDH60o1s+4E*7dsX#%6FJsp}}L7*Mtabe_)Muw_YVnL2Upd!kS?fI_50T z%VZzRu(Ws=EV8GnBftwt?W0yX7}rwGIy}F)x|Nk`)l-XJG74RDJ7>VdQKq^hu!G?y zI5GgnaX}$+)!R$U7mKw(3}UpbtTnnMo2*%Dwa0nPUz91H*K%tGkq3gglNI70tuV-G zJg(5ta#@YGKObH!_E~c@c|A;yu_$}eE-tiCRbU|(sTRsYtD8}|^a`nqx!ONk#+61u zCcbT>@~_#bU6-5zljA&8l0(dKLm_-9<(tf5Onj>jtcgIPh&@im0mh1%-7oY518bL& zG$A&JSy9BZ`^{ZxU?#xUPRDb^XWOhau_PM5%+mwaNP7v(GHE5U=99-m=xU-<^(s-) z14+()rlT%j*)~&*Y5LMUdH{NONcoD~fe{FcjKFT(0(+Rx3+zqvuE40xd!0!Hq~83z ze+)OD%LrV+(6H`#4!6r^?7tAQ4Mk3H zc=w|NodFXh!4d5V*|qltAomEyM( zJYaq~UHDDKPsez|3eJtfBM7bJocsLk&NDWQF$)PA)j4Xdyp%kr*!Dg2p(Zi6&&qo|@>(ps^E#53urVWWDQ@|R=dpIpC29;N z4*(a~xJ2Q?z-5q18<#l)pG@(HXhs{V1qA@6FHxinEX5N=4U~;P#;FZeieG;KYga^^gtuVuEVITG_Qk=UpD$&b$LFQ>Smu4yi@U>I>V#5j~ahj zLxX~-nT|rY;Ij>5;z4|{M99VRE`0Vu_RJJHkI!o$`w2c?(N=a&0RMH!j!uzdQKcs# z`|T9@OvwKkvUjrNWtivVTsW@T1y{lR^!b(CAP;3o@^dJc;aO8;yw-ZZEP1LjNy4S` zh#i$tWLbHt|6(4MacZ6#&NJ1IwCtnHnU+o$n-8UZ%h)+zGc}=+sTq;)n~@X z<&k0~&oSl9Oy^Nbe~WLkJ}%E+C}*}O*Lmegu1qydR)uC~dOgegbm>{L>`eK&R;QGd zRn1JMad|Kz3@OLrD*I|-AgHhf!az`I3xt87$`%L%0iJovhA7&g_=}2{f^Sm16nwMd zrQlnbuQb1;ZnyHS+WfLYU%{>RXS(@S+$#gOf$HY%S^OPY{NJbfy}aasVQ(Wu=PcpiAxayJARkOsC%0gO+hc7g721~4X#+UqP84@)pIS*KVJynuW> zT#e*Eu|>?Lrk=B#H0#u`0C@Ka^-JrQFJ0bn3IKMegPOVuB(au}7HiY$nQoygck=8V5ZewL!P}SD=9-i$1L+@$J3Ck27 zw={%L5k8ynfxm>}$cYd9q%-l^g%9h&9G{&K=87Dt&ci)|52x|Ri;v6V3vp*%q8p1i zjdN%P*OnP{gV1kz`^t*xJD64mdGb#xG$>y1MzKMM^O>G1{ENb`7n%|}N96zR6&;~x zN#40ae^$J((xA`hGoA1zY7E-$Wqi|XlBAJZx~ zxAq*gNj=?Obtdw@j+QZ~vxe>T6*7M7KR;qLV3gha2SeQ%G&{jos#K&z?;T{{?VD@y2s>Y~aBMz;&;CG<>DQRNUyE0MJ2rJPnor%BrV<&4U( zi@OD>hpSLsnn4>y^Ch4N(0&?638xXGnRFBBm@e<);WS^HNp}c(58lq#0v4K$Rbak$ z7SICPQyy?Fpk;-1t_HfuSmM&?;=JXc-!WEzK39GU=%1?30R57S<(;KL(7o;#QSDQD*m zgFj@9fDRe^K!0R#DPPRH5VR<71*~!DhH)3;)lO z_gBh}$R8B>QzHMq$Zr%$47}~he8<(Ww$RCRzs7Wt(ED`e$0YTiMKV)pO603V{<`qX zgf>g+?}XkhsppH$n>djZmA|OF=(83Y zD839c_#O-GDSl4J>TRL&>aV-<=v50%D?Wtt7{^>ydR=in(8(6s;XZ_CWXeJ<)r>B* zk?(rlO`lOnTEb0-(&%oNn_d_6IKAh3lsvS7AFep1exUkpmzVAp^tk)=iuWm>UboU- z!D^UK1;;7PSq7u?E#$(}FQ4wR(8*QzxbmrbzS4ZG>H${)9k9@R*W<1tde}lC)S;N# z7qI5zwApwRXt$sV`gJw0a@Pnt;Qq1mA*@?pvCuDod~~ms@5k`0l)kT!_J;FOpntW} zE~&a%E29|;RSCxzK1$`ZMbHF2j}j{ADl07?Em1*-EOdS4qX<~OWof?Rdd5{nKNoa> zc)V28`xfGnRZZ0aF5v(@R`r6bn#L{kqNF`2NR6y&`msXpyz-ww^ChK;KKhNThL#?$ z{Pg1qHjTCldR4pM!^l)=K=nZ5f+pzoyx+N|(*Or}=)YGAuhHhw_XHiF16BX&nok3Z zIZc(mfZkcc=zyEY-~xKzLOcc+kZY+*yQcgQEu=yV-Bw-?RB0g|*8!SkAs*KOT4*7j z569CI3-Nq7o=&z9&!bvuv=GmuS_)Z+NBJUJV<8^pi)fRD{MDbMI@)HTW!1mc>u9Hi z9xppgiz#WLpO$Gr=PN}2;L(kGddosDm*)Xp+`#oaNC%1wfxat9tyxRx_bN?hzcdOo zpDg^(Vy7d6p7r>$P(^uF7JA1sHwy)PhbWWpwM3-2pA!LeKcpr?RNNTa^eM#qV1lmJ?hMn5cQbexn%zXUotjZ(f=2(b(x{c~B#68_cr&)-5x{X#_h?>r zx{dlQ#68_kyDY>#-9Z;xh(Zx-U7UQd6v5cl*3%9p|Qs)u`eBh^@ldwLTsv=I07W;)TDw0Kevi_l7UF*2PS0D2`+W!f(n8$t12PK6={mo^s?vzjo04`N{jBt$V<-KGh2ANh zVeF*$(`cT-yH%obI_MA5Ji|<*%Yb%Kg-pTg$W?Z{k)+va)L`sRYc8UbjnOpvJT(~S z18MX$HsOC8{b4z4F2yESBgMaqlOv6o>NMSD^R`a5WtHnMQE?5{7MHS}^Q4qjWo-Fg zNF21RhWF>EgSzM&l_l8s{e5*wNgjQzu%yIIPhcyL*x$$csua%qx791#&%Z1F|H+kY z;eU!h3pLd!n|`x|CE4_Us;vLM9W@fNy;Xd+w~ButkNc<=$0-`UApD6^)BhUppi5K)r|^UMnr32BD`24GIkjT_bd((1_5O z&|RPvG%Ear(1W1U=>|}PZV`GP=p1?(w1nOe8q!`XT}TnodU}L7-ddxx{vDzp(Zjw3 zB?gzj^(wI_tWR{CQ+SzarB1(J82 zzXg5J&AB*6-=!a})U{FFS?tzM(bjnm(+(>tmh@?I7w{0{Kr6 zG2dYE@42~-cOa%c0?H-MESss_q5nhmaoQ33g}Y9R=tnD;YIlo1^CxQe>8B!ce?<4V z&jP>D+p4`Fk|R`6b&fWndpuo`zn!;HdqZ!o*$VoF;tK6;eOBdmO>>-A83#Q8f8N$# zu1KL2j{GNy?{U0Sbfxw--Q>PTTca&1`#j_v+wao* zox1ii`tcR`|9SUq+8hU3Tbrcmo_nFgQT-9(Xnv!{EqR1)1^9kPwvtVLg#o#b>S1J5qo%pc8l{(?FQ|j&J0e(>Uue#sV8c_O& z+8u0757T_A0gcg2eL~w%GY52^b1~>mpqFc3@hsJ265Su6lTo9)k!u^|2i!aL`@pC4 zgW6JjpX;FZle~TU5#k~b?*$q(j`|xk zj_(^Zj^rCOj@cVD9@`BX$KeecN8AnCk1%>0v>#wJHfS&U-h$lc{gZyYc6;ezVoyE* z{~-9|wWso!ZZ2l3`iNt&N#fXRk~rp?B#yNviDRru;@E1EIHsB;j-@7vW2i~u*lChD zW|}09l_rT}B+N}jLz9#c%CXQSaSSv`9Q#ZX$2^n7vCbrMjDvZKXl9Z)rh!CKIfj`e zj$I~+W0pzcSY?tpMwujzMka})5R@g9qYk7ZzL+GAGGdPJA)bin#f416beJNTH5zv2 zd+9ERo6e{2fR5959R=8}{S^Eq^bq(OZ_+Z*w2y%if}l=~b==xY&;pHpDACRV zU#@W})mj(m42>=LHTLH?jmrvXYr)qEzf{`<{sfJEK3QWwPuG3~zER^+TC`r!)mlGj zn-&A@l3Zae4t|5iwcDa4LAPq$GX2_K@B`YIb0J+xUC!fi7T|E#(yjDm(68Y%ydEbN zw`2cTMt6fwr{_WE(Gk!^RGe3jZ^ZaPPou@4&9nye9Qrh94;=#COt*pd3EfHegHO_b zfbIuvroTgp&3L+XIU`bTL?nF{WqBWcfu^~mNWI22A@YkY%BdG4HR!%nQg5cY@cd>; zy+!C_B6&WZ@c37zRJLLU+Ow9fWl7G863s?)*xbA%5%I5jAIMCef* zXL;QHPL@CH`WD*%sL-u>oOj&K^k$(C3q2~7JS_JMZ4|my=(y0Eg+46ws8IfzhR01_ z$tApB_(q{yg&xi4R4Nc1p^ZYf3LO`Ev(Sfy9u-Q3qA#>j=vJZQLT?uOu+XDIsYvvN zHVWM;bX=$#CxI6^Z>Hzyk5r?bsy(BfrU!8zs3AVmF_I8$(eIq2pf1EHM1wwl@AVws z!4Qp>z76`D0;ZSZ-4fo3RU>4lkb#4LY7og+ebc~ShBp@feGB{s!axj{hf_K?&gL+` z;UQZl_gQdmPFV}+zN*!r9Yt-RoAfT`J?lU}RlWsufAKcZPgf6sE-hxwoo=S9tA+Z8 zz`t3s3pBrc52(`rS~;gG3(A_ZtSqdkK7iDh%D6;d$(5ilcn*Trlz$HNUC)<5>wIkC zUrU(&bsaa=q4i5}o}}ZS3%ejU^eHc%aHl84rDgSxRgaO?Dg z>S!YmP8UnCCe}jUft4I@pFsK9SqJ&G(w|-E zPmR`qy6HNqhx~J(I{pe^3FJMXI^LEwfNsK5K*w5tBIp)63G@?m3h240rH-}!4CtQ^ zs?!*q1$qGmK`+GfLdVm+6?6ji%cFg;c1_W8IvuhOT945a!?XM6RH!#=ItQ zrs#F@QZ_}V-lrB|?iAuvgpXVuBZGsHZG+LR4HWE4#mqREPRkonHEd)=p1nWZ`EuHIa!MadS2%bq z0k(Ix1lzJ@9i74EaA;jHEE(EE9ietuVDH+48x-FY+ZSC)U1ltvT4}l69d7Gx4Yq_j zR#}3!aJMbk5l!_5yF!$-?#*VL{|Jypu)4aZxx2HijoEb>RyAwq+As`r5?Y~4TCKYk zGafkD6%KU@3)PNJw123(6^?gyG=;+L!7f%pN^>XLZbNu=Ynw>I!KR*Yr?9KKJJ$-+ z)!C&OF0*xISUJ%Y?6ypFhgPl56*hHtx3qSvfyATCQVcdXw|0eBhT2+t#6`HweSi@n|B}N0I*i-ZnGRPl@P|xjU-(&bWx!m+ol4=&UsRMv~F~=7C6j z2SlCmu1F#pPuVz@Y>o5E*iWHk2VCAA4aJ8?QnrwXdy6>&g{G11+oK85Yd2xBX(W|0 z&JtM=zmJZvoDj*FU zO4^7W>q$itDO=DPSMICTJ0o2kiT4jiRj>40Msj7X@#IJ%t-4{eWe)a7;|a5$_zB3q^OLp*?H22csvfr*U%=XAWJeUw*eJCj zJ)Vqa1Tv_GOfxlrI*1AviLQ<9hzo3qqC1ArGNJAK*YcrcD4vzd${6(-_1;)ETA471 zLPIEA{8U_1bVn>6itjdeMy*Amrw>)4keWL@Gv$#JO0J6~V>Xh3Zwt6oH3q4BB%X>5 zMZ=@RQCkx2ll91gXctaoPb>*nxp^>#e(A>0@1?`!u5Z78Q6bgrWVwUAJvwna@K`d26+XhG5qp3)L zBozs!5Xx;E;X*No`un5(8A-D_G>nOykQEw!WhJeR@5Z9NJ;v@eW9Vfvr8yaeX@u%- z8`-gg^)oU%ip@x-)I5`5`yGy@vMq!o3AD>f{J=wWkD1t+(dRYSOu*;Pp02@2YP*>j z$|R~>$I9(OR-)F{Vw1^aCx+r|Odf`j!DF;~qJ1NYSZcJ3r&W@dt79!-*lmyP7)gkY zW0Nu8`Vz5WemZ6nWtqxA)iq)O^=;gXqj+gS|l{*k`au?fxQ@Mt2oV<0QZ?hR{J zd{myH;YfTmlhBMovBOMcNvyHY?!l#Pu|YINM!#v)8kDOeN!ezoxIiB3GPK*Gk=;@I z*_0*WXPCftL(qn>u*YoBnNo&G$3<+ zeXJi`leu?UOmNd69|U{ya3{pP}1ROJbX^QDh^K7uS!IQ2V#B6w%E2r zBr%$v3MeO$9Ec36)z*6IN;%n&VM)yqq$9MUVXRv56h9^gGd;9^APQ(j57H${f&dDe z$ol@lLF!DqxDpd3DYD*vd5Ca5_<7ci_>U4yR<-eP1B?2qn8wCfzGbDiF?TX=X{~NR zfR>rs)EXZdqONFMDwq>VSWla**uw5d9;BHn)~nVQ1KrWxcsQBLS|;!iQ(16jZ12dh zHHc`p3Qi<{o7pE5(k{s!a1#8O!`72LS#Qa+Rul{#wSK5wecC{DyA>~seQEbDGa2JG zLcGeAbZ$Ej&pta^ZQa`!mDPkgOo>HhUCc=Fw8muVN4KdJDU*^r;Oo&~LntrPzc^Lk zA!y0fjFG9Ih$W#YPN}e(@Q6Wlof$_h=AL-YFcLv1nUzN*((B1!d~|98F9~>RX4|o$ zgzmYy?WA@*{GthNaB0Y3au^NO&7DP?q6stO-`e3E?*Od=GYPN>&=gAzMN}$3Hd+$+ zi*0Lqr13E=hOxFY1;u7;HWKK-cz={{_A|W6Ot8QT=h`E2#8?Rm_V=q8Cqdn^MY55M zZ5w3GG+8yM7cGt4>4}zERl22Iq-Etv%hF43E3X}Pm82JxM0WDRLnn=SRHyg(GMqDr51ud*Fb+Ym>q?|ZTESX~`4AqvUI}}m ziPdNe3T2%~A!1=KvL$$4PZjmXu^3q=Sn>c$k2ZTj&Is67Yf4H}d)olNk4q$nH*P62ayyTR{F zmplZ0u7!#A&eV&&omvCCt}CI-EweDIK1t{&P+}kMoa%=~RS&N35L%FXl>3jp)`B0^ z%k1f2>uEoJfMzjX;A&&s-(1r^sWa#0@i4WwRKF(C9_(RM`csV(yG6LohVhTRR{n9l zdAx9am9E`q_GqJ;b&@iIIu7FHZwfa0A;DL?3;R*ZZt(_R^8`SDvg zRd-jEj{gSe4V(GB&HTY;CT-@=7BivQj7vAF;ht~&a-mlVJqTJlel5OGqT`1DPT(lK z(j9r4ZdCZjCo~U`)~ zp5G~YH%g&5;>+p2iBs@>79BShO$1@S2nAOgek%4&tjQy-n(q+fCp5KcFNn9=iL!Pfv3V*a2bMoB2@n=iNUnm`aaVA>q0o^zL2>wIL zH~dE(p;3@eNO@NM7c=8et5ROb&&uX7(9A}eCfdrtv$|2>^}Eo-FBagEMts7bS5P{B z1fG_T|3dzw{1@ErBH#GS>c89XfX7harh(c7+8x8IfSV2_lcNZis?IGQKU{mc2zJoc z(9pRUXcrU|qTVcrao+@*1K%H;xRIN|fy4rCvob2vR6VX$wK}M7SE(C@8=5LAVB$`7 zyBj5-Ez#1x36Bzaq%RA-eyS*)@S%_j5!7Ujo;R}i-*YZ>OP1&lS^Q)c|K|)pp=I$d zn847Rscv%|_^OiouCsbC^u6dk)qT&tE$eDdIC{DJ2m8xDe0K3K);Qn9&jUK&WAZMO zcbL4zIeCuaO2=U z$;8Rf&4fxo{N&`XSU8biB{?;Ljez(-hWa=^2_b(q3B(UFP9T0J{Kb*+FV}11S6Dk6 z`$?T0^w!(LOdy<&X6yV`Mr;38=eJIF&RBupj=;Yhz6PF6Y&-?YmvS+uK* z{cfIsm~=dQ3kuZGeS$N<9u}J$WQOwci+NF9jlVqw^(__P#vl1IfDm^#-`v%1H%1tI z3s5ya_~j3BU zBiNN)oxe|=llpOXfVX$iet*jJ?}6)noLN|f_)n&F3QvR)O}phhmfE2)u70O8BZ zRGc}FQX58Ep-~|=M0}!%if*0B__^wQ#+TW_wPi- z__m)4#*-)2FGa8*zxV)(hC`9ud^`jfXmrU=UKql9VQ_HJ++)SqQ3yPt_yA@HzmkSp z8@^HX*VInaXhj%Rj>y@aU(PK3=5}d@K6&xy$Hp$AMEC*lw7+N+eA&$16dj1{j^SL1 z(0hwI`*=_8-!l-6i-okdA6d7@63LWb9YgmcyIl88Kl>Y`wRdstF2v`ZefVrqX-v7s z`~|Xw`0(!`CO-it>yj^$W#R6gmYzkM9(ZZqP;1Abbr(H;_7#ug?^%eNPu;Q>hw8~K z-I0Amc!RqoX^vpSvn9d(v?cB5mMNXN#oTt@7HgbsiAPfyq>J~+p;25o|Hc;!sEle!vPg?)twYe9 zfE~3J3?aDZEfQbH5$6gcH3Df80eEI(CJJ@LG(uweh#6{)G^1$=i$Ekzw3Wh3k<8@Mt#fvF^2zDmH)rW{y*l(Yg7OL literal 26624 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 JEv!`o{|~?3NV5O{ diff --git a/AssetStudioGUI/Studio.cs b/AssetStudioGUI/Studio.cs index 8befaf0..0c4fe18 100644 --- a/AssetStudioGUI/Studio.cs +++ b/AssetStudioGUI/Studio.cs @@ -209,7 +209,7 @@ namespace AssetStudioGUI var preloadEnd = preloadIndex + preloadSize; for (int k = preloadIndex; k < preloadEnd; k++) { - if (Game.Name == "GI" || Game.Name == "CB2" || Game.Name == "CB3") + if (Game.Name == "GI" || Game.Name == "GI_CB2" || Game.Name == "GI_CB3") { if (long.TryParse(m_Container.Key, out var containerValue)) { @@ -392,7 +392,7 @@ namespace AssetStudioGUI var preloadEnd = preloadIndex + preloadSize; for (int k = preloadIndex; k < preloadEnd; k++) { - if (Game.Name == "GI" || Game.Name == "CB2" || Game.Name == "CB3") + if (Game.Name == "GI" || Game.Name == "GI_CB2" || Game.Name == "GI_CB3") { if (long.TryParse(m_Container.Key, out var containerValue)) { @@ -617,7 +617,7 @@ namespace AssetStudioGUI case AssetGroupOption.ByContainer: //container path if (!string.IsNullOrEmpty(asset.Container)) { - exportPath = Game.Name == "GI" || Game.Name == "CB2" || Game.Name == "CB3" ? Path.Combine(savePath, Path.GetDirectoryName(asset.Container)) : Path.Combine(savePath, asset.Container); + exportPath = Path.HasExtension(asset.Container) ? Path.Combine(savePath, Path.GetFileNameWithoutExtension(asset.Container)) : Path.Combine(savePath, asset.Container); } else { diff --git a/AssetStudioUtility/ACL/ACL.cs b/AssetStudioUtility/ACL/ACL.cs index b3a471b..e1c1c40 100644 --- a/AssetStudioUtility/ACL/ACL.cs +++ b/AssetStudioUtility/ACL/ACL.cs @@ -32,4 +32,33 @@ namespace ACL #endregion } + + public static class SRACL + { + private const string DLL_NAME = "sracl"; + static SRACL() + { + DllLoader.PreloadDll(DLL_NAME); + } + public static void DecompressAll(uint[] data, out float[] values, out float[] times) + { + var pinned = GCHandle.Alloc(data, GCHandleType.Pinned); + var pData = pinned.AddrOfPinnedObject(); + DecompressAll(pData, out var pValues, out var numValues, out var pTimes, out var numTimes); + pinned.Free(); + + values = new float[numValues]; + Marshal.Copy(pValues, values, 0, numValues); + + times = new float[numTimes]; + Marshal.Copy(pTimes, times, 0, numTimes); + } + + #region importfunctions + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void DecompressAll(IntPtr data, out IntPtr pValues, out int numValues, out IntPtr pTimes, out int numTimes); + + #endregion + } } diff --git a/AssetStudioUtility/ACL/SRACL.cs b/AssetStudioUtility/ACL/SRACL.cs deleted file mode 100644 index 2515695..0000000 --- a/AssetStudioUtility/ACL/SRACL.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using AssetStudio.PInvoke; - -namespace ACL -{ - public static class SRACL - { - private const string DLL_NAME = "sracl"; - static SRACL() - { - DllLoader.PreloadDll(DLL_NAME); - } - public static void DecompressAll(uint[] data, out float[] values, out float[] times) - { - var pinned = GCHandle.Alloc(data, GCHandleType.Pinned); - var pData = pinned.AddrOfPinnedObject(); - DecompressAll(pData, out var pValues, out var numValues, out var pTimes, out var numTimes); - pinned.Free(); - - values = new float[numValues]; - Marshal.Copy(pValues, values, 0, numValues); - - times = new float[numTimes]; - Marshal.Copy(pTimes, times, 0, numTimes); - } - - #region importfunctions - - [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] - private static extern void DecompressAll(IntPtr data, out IntPtr pValues, out int numValues, out IntPtr pTimes, out int numTimes); - - #endregion - } -} diff --git a/AssetStudioUtility/AnimationClipConverter.cs b/AssetStudioUtility/AnimationClipConverter.cs index 25007f9..1b60bc8 100644 --- a/AssetStudioUtility/AnimationClipConverter.cs +++ b/AssetStudioUtility/AnimationClipConverter.cs @@ -50,14 +50,14 @@ namespace AssetStudio var lastSampleFrame = streamedFrames.Count > 1 ? streamedFrames[streamedFrames.Count - 2].time : 0.0f; var lastFrame = Math.Max(lastDenseFrame, lastSampleFrame); - if (m_Clip.m_ACLClip.IsSet && Game.Name != "SR") + if (m_Clip.m_ACLClip.IsSet && Game.Name != "SR_CB2" && Game.Name != "SR_CB3") { var lastACLFrame = ProcessACLClip(m_Clip, bindings, tos); lastFrame = Math.Max(lastFrame, lastACLFrame); } ProcessStreams(streamedFrames, bindings, tos, m_Clip.m_DenseClip.m_SampleRate); ProcessDenses(m_Clip, bindings, tos); - if (m_Clip.m_ACLClip.IsSet && Game.Name == "SR") + if (m_Clip.m_ACLClip.IsSet && (Game.Name == "SR_CB2" || Game.Name == "SR_CB3")) { var lastACLFrame = ProcessACLClip(m_Clip, bindings, tos); lastFrame = Math.Max(lastFrame, lastACLFrame); @@ -96,7 +96,7 @@ namespace AssetStudio { var curve = frame.keyList[curveIndex]; var index = curve.index; - if (animationClip.m_MuscleClip.m_Clip.m_ACLClip.IsSet && Game.Name != "SR") + if (animationClip.m_MuscleClip.m_Clip.m_ACLClip.IsSet && Game.Name != "SR_CB2" && Game.Name != "SR_CB3") index += (int)animationClip.m_MuscleClip.m_Clip.m_ACLClip.m_CurveCount; var binding = bindings.FindBinding(index); @@ -147,7 +147,7 @@ namespace AssetStudio for (var curveIndex = 0; curveIndex < dense.m_CurveCount;) { var index = (int)streamCount + curveIndex; - if (clip.m_ACLClip.IsSet && Game.Name != "SR") + if (clip.m_ACLClip.IsSet && Game.Name != "SR_CB2" && Game.Name != "SR_CB3") index += (int)clip.m_ACLClip.m_CurveCount; var binding = bindings.FindBinding(index); var path = GetCurvePath(tos, binding.path); @@ -177,7 +177,7 @@ namespace AssetStudio float[] values; float[] times; var acl = clip.m_ACLClip; - if (Game.Name != "SR") + if (Game.Name != "SR_CB2" && Game.Name != "SR_CB3") { acl.Process(out values, out times); } @@ -195,7 +195,7 @@ namespace AssetStudio for (int curveIndex = 0; curveIndex < acl.m_CurveCount;) { var index = curveIndex; - if (Game.Name == "SR") + if (Game.Name == "SR_CB2" || Game.Name == "SR_CB3") index += (int)(clip.m_StreamedClip.curveCount + clip.m_DenseClip.m_CurveCount); GenericBinding binding = bindings.FindBinding(index); string path = GetCurvePath(tos, binding.path); diff --git a/AssetStudioUtility/AssetStudioUtility.csproj b/AssetStudioUtility/AssetStudioUtility.csproj index 1417cc6..ae5b4d5 100644 --- a/AssetStudioUtility/AssetStudioUtility.csproj +++ b/AssetStudioUtility/AssetStudioUtility.csproj @@ -1,17 +1,17 @@ - net472;netstandard2.0;net5.0;net6.0 - 0.18.30 - 0.18.30 - 0.18.30 + net6.0 + 0.18.60 + 0.18.60 + 0.18.60 Copyright © Razmoth 2022; Copyright © Perfare 2018-2022 embedded - + diff --git a/AssetStudioUtility/ImageExtensions.cs b/AssetStudioUtility/ImageExtensions.cs index a6cbad7..02998a3 100644 --- a/AssetStudioUtility/ImageExtensions.cs +++ b/AssetStudioUtility/ImageExtensions.cs @@ -45,9 +45,9 @@ namespace AssetStudio public static byte[] ConvertToBytes(this Image image) where TPixel : unmanaged, IPixel { - if (image.TryGetSinglePixelSpan(out var pixelSpan)) + if (image.DangerousTryGetSinglePixelMemory(out var pixelSpan)) { - return MemoryMarshal.AsBytes(pixelSpan).ToArray(); + return MemoryMarshal.AsBytes(pixelSpan.Span).ToArray(); } return null; } diff --git a/AssetStudioUtility/ModelConverter.cs b/AssetStudioUtility/ModelConverter.cs index 54e90cf..b9a4320 100644 --- a/AssetStudioUtility/ModelConverter.cs +++ b/AssetStudioUtility/ModelConverter.cs @@ -884,7 +884,7 @@ namespace AssetStudio var m_ClipBindingConstant = animationClip.m_ClipBindingConstant ?? m_Clip.ConvertValueArrayToGenericBinding(); var m_ACLClip = m_Clip.m_ACLClip; var aclCount = m_ACLClip.m_CurveCount; - if (m_ACLClip.m_CurveCount != 0 && Game.Name != "SR") + if (m_ACLClip.m_CurveCount != 0 && Game.Name != "SR_CB2" && Game.Name != "SR_CB3") { m_ACLClip.Process(out var values, out var times); for (int frameIndex = 0; frameIndex < times.Length; frameIndex++) @@ -906,7 +906,7 @@ namespace AssetStudio for (int curveIndex = 0; curveIndex < frame.keyList.Length;) { var index = frame.keyList[curveIndex].index; - if (Game.Name != "SR") + if (Game.Name != "SR_CB2" && Game.Name != "SR_CB3") index += (int)aclCount; ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, frame.time, streamedValues, 0, ref curveIndex); } @@ -920,12 +920,12 @@ namespace AssetStudio for (int curveIndex = 0; curveIndex < m_DenseClip.m_CurveCount;) { var index = streamCount + curveIndex; - if (Game.Name != "SR") + if (Game.Name != "SR_CB2" && Game.Name != "SR_CB3") index += aclCount; ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, time, m_DenseClip.m_SampleArray, (int)frameOffset, ref curveIndex); } } - if (m_ACLClip.m_CurveCount != 0 && Game.Name == "SR") + if (m_ACLClip.m_CurveCount != 0 && Game.Name == "SR_CB2" && Game.Name != "SR_CB3") { m_ACLClip.ProcessSR(out var values, out var times); for (int frameIndex = 0; frameIndex < times.Length; frameIndex++) diff --git a/AssetStudioUtility/ShaderConverter.cs b/AssetStudioUtility/ShaderConverter.cs index 2597e58..f267644 100644 --- a/AssetStudioUtility/ShaderConverter.cs +++ b/AssetStudioUtility/ShaderConverter.cs @@ -44,7 +44,7 @@ namespace AssetStudio var compressedLength = shader.compressedLengths[i][j]; var decompressedLength = shader.decompressedLengths[i][j]; var decompressedBytes = new byte[decompressedLength]; - if (game.Name == "GI" || game.Name == "CB2" || game.Name == "CB3") + if (game.Name == "GI" || game.Name == "GI_CB2" || game.Name == "GI_CB3") { Buffer.BlockCopy(shader.compressedBlob, (int)offset, decompressedBytes, 0, (int)decompressedLength); } diff --git a/AssetStudioUtility/SpriteHelper.cs b/AssetStudioUtility/SpriteHelper.cs index db1ac99..5002967 100644 --- a/AssetStudioUtility/SpriteHelper.cs +++ b/AssetStudioUtility/SpriteHelper.cs @@ -84,20 +84,19 @@ namespace AssetStudio var matrix = Matrix3x2.CreateScale(m_Sprite.m_PixelsToUnits); matrix *= Matrix3x2.CreateTranslation(m_Sprite.m_Rect.width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.height * m_Sprite.m_Pivot.Y - textureRectOffset.Y); path = path.Transform(matrix); - var graphicsOptions = new GraphicsOptions - { - Antialias = false, - AlphaCompositionMode = PixelAlphaCompositionMode.DestOut - }; var options = new DrawingOptions { - GraphicsOptions = graphicsOptions + GraphicsOptions = new GraphicsOptions + { + Antialias = false, + AlphaCompositionMode = PixelAlphaCompositionMode.DestOut + } }; using (var mask = new Image(rect.Width, rect.Height, SixLabors.ImageSharp.Color.Black)) { mask.Mutate(x => x.Fill(options, SixLabors.ImageSharp.Color.Red, path)); var bursh = new ImageBrush(mask); - spriteImage.Mutate(x => x.Fill(graphicsOptions, bursh)); + spriteImage.Mutate(x => x.Fill(options, bursh)); spriteImage.Mutate(x => x.Flip(FlipMode.Vertical)); return spriteImage; } diff --git a/AssetStudioUtility/Texture2DExtensions.cs b/AssetStudioUtility/Texture2DExtensions.cs index e855ad0..847aaf6 100644 --- a/AssetStudioUtility/Texture2DExtensions.cs +++ b/AssetStudioUtility/Texture2DExtensions.cs @@ -7,6 +7,13 @@ namespace AssetStudio { public static class Texture2DExtensions { + private static Configuration _configuration; + + static Texture2DExtensions() + { + _configuration = Configuration.Default.Clone(); + _configuration.PreferContiguousImageBuffers = true; + } public static Image ConvertToImage(this Texture2D m_Texture2D, bool flip) { var converter = new Texture2DConverter(m_Texture2D); @@ -15,7 +22,7 @@ namespace AssetStudio { if (converter.DecodeTexture2D(buff)) { - var image = Image.LoadPixelData(buff, m_Texture2D.m_Width, m_Texture2D.m_Height); + var image = Image.LoadPixelData(_configuration, buff, m_Texture2D.m_Width, m_Texture2D.m_Height); if (flip) { image.Mutate(x => x.Flip(FlipMode.Vertical)); diff --git a/Texture2DDecoderWrapper/Texture2DDecoderWrapper.csproj b/Texture2DDecoderWrapper/Texture2DDecoderWrapper.csproj index 47af511..b1e6699 100644 --- a/Texture2DDecoderWrapper/Texture2DDecoderWrapper.csproj +++ b/Texture2DDecoderWrapper/Texture2DDecoderWrapper.csproj @@ -1,11 +1,11 @@ - net472;netstandard2.0;net5.0;net6.0 + net6.0 true - 0.18.30 - 0.18.30 - 0.18.30 + 0.18.60 + 0.18.60 + 0.18.60 Copyright © Perfare 2020-2022; Copyright © hozuki 2020 embedded