From 55b9969a8e253a5754ee876ddc8aa74c993a7f41 Mon Sep 17 00:00:00 2001 From: D3fau4 <19638408+D3fau4@users.noreply.github.com> Date: Tue, 25 Jan 2022 02:42:53 +0100 Subject: [PATCH 1/3] Full support for Oodle compression (#440) * Full support for Oodle descompression * ups * Save/Compress support * throw exception if oo2core_6_win64 dll` dont exists * Show a MessageBox when the dll is not present --- .../FileFormats/Archives/GFPAK.cs | 22 +- Switch_Toolbox_Library/Compression/Oodle.cs | 245 ++++++++++++++++++ .../Compression/STLibraryCompression.cs | 14 +- Switch_Toolbox_Library/Toolbox_Library.csproj | 1 + 4 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 Switch_Toolbox_Library/Compression/Oodle.cs diff --git a/File_Format_Library/FileFormats/Archives/GFPAK.cs b/File_Format_Library/FileFormats/Archives/GFPAK.cs index b5fc795e..cf95f2b1 100644 --- a/File_Format_Library/FileFormats/Archives/GFPAK.cs +++ b/File_Format_Library/FileFormats/Archives/GFPAK.cs @@ -493,6 +493,11 @@ namespace FirstPlugin public void Save(System.IO.Stream stream) { + if (version == 0x1000 && !File.Exists($"{Runtime.ExecutableDir}\\oo2core_6_win64.dll")) + { + MessageBox.Show("It is necessary to have 'oo2core_6_win64.dll' in the executable folder."); + return; + } Write(new FileWriter(stream)); } @@ -544,6 +549,13 @@ namespace FirstPlugin GFPAKHashCache.EnsureHashCache(); version = reader.ReadInt32(); + + if (version == 0x1000 && !File.Exists($"{Runtime.ExecutableDir}\\oo2core_6_win64.dll")) + { + MessageBox.Show("It is necessary to have 'oo2core_6_win64.dll' in the executable folder."); + return; + } + uint padding = reader.ReadUInt32(); uint FileCount = reader.ReadUInt32(); FolderCount = reader.ReadInt32(); @@ -582,7 +594,7 @@ namespace FirstPlugin fileEntry.Read(reader); string Extension = FindMatch(fileEntry.FileData); - if (Extension.EndsWith("gfbanmcfg")) + if (Extension.EndsWith("gfbanmcfg") && version != 0x1000) { GFBANMCFG cfg = new GFBANMCFG(); cfg.Load(new MemoryStream(fileEntry.FileData)); @@ -847,6 +859,11 @@ namespace FirstPlugin } else if (Type == CompressionType.None) FileData = reader.ReadBytes((int)DecompressedFileSize); + else if (Type == CompressionType.Oodle) + { + FileData = reader.ReadBytes((int)CompressedFileSize); + FileData = STLibraryCompression.Type_Oodle.Decompress(FileData, (int)DecompressedFileSize); + } else FileData = reader.ReadBytes((int)CompressedFileSize); } @@ -882,7 +899,8 @@ namespace FirstPlugin else if (Type == CompressionType.Zlib) return STLibraryCompression.ZLIB.Compress(data); else if (Type == CompressionType.Oodle) - throw new Exception("Oodle compression type not supported yet for saving!"); + return STLibraryCompression.Type_Oodle.Compress(data, Toolbox.Library.Compression.Oodle.OodleLZ_Compressor.OodleLZ_Compressor_Kraken, + Toolbox.Library.Compression.Oodle.OodleLZ_CompressionLevel.OodleLZ_CompressionLevel_Optimal2); else return data; } diff --git a/Switch_Toolbox_Library/Compression/Oodle.cs b/Switch_Toolbox_Library/Compression/Oodle.cs new file mode 100644 index 00000000..3560e3cf --- /dev/null +++ b/Switch_Toolbox_Library/Compression/Oodle.cs @@ -0,0 +1,245 @@ +using System; +using System.Runtime.InteropServices; + +namespace Toolbox.Library.Compression +{ + // Code from https://github.com/JKAnderson/SoulsFormats/blob/master/SoulsFormats/Util/Oodle26.cs + public static class Oodle + { + public static byte[] Compress(byte[] source, OodleLZ_Compressor compressor, OodleLZ_CompressionLevel level) + { + IntPtr pOptions = OodleLZ_CompressOptions_GetDefault(compressor, level); + OodleLZ_CompressOptions options = Marshal.PtrToStructure(pOptions); + // Required for the game to not crash + options.seekChunkReset = true; + // This is already the default but I am including it for authenticity to game code + options.seekChunkLen = 0x40000; + pOptions = Marshal.AllocHGlobal(Marshal.SizeOf()); + + try + { + Marshal.StructureToPtr(options, pOptions, false); + long compressedBufferSizeNeeded = OodleLZ_GetCompressedBufferSizeNeeded(source.LongLength); + byte[] compBuf = new byte[compressedBufferSizeNeeded]; + long compLen = OodleLZ_Compress(compressor, source, source.LongLength, compBuf, level, pOptions, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0); + Array.Resize(ref compBuf, (int)compLen); + return compBuf; + } + finally + { + Marshal.FreeHGlobal(pOptions); + } + } + + public static byte[] Decompress(byte[] source, long uncompressedSize) + { + long decodeBufferSize = OodleLZ_GetDecodeBufferSize(uncompressedSize, true); + byte[] rawBuf = new byte[decodeBufferSize]; + long rawLen = OodleLZ_Decompress(source, source.LongLength, rawBuf, uncompressedSize); + Array.Resize(ref rawBuf, (int)rawLen); + return rawBuf; + } + + + /// + /// + /// + /// + /// + /// = NULL + /// = NULL + /// = NULL + /// = NULL + /// = 0 + [DllImport("oo2core_6_win64.dll", CallingConvention = CallingConvention.StdCall)] + private static extern long OodleLZ_Compress( + OodleLZ_Compressor compressor, + [MarshalAs(UnmanagedType.LPArray)] + byte[] rawBuf, + long rawLen, + [MarshalAs(UnmanagedType.LPArray)] + byte[] compBuf, + OodleLZ_CompressionLevel level, + IntPtr pOptions, + IntPtr dictionaryBase, + IntPtr lrm, + IntPtr scratchMem, + long scratchSize); + + private static long OodleLZ_Compress(OodleLZ_Compressor compressor, byte[] rawBuf, long rawLen, byte[] compBuf, OodleLZ_CompressionLevel level) + => OodleLZ_Compress(compressor, rawBuf, rawLen, compBuf, level, + IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0); + + + /// = OodleLZ_Compressor_Invalid + /// = OodleLZ_CompressionLevel_Normal + [DllImport("oo2core_6_win64.dll", CallingConvention = CallingConvention.StdCall)] + private static extern IntPtr OodleLZ_CompressOptions_GetDefault( + OodleLZ_Compressor compressor, + OodleLZ_CompressionLevel lzLevel); + + private static IntPtr OodleLZ_CompressOptions_GetDefault() + => OodleLZ_CompressOptions_GetDefault(OodleLZ_Compressor.OodleLZ_Compressor_Invalid, OodleLZ_CompressionLevel.OodleLZ_CompressionLevel_Normal); + + + /// + /// + /// + /// + /// = OodleLZ_FuzzSafe_Yes + /// = OodleLZ_CheckCRC_No + /// = OodleLZ_Verbosity_None + /// = NULL + /// = 0 + /// = NULL + /// = NULL + /// = NULL + /// = 0 + /// = OodleLZ_Decode_Unthreaded + [DllImport("oo2core_6_win64.dll", CallingConvention = CallingConvention.StdCall)] + private static extern long OodleLZ_Decompress( + [MarshalAs(UnmanagedType.LPArray)] + byte[] compBuf, + long compBufSize, + [MarshalAs(UnmanagedType.LPArray)] + byte[] rawBuf, + long rawLen, + OodleLZ_FuzzSafe fuzzSafe, + OodleLZ_CheckCRC checkCRC, + OodleLZ_Verbosity verbosity, + IntPtr decBufBase, + long decBufSize, + IntPtr fpCallback, + IntPtr callbackUserData, + IntPtr decoderMemory, + long decoderMemorySize, + OodleLZ_Decode_ThreadPhase threadPhase); + + private static long OodleLZ_Decompress(byte[] compBuf, long compBufSize, byte[] rawBuf, long rawLen) + => OodleLZ_Decompress(compBuf, compBufSize, rawBuf, rawLen, + OodleLZ_FuzzSafe.OodleLZ_FuzzSafe_Yes, OodleLZ_CheckCRC.OodleLZ_CheckCRC_No, OodleLZ_Verbosity.OodleLZ_Verbosity_None, + IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, OodleLZ_Decode_ThreadPhase.OodleLZ_Decode_Unthreaded); + + + [DllImport("oo2core_6_win64.dll", CallingConvention = CallingConvention.StdCall)] + private static extern long OodleLZ_GetCompressedBufferSizeNeeded( + long rawSize); + + + [DllImport("oo2core_6_win64.dll", CallingConvention = CallingConvention.StdCall)] + private static extern long OodleLZ_GetDecodeBufferSize( + long rawSize, + [MarshalAs(UnmanagedType.Bool)] + bool corruptionPossible); + + + [StructLayout(LayoutKind.Sequential)] + private struct OodleLZ_CompressOptions + { + public uint verbosity; + public int minMatchLen; + [MarshalAs(UnmanagedType.Bool)] + public bool seekChunkReset; + public int seekChunkLen; + public OodleLZ_Profile profile; + public int dictionarySize; + public int spaceSpeedTradeoffBytes; + public int maxHuffmansPerChunk; + [MarshalAs(UnmanagedType.Bool)] + public bool sendQuantumCRCs; + public int maxLocalDictionarySize; + public int makeLongRangeMatcher; + public int matchTableSizeLog2; + } + + + private enum OodleLZ_CheckCRC : int + { + OodleLZ_CheckCRC_No = 0, + OodleLZ_CheckCRC_Yes = 1, + OodleLZ_CheckCRC_Force32 = 0x40000000 + } + + public enum OodleLZ_CompressionLevel : int + { + OodleLZ_CompressionLevel_None = 0, + OodleLZ_CompressionLevel_SuperFast = 1, + OodleLZ_CompressionLevel_VeryFast = 2, + OodleLZ_CompressionLevel_Fast = 3, + OodleLZ_CompressionLevel_Normal = 4, + + OodleLZ_CompressionLevel_Optimal1 = 5, + OodleLZ_CompressionLevel_Optimal2 = 6, + OodleLZ_CompressionLevel_Optimal3 = 7, + OodleLZ_CompressionLevel_Optimal4 = 8, + OodleLZ_CompressionLevel_Optimal5 = 9, + + OodleLZ_CompressionLevel_HyperFast1 = -1, + OodleLZ_CompressionLevel_HyperFast2 = -2, + OodleLZ_CompressionLevel_HyperFast3 = -3, + OodleLZ_CompressionLevel_HyperFast4 = -4, + + OodleLZ_CompressionLevel_HyperFast = OodleLZ_CompressionLevel_HyperFast1, + OodleLZ_CompressionLevel_Optimal = OodleLZ_CompressionLevel_Optimal2, + OodleLZ_CompressionLevel_Max = OodleLZ_CompressionLevel_Optimal5, + OodleLZ_CompressionLevel_Min = OodleLZ_CompressionLevel_HyperFast4, + + OodleLZ_CompressionLevel_Force32 = 0x40000000, + OodleLZ_CompressionLevel_Invalid = OodleLZ_CompressionLevel_Force32 + } + + public enum OodleLZ_Compressor : int + { + OodleLZ_Compressor_Invalid = -1, + OodleLZ_Compressor_None = 3, + + OodleLZ_Compressor_Kraken = 8, + OodleLZ_Compressor_Leviathan = 13, + OodleLZ_Compressor_Mermaid = 9, + OodleLZ_Compressor_Selkie = 11, + OodleLZ_Compressor_Hydra = 12, + + OodleLZ_Compressor_BitKnit = 10, + OodleLZ_Compressor_LZB16 = 4, + OodleLZ_Compressor_LZNA = 7, + OodleLZ_Compressor_LZH = 0, + OodleLZ_Compressor_LZHLW = 1, + OodleLZ_Compressor_LZNIB = 2, + OodleLZ_Compressor_LZBLW = 5, + OodleLZ_Compressor_LZA = 6, + + OodleLZ_Compressor_Count = 14, + OodleLZ_Compressor_Force32 = 0x40000000 + } + + private enum OodleLZ_Decode_ThreadPhase : int + { + OodleLZ_Decode_ThreadPhase1 = 1, + OodleLZ_Decode_ThreadPhase2 = 2, + OodleLZ_Decode_ThreadPhaseAll = 3, + OodleLZ_Decode_Unthreaded = OodleLZ_Decode_ThreadPhaseAll + } + + private enum OodleLZ_FuzzSafe : int + { + OodleLZ_FuzzSafe_No = 0, + OodleLZ_FuzzSafe_Yes = 1 + } + + private enum OodleLZ_Profile : int + { + OodleLZ_Profile_Main = 0, + OodleLZ_Profile_Reduced = 1, + OodleLZ_Profile_Force32 = 0x40000000 + } + + private enum OodleLZ_Verbosity : int + { + OodleLZ_Verbosity_None = 0, + OodleLZ_Verbosity_Minimal = 1, + OodleLZ_Verbosity_Some = 2, + OodleLZ_Verbosity_Lots = 3, + OodleLZ_Verbosity_Force32 = 0x40000000 + } + } +} diff --git a/Switch_Toolbox_Library/Compression/STLibraryCompression.cs b/Switch_Toolbox_Library/Compression/STLibraryCompression.cs index 26b94a78..75fe38b3 100644 --- a/Switch_Toolbox_Library/Compression/STLibraryCompression.cs +++ b/Switch_Toolbox_Library/Compression/STLibraryCompression.cs @@ -712,6 +712,18 @@ namespace Toolbox.Library.IO return LZ4.LZ4Codec.Encode(data, inputOffset, data.Length); } } - } + public class Type_Oodle + { + public static byte[] Decompress(byte[] data, int decompressedSize) + { + return Toolbox.Library.Compression.Oodle.Decompress(data, decompressedSize); + } + + public static byte[] Compress(byte[] source, Compression.Oodle.OodleLZ_Compressor compressor, Compression.Oodle.OodleLZ_CompressionLevel level) + { + return Toolbox.Library.Compression.Oodle.Compress(source, compressor, level); + } + } + } } diff --git a/Switch_Toolbox_Library/Toolbox_Library.csproj b/Switch_Toolbox_Library/Toolbox_Library.csproj index 9977a353..6f67437e 100644 --- a/Switch_Toolbox_Library/Toolbox_Library.csproj +++ b/Switch_Toolbox_Library/Toolbox_Library.csproj @@ -248,6 +248,7 @@ + From 205c8d7ba228bb247b9ae670bbffadc0575adb2c Mon Sep 17 00:00:00 2001 From: Rei Date: Mon, 14 Feb 2022 18:18:02 -0500 Subject: [PATCH 2/3] Rewrite pokemon string gen code; Add some PLA strings (#455) --- .../FileFormats/Hashes/GFPAKHashCache.cs | 66 ++++-- File_Format_Library/Resources/Hashes/Pkmn.txt | 215 ++++++++++-------- 2 files changed, 167 insertions(+), 114 deletions(-) diff --git a/File_Format_Library/FileFormats/Hashes/GFPAKHashCache.cs b/File_Format_Library/FileFormats/Hashes/GFPAKHashCache.cs index 6e6da071..fe28b6a9 100644 --- a/File_Format_Library/FileFormats/Hashes/GFPAKHashCache.cs +++ b/File_Format_Library/FileFormats/Hashes/GFPAKHashCache.cs @@ -83,33 +83,61 @@ namespace FirstPlugin.FileFormats.Hashes PutHash(HashString); - if (HashString.Contains("pm0000") || - HashString.Contains("poke_XXXX") || - HashString.Contains("poke_ball_0000") || - HashString.Contains("poke_face_0000") || - HashString.Contains("poke_motion_0000")) + //Mon nums + if (HashString.Contains("XXXX")) { - GenerateGenericPokeStrings(HashString); + GeneratePkmnString(HashString); PokeHashTemplates.Add(HashString); } } } - private static void GenerateGenericPokeStrings(string hashStr) + private static void GeneratePkmnString(string hashStr) { - for (int i = 0; i < 1000; i++) - { - string pokeStr = string.Empty; - if (hashStr.Contains("pm0000")) pokeStr = hashStr.Replace("pm0000", $"pm{i.ToString("D4")}"); - else if (hashStr.Contains("poke_XXXX")) pokeStr = hashStr.Replace("poke_XXXX", $"poke_{i.ToString("D4")}"); - else if (hashStr.Contains("poke_ball_0000")) pokeStr = hashStr.Replace("poke_ball_0000", $"poke_ball_{i.ToString("D4")}"); - else if (hashStr.Contains("poke_face_0000")) pokeStr = hashStr.Replace("poke_face_0000", $"poke_face_{i.ToString("D4")}"); - else if (hashStr.Contains("poke_motion_0000")) pokeStr = hashStr.Replace("poke_motion_0000", $"poke_motion_{i.ToString("D4")}"); - ulong hash = FNV64A1.Calculate(pokeStr); - if (!HashCacheContent.ContainsKey(hash)) - HashCacheContent.Add(hash, pokeStr); - } + int[] alolanMons = { + 37, 38 + }; + int[] husuiMons = { + 58, 59, 100, 101, 157, 211, 215, 503, 549, 550, + 570, 571, 628, 751, 764, 765, 843, 1003, 1005, 1006 + }; + + int[] frenzyForms = { + 59, 101, 549, 751, 1002 + }; + + string pokeStr = string.Empty; + List monNames; + for (int i = 0; i < 1010; i++) + { + monNames = new List(); + //Gen species num + pokeStr = hashStr.Replace("XXXX", i.ToString("D4")); + + //..also sub out alt forms + if (frenzyForms.Contains(i)) + monNames.Add(pokeStr.Replace("YY", "71")); + + monNames.Add(pokeStr.Replace("YY", "00")); + + //..also sub out region forms + foreach (var n in monNames) { + if (alolanMons.Contains(i)) + TryAddHash(n.Replace("ZZ", "11")); + else if (husuiMons.Contains(i)) + TryAddHash(n.Replace("ZZ", "41")); + else + TryAddHash(n.Replace("ZZ", "00")); + } + monNames.Clear(); + } + } + + private static void TryAddHash(string str) { + ulong hash = FNV64A1.Calculate(str); + if (!HashCacheContent.ContainsKey(hash)) + HashCacheContent.Add(hash, str); } public static void GeneratePokeStringsFromFile(string FileName) diff --git a/File_Format_Library/Resources/Hashes/Pkmn.txt b/File_Format_Library/Resources/Hashes/Pkmn.txt index b681424a..417ddf3b 100644 --- a/File_Format_Library/Resources/Hashes/Pkmn.txt +++ b/File_Format_Library/Resources/Hashes/Pkmn.txt @@ -1,110 +1,110 @@ pc0002_00_fa0004_eye_close01.gfbanm pc0002_00_fi0001_wait01_loop.gfbanm -bin/pokemon/pm0000_00/ -bin/pokemon/pm0000_00/tex/ -bin/pokemon/pm0000_00/anm/ -bin/pokemon/pm0000_00/mdl/ +bin/pokemon/pmXXXX_00/ +bin/pokemon/pmXXXX_00/tex/ +bin/pokemon/pmXXXX_00/anm/ +bin/pokemon/pmXXXX_00/mdl/ bin/pokemon_data/ bin/graphics/mask_texture/pattern_01/ bin/app/pokecamp/cooking/common_model/anm/ bin/app/pokecamp/cooking/common_model/mdl/ bin/app/pokecamp/cooking/common_model/ bin/chara/data/pc/p2/p1_base_app01/anm/ -pm0000_00.gfbpokecfg -pm0000_00.gfbmdl -pm0000_00_rare.gfbmdl -pm0000_00_field01.gfbanmcfg -pm0000_00_field.gfbanmcfg -pm0000_00_battle.gfbanmcfg -pm0000_00_capture.gfbanmcfg -pm0000_00_battle01.gfbanmcfg -pm0000_00_capture01.gfbanmcfg -pm0000_00_camp.gfbanmcfg -pm0000_00_app01.gfbanmcfg -pm0000_00_loop01.gfbanm -pm0000_00_loop02.gfbanm -pm0000_00_gloop01.gfbanm -pm0000_00_mouth01.gfbanm -pm0000_00_eye01.gfbanm -pm0000_00_ba01_land01.gfbanm -pm0000_00_ba01_landA01.gfbanm -pm0000_00_ba01_landB01.gfbanm -pm0000_00_ba01_landC01.gfbanm -pm0000_00_ba02_roar01.gfbanm -pm0000_00_ba10_waitA01.gfbanm -pm0000_00_ba10_waitA02.gfbanm -pm0000_00_ba10_waitB01.gfbanm -pm0000_00_ba10_waitB02.gfbanm -pm0000_00_ba10_waitC01.gfbanm -pm0000_00_ba10_waitC02.gfbanm -pm0000_00_ba20_buturi01.gfbanm -pm0000_00_ba20_buturi02.gfbanm -pm0000_00_ba20_buturi03.gfbanm -pm0000_00_ba21_tokusyu01.gfbanm -pm0000_00_ba21_tokusyu02.gfbanm -pm0000_00_ba21_tokusyu03.gfbanm -pm0000_00_ba30_damageS01.gfbanm -pm0000_00_ba41_down01.gfbanm -pm0000_00_ba50_wideuse01.gfbanm -pm0000_00_ba50_wideuse02.gfbanm -pm0000_00_ba50_wideuse03.gfbanm -pm0000_00_cm10_bawait_fiwait01.gfbanm -pm0000_00_cm10_bawait_kwwait01.gfbanm -pm0000_00_cm10_fiwait_bawait01.gfbanm -pm0000_00_cm10_fiwait_kwwait01.gfbanm -pm0000_00_cm10_kwwait_bawait01.gfbanm -pm0000_00_cm10_kwwait_fiwait01.gfbanm -pm0000_00_fi01_wait01.gfbanm -pm0000_00_fi01_wait02.gfbanm -pm0000_00_fi20_walk01.gfbanm -pm0000_00_fi21_run01.gfbanm -pm0000_00_fi30_wait_walk01.gfbanm -pm0000_00_fi30_walk_wait01.gfbanm -pm0000_00_fi31_run_wait01.gfbanm -pm0000_00_fi31_wait_run01.gfbanm -pm0000_00_fi32_run_walk01.gfbanm -pm0000_00_fi32_walk_run01.gfbanm -pm0000_00_fi50_conerwait01_start.gfbanm -pm0000_00_fi51_conerwait01_loop.gfbanm -pm0000_00_fi52_conerwait01_end.gfbanm -pm0000_00_fi70_threeselect01.gfbanm -pm0000_00_kw01_wait01.gfbanm -pm0000_00_kw10_respond01.gfbanm -pm0000_00_kw11_turnA01.gfbanm -pm0000_00_kw11_turnB01.gfbanm -pm0000_00_kw11_turnC01.gfbanm -pm0000_00_kw20_drowseA01.gfbanm -pm0000_00_kw20_drowseB01.gfbanm -pm0000_00_kw20_drowseC01.gfbanm -pm0000_00_kw21_sleepA01.gfbanm -pm0000_00_kw21_sleepB01.gfbanm -pm0000_00_kw21_sleepC01.gfbanm -pm0000_00_kw30_hate01.gfbanm -pm0000_00_kw30_hate02.gfbanm -pm0000_00_kw31_question01.gfbanm -pm0000_00_kw32_happyA01.gfbanm -pm0000_00_kw32_happyB01.gfbanm -pm0000_00_kw32_happyC01.gfbanm -pm0000_00_kw33_moveA01.gfbanm -pm0000_00_kw33_moveB01.gfbanm -pm0000_00_kw33_moveC01.gfbanm -pm0000_00_kw33_moveD01.gfbanm -pm0000_00_kw34_lonely01.gfbanm -pm0000_00_kw35_playA01.gfbanm -pm0000_00_kw35_playB01.gfbanm -pm0000_00_kw35_playC01.gfbanm -pm0000_00_kw36_mad01.gfbanm -pm0000_00_kw50_eatA01.gfbanm -pm0000_00_kw50_eatB01.gfbanm -pm0000_00_kw50_eatC01.gfbanm -pm0000_00_kw60_touch01.gfbanm +pmXXXX_00.gfbpokecfg +pmXXXX_00.gfbmdl +pmXXXX_00_rare.gfbmdl +pmXXXX_00_field01.gfbanmcfg +pmXXXX_00_field.gfbanmcfg +pmXXXX_00_battle.gfbanmcfg +pmXXXX_00_capture.gfbanmcfg +pmXXXX_00_battle01.gfbanmcfg +pmXXXX_00_capture01.gfbanmcfg +pmXXXX_00_camp.gfbanmcfg +pmXXXX_00_app01.gfbanmcfg +pmXXXX_00_loop01.gfbanm +pmXXXX_00_loop02.gfbanm +pmXXXX_00_gloop01.gfbanm +pmXXXX_00_mouth01.gfbanm +pmXXXX_00_eye01.gfbanm +pmXXXX_00_ba01_land01.gfbanm +pmXXXX_00_ba01_landA01.gfbanm +pmXXXX_00_ba01_landB01.gfbanm +pmXXXX_00_ba01_landC01.gfbanm +pmXXXX_00_ba02_roar01.gfbanm +pmXXXX_00_ba10_waitA01.gfbanm +pmXXXX_00_ba10_waitA02.gfbanm +pmXXXX_00_ba10_waitB01.gfbanm +pmXXXX_00_ba10_waitB02.gfbanm +pmXXXX_00_ba10_waitC01.gfbanm +pmXXXX_00_ba10_waitC02.gfbanm +pmXXXX_00_ba20_buturi01.gfbanm +pmXXXX_00_ba20_buturi02.gfbanm +pmXXXX_00_ba20_buturi03.gfbanm +pmXXXX_00_ba21_tokusyu01.gfbanm +pmXXXX_00_ba21_tokusyu02.gfbanm +pmXXXX_00_ba21_tokusyu03.gfbanm +pmXXXX_00_ba30_damageS01.gfbanm +pmXXXX_00_ba41_down01.gfbanm +pmXXXX_00_ba50_wideuse01.gfbanm +pmXXXX_00_ba50_wideuse02.gfbanm +pmXXXX_00_ba50_wideuse03.gfbanm +pmXXXX_00_cm10_bawait_fiwait01.gfbanm +pmXXXX_00_cm10_bawait_kwwait01.gfbanm +pmXXXX_00_cm10_fiwait_bawait01.gfbanm +pmXXXX_00_cm10_fiwait_kwwait01.gfbanm +pmXXXX_00_cm10_kwwait_bawait01.gfbanm +pmXXXX_00_cm10_kwwait_fiwait01.gfbanm +pmXXXX_00_fi01_wait01.gfbanm +pmXXXX_00_fi01_wait02.gfbanm +pmXXXX_00_fi20_walk01.gfbanm +pmXXXX_00_fi21_run01.gfbanm +pmXXXX_00_fi30_wait_walk01.gfbanm +pmXXXX_00_fi30_walk_wait01.gfbanm +pmXXXX_00_fi31_run_wait01.gfbanm +pmXXXX_00_fi31_wait_run01.gfbanm +pmXXXX_00_fi32_run_walk01.gfbanm +pmXXXX_00_fi32_walk_run01.gfbanm +pmXXXX_00_fi50_conerwait01_start.gfbanm +pmXXXX_00_fi51_conerwait01_loop.gfbanm +pmXXXX_00_fi52_conerwait01_end.gfbanm +pmXXXX_00_fi70_threeselect01.gfbanm +pmXXXX_00_kw01_wait01.gfbanm +pmXXXX_00_kw10_respond01.gfbanm +pmXXXX_00_kw11_turnA01.gfbanm +pmXXXX_00_kw11_turnB01.gfbanm +pmXXXX_00_kw11_turnC01.gfbanm +pmXXXX_00_kw20_drowseA01.gfbanm +pmXXXX_00_kw20_drowseB01.gfbanm +pmXXXX_00_kw20_drowseC01.gfbanm +pmXXXX_00_kw21_sleepA01.gfbanm +pmXXXX_00_kw21_sleepB01.gfbanm +pmXXXX_00_kw21_sleepC01.gfbanm +pmXXXX_00_kw30_hate01.gfbanm +pmXXXX_00_kw30_hate02.gfbanm +pmXXXX_00_kw31_question01.gfbanm +pmXXXX_00_kw32_happyA01.gfbanm +pmXXXX_00_kw32_happyB01.gfbanm +pmXXXX_00_kw32_happyC01.gfbanm +pmXXXX_00_kw33_moveA01.gfbanm +pmXXXX_00_kw33_moveB01.gfbanm +pmXXXX_00_kw33_moveC01.gfbanm +pmXXXX_00_kw33_moveD01.gfbanm +pmXXXX_00_kw34_lonely01.gfbanm +pmXXXX_00_kw35_playA01.gfbanm +pmXXXX_00_kw35_playB01.gfbanm +pmXXXX_00_kw35_playC01.gfbanm +pmXXXX_00_kw36_mad01.gfbanm +pmXXXX_00_kw50_eatA01.gfbanm +pmXXXX_00_kw50_eatB01.gfbanm +pmXXXX_00_kw50_eatC01.gfbanm +pmXXXX_00_kw60_touch01.gfbanm bin/chara/data/pc/p1/anm bin/chara/data/pc/p1/mdl bin/archive/chara/data/pc/p1/anm bin/archive/chara/data/pc/p1/mdl -bin/pokemon/pm0000_00/g_shader/ -pm0000_00.gfbgpokecfg +bin/pokemon/pmXXXX_00/g_shader/ +pmXXXX_00.gfbgpokecfg eg_cmn_cloud01.gfbanm eg_cmn_cloud01.gfbanmcfg eg_cmn_cloud01.gfbmdl @@ -4438,4 +4438,29 @@ ob0003_30_ba0006_luminous06.gfbanm ob0003_30_ba0007_luminous07.gfbanm ob0003_30_ba0008_luminous08.gfbanm ob0023_00_fi0002_shine01.gfbanm -ob0023_00_fi0001_wait01_loop.gfbanm \ No newline at end of file +ob0023_00_fi0001_wait01_loop.gfbanm +bin/pokemon/pmXXXX/pmXXXX_YY_ZZ/ +bin/pokemon/pmXXXX/pmXXXX_YY_ZZ/anm/ +bin/pokemon/pmXXXX/pmXXXX_YY_ZZ/mdl/ +bin/pokemon/pmXXXX/pmXXXX_YY_ZZ/tex/ +bin/pokemon/pmXXXX/pmXXXX_YY_ZZ/locators/ +pmXXXX_YY_ZZ.trpokecfg +pmXXXX_YY_ZZ.trmdl +pmXXXX_YY_ZZ.trmtr +pmXXXX_YY_ZZ.trmsh +pmXXXX_YY_ZZ.trmbf +pmXXXX_YY_ZZ.trmmt +pmXXXX_YY_ZZ.trskl +pmXXXX_YY_ZZ_eff.trskl +pmXXXX_YY_ZZ_rare.trmtr +pmXXXX_YY_ZZ_lod1.trmbf +pmXXXX_YY_ZZ_lod1.trmsh +pmXXXX_YY_ZZ_lod2.trmbf +pmXXXX_YY_ZZ_lod2.trmsh +pmXXXX_YY_ZZ_base.tracn +pmXXXX_YY_ZZ_base.tracp +pmXXXX_YY_ZZ_base.tracr +pmXXXX_YY_ZZ_base.tracs +pmXXXX_YY_ZZ_base.tracl +pmXXXX_YY_ZZ_base.tralk +pmXXXX_YY_ZZ_base.trbik \ No newline at end of file From f6e3da84739c23e7dee4f9c1aceb5a4d9d7a7483 Mon Sep 17 00:00:00 2001 From: MichaelHinrichs <37460517+MichaelHinrichs@users.noreply.github.com> Date: Mon, 14 Feb 2022 17:18:29 -0600 Subject: [PATCH 3/3] Fix file names with slashes (#450) In Luigi's Manson 3, some of the archived models have slashes in their names. This means that they can't be exported with those names, and Toolbox will crash when it reaches them, if you try to "export all". What i have done to fix this, is make toolbox treat names with slashes as directory paths, with a file name on the end. --- File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs b/File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs index 365cff8a..32aa0727 100644 --- a/File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs +++ b/File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; @@ -63,7 +64,9 @@ namespace FirstPlugin.LuigisMansion3 settings.SuppressConfirmDialog = true; - DAE.Export($"{folderPath}/{mdl.Text}.dae", settings, model, new List()); + if (mdl.Text.Contains("/")) + Directory.CreateDirectory($"{folderPath}/{Path.GetDirectoryName(mdl.Text)}"); + DAE.Export($"{folderPath}/{mdl.Text.Replace("/", "//")}.dae", settings, model, new List()); } System.Windows.Forms.MessageBox.Show($"Exported models Successfuly!");