From cf3ef8565121fb128be7a1d18de33965194bd667 Mon Sep 17 00:00:00 2001 From: namsku Date: Mon, 18 Nov 2024 18:33:53 +0100 Subject: [PATCH 1/4] Improving stability for RE2R Non RT --- RszTool/RszFile/PfbFile.cs | 12 +++++++++++- RszTool/RszFile/RSZFile.cs | 12 ------------ RszTool/RszFile/ScnFile.cs | 12 +++++++++++- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/RszTool/RszFile/PfbFile.cs b/RszTool/RszFile/PfbFile.cs index 4fa6abc..18151cc 100644 --- a/RszTool/RszFile/PfbFile.cs +++ b/RszTool/RszFile/PfbFile.cs @@ -113,7 +113,17 @@ public GameObjectData? Parent set => parentRef = value != null ? new(value) : null; } - public string? Name => (Instance?.GetFieldValue("v0") ?? Instance?.GetFieldValue("Name")) as string; + public string? Name + { + get => (Instance?.GetFieldValue("v0") ?? Instance?.GetFieldValue("Name")) as string; + set + { + if (Instance != null && value != null) + { + Instance?.SetFieldValue("Name", value); + } + } + } public int? ObjectId => Info?.Data.objectId; diff --git a/RszTool/RszFile/RSZFile.cs b/RszTool/RszFile/RSZFile.cs index b3825e2..e4e673c 100644 --- a/RszTool/RszFile/RSZFile.cs +++ b/RszTool/RszFile/RSZFile.cs @@ -343,12 +343,6 @@ public void InstanceUnflatten(RszInstance instance) { if (items[j] is int instanceId) { - if (instanceId >= instance.Index && field.IsTypeInferred) - { - // TODO: may detect error, should roll back - field.type = RszFieldType.S32; - throw new RszRetryOpenException($"Detected {instance.RszClass.name}.{field.name} as Object before, but seems wrong"); - } items[j] = InstanceList[instanceId]; InstanceUnflatten(InstanceList[instanceId]); } @@ -356,12 +350,6 @@ public void InstanceUnflatten(RszInstance instance) } else if (instance.Values[i] is int instanceId) { - if (instanceId >= instance.Index && field.IsTypeInferred) - { - // TODO: may detect error, should roll back - field.type = RszFieldType.S32; - throw new RszRetryOpenException($"Detected {instance.RszClass.name}.{field.name} as Object before, but seems wrong"); - } instance.Values[i] = InstanceList[instanceId]; InstanceUnflatten(InstanceList[instanceId]); } diff --git a/RszTool/RszFile/ScnFile.cs b/RszTool/RszFile/ScnFile.cs index 500a744..05c3302 100644 --- a/RszTool/RszFile/ScnFile.cs +++ b/RszTool/RszFile/ScnFile.cs @@ -167,7 +167,17 @@ public GameObjectData? Parent set => parentRef = value != null ? new(value) : null; } - public string? Name => (Instance?.GetFieldValue("v0") ?? Instance?.GetFieldValue("Name")) as string; + public string? Name + { + get => (Instance?.GetFieldValue("v0") ?? Instance?.GetFieldValue("Name")) as string; + set + { + if (Instance != null && value != null) + { + Instance?.SetFieldValue("Name", value); + } + } + } public int? ObjectId => Info?.Data.objectId; From 07d031787486d921de25112c68494f6cdf17562b Mon Sep 17 00:00:00 2001 From: namsku Date: Thu, 21 Nov 2024 21:20:32 +0100 Subject: [PATCH 2/4] Fix Console Verbose, Prefab Missing, Read Rsz error --- RszTool.App/Patches/OpenFolderDialog.cs | 464 ++++++++++++++++++ RszTool.App/Themes/CommonTheme.xaml | 43 ++ RszTool.App/Themes/Controls/ComboBox.xaml | 139 ++++++ RszTool.App/Themes/Controls/MenuItem.xaml | 298 +++++++++++ .../ViewModels/BaseRszFileViewModel.cs | 2 +- .../ViewModels/FileExplorerViewModel.cs | 168 +++++++ RszTool.App/ViewModels/RszTestViewModel.cs | 4 +- RszTool.App/ViewModels/ThemeManager.cs | 57 +++ RszTool.App/Views/FileExplorerTree.xaml | 157 ++++++ RszTool.App/Views/FileExplorerTree.xaml.cs | 39 ++ RszTool.App/Views/TreeViewTemplate.xaml | 119 +++++ 11 files changed, 1487 insertions(+), 3 deletions(-) create mode 100644 RszTool.App/Patches/OpenFolderDialog.cs create mode 100644 RszTool.App/Themes/CommonTheme.xaml create mode 100644 RszTool.App/Themes/Controls/ComboBox.xaml create mode 100644 RszTool.App/Themes/Controls/MenuItem.xaml create mode 100644 RszTool.App/ViewModels/FileExplorerViewModel.cs create mode 100644 RszTool.App/ViewModels/ThemeManager.cs create mode 100644 RszTool.App/Views/FileExplorerTree.xaml create mode 100644 RszTool.App/Views/FileExplorerTree.xaml.cs create mode 100644 RszTool.App/Views/TreeViewTemplate.xaml diff --git a/RszTool.App/Patches/OpenFolderDialog.cs b/RszTool.App/Patches/OpenFolderDialog.cs new file mode 100644 index 0000000..9783fac --- /dev/null +++ b/RszTool.App/Patches/OpenFolderDialog.cs @@ -0,0 +1,464 @@ +#if !NET5_0_OR_GREATER + +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Interop; + +namespace Microsoft.Win32; + +public class OpenFolderDialog +{ + public bool ShowDialog() + { + var hwndOwner = NativeMethods.GetActiveWindow(); + var dialog = (IFileOpenDialog)new FileOpenDialog(); + Configure(dialog); + + var hr = dialog.Show(hwndOwner); + if (hr == NativeMethods.ERROR_CANCELLED) + return false; + + if (hr != NativeMethods.S_OK) + return false; + + dialog.GetResult(out var item); + item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var path); + FolderName = path; + return true; + } + + public string? Title { get; set; } + public string? OkButtonLabel { get; set; } + public string? InitialDirectory { get; set; } + public string? FolderName { get; set; } + public bool ChangeCurrentDirectory { get; set; } + + private void Configure(IFileOpenDialog dialog) + { + dialog.SetOptions(CreateOptions()); + + if (InitialDirectory != null && !string.IsNullOrEmpty(InitialDirectory)) + { + var result = NativeMethods.SHCreateItemFromParsingName(InitialDirectory, IntPtr.Zero, typeof(IShellItem).GUID, out var item); + switch (result) + { + case NativeMethods.S_OK: + if (item is not null) + { + dialog.SetFolder(item); + } + break; + case NativeMethods.FILE_NOT_FOUND: + break; + default: + throw new Win32Exception(result); + } + } + + if (Title is not null) + { + dialog.SetTitle(Title); + } + + if (OkButtonLabel is not null) + { + dialog.SetOkButtonLabel(OkButtonLabel); + } + } + + private FOS CreateOptions() + { + var result = FOS.FOS_FORCEFILESYSTEM | FOS.FOS_PICKFOLDERS; + if (!ChangeCurrentDirectory) + { + result |= FOS.FOS_NOCHANGEDIR; + } + + return result; + } +} + +internal static class NativeMethods +{ +#pragma warning disable IDE1006 // Naming Styles + internal const int S_OK = 0x00000000; + internal const int ERROR_CANCELLED = unchecked((int)0x800704C7); + internal const int FILE_NOT_FOUND = unchecked((int)0x80070002); +#pragma warning restore IDE1006 // Naming Styles + + [DllImport("user32")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr GetActiveWindow(); + + [DllImport("shell32")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv); +} + + +internal enum SIGDN : uint +{ + SIGDN_NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL + SIGDN_PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING + SIGDN_PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + SIGDN_FILESYSPATH = 0x80058000, // SHGDN_FORPARSING + SIGDN_URL = 0x80068000, // SHGDN_FORPARSING + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + SIGDN_PARENTRELATIVE = 0x80080001, // SHGDN_INFOLDER +} + + +internal enum FDE_SHAREVIOLATION_RESPONSE +{ + FDESVR_DEFAULT = 0x00000000, + FDESVR_ACCEPT = 0x00000001, + FDESVR_REFUSE = 0x00000002, +} + + +internal enum FDE_OVERWRITE_RESPONSE +{ + FDEOR_DEFAULT = 0x00000000, + FDEOR_ACCEPT = 0x00000001, + FDEOR_REFUSE = 0x00000002, +} + + + +internal static class IIDGuid +{ + // IID GUID strings for relevant COM interfaces + internal const string IModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802"; + internal const string IFileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8"; + internal const string IFileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960"; + internal const string IFileSaveDialog = "84bccd23-5fde-4cdb-aea4-af64b83d78ab"; + internal const string IFileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; + internal const string IShellItem = "43826D1E-E718-42EE-BC55-A1E261C37BFE"; + internal const string IShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; +} + + +internal static class CLSIDGuid +{ + internal const string FileOpenDialog = "DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7"; + internal const string FileSaveDialog = "C0B4E2F3-BA21-4773-8DBA-335EC946EB8B"; +} + + +[ComImport, +Guid(IIDGuid.IShellItem), +InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IShellItem +{ + void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv); + + void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + void GetDisplayName([In] SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); + + void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs); + + void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); +} + + +[Flags] +internal enum FOS : uint +{ + /// + /// When saving a file, prompt before overwriting an existing file of the same name. This is a default value for the Save dialog. + /// + FOS_OVERWRITEPROMPT = 0x00000002, + + /// + /// In the Save dialog, only allow the user to choose a file that has one of the file name extensions specified through IFileDialog::SetFileTypes. + /// + FOS_STRICTFILETYPES = 0x00000004, + + /// + /// Don't change the current working directory. + /// + FOS_NOCHANGEDIR = 0x00000008, + + /// + /// Present an Open dialog that offers a choice of folders rather than files. + /// + FOS_PICKFOLDERS = 0x00000020, + + /// + /// Ensures that returned items are file system items (SFGAO_FILESYSTEM). Note that this does not apply to items returned by IFileDialog::GetCurrentSelection. + /// + FOS_FORCEFILESYSTEM = 0x00000040, + + /// + /// Enables the user to choose any item in the Shell namespace, not just those with SFGAO_STREAM or SFAGO_FILESYSTEM attributes. This flag cannot be combined with FOS_FORCEFILESYSTEM. + /// + FOS_ALLNONSTORAGEITEMS = 0x00000080, + + /// + /// Do not check for situations that would prevent an application from opening the selected file, such as sharing violations or access denied errors. + /// + FOS_NOVALIDATE = 0x00000100, + + /// + /// Enables the user to select multiple items in the open dialog. Note that when this flag is set, the IFileOpenDialog interface must be used to retrieve those items. + /// + FOS_ALLOWMULTISELECT = 0x00000200, + + /// + /// The item returned must be in an existing folder. This is a default value. + /// + FOS_PATHMUSTEXIST = 0x00000800, + + /// + /// The item returned must exist. This is a default value for the Open dialog. + /// + FOS_FILEMUSTEXIST = 0x00001000, + + /// + /// Prompt for creation if the item returned in the save dialog does not exist. Note that this does not actually create the item. + /// + FOS_CREATEPROMPT = 0x00002000, + + /// + /// In the case of a sharing violation when an application is opening a file, call the application back through OnShareViolation for guidance. This flag is overridden by FOS_NOVALIDATE. + /// + FOS_SHAREAWARE = 0x00004000, + + /// + /// Do not return read-only items. This is a default value for the Save dialog. + /// + FOS_NOREADONLYRETURN = 0x00008000, + + /// + /// Do not test whether creation of the item as specified in the Save dialog will be successful. If this flag is not set, the calling application must handle errors, such as denial of access, discovered when the item is created. + /// + FOS_NOTESTFILECREATE = 0x00010000, + + /// + /// Hide the list of places from which the user has recently opened or saved items. This value is not supported as of Windows 7. + /// + FOS_HIDEMRUPLACES = 0x00020000, + + /// + /// Hide items shown by default in the view's navigation pane. This flag is often used in conjunction with the IFileDialog::AddPlace method, to hide standard locations and replace them with custom locations. + /// + FOS_HIDEPINNEDPLACES = 0x00040000, + + /// + /// Shortcuts should not be treated as their target items. This allows an application to open a .lnk file rather than what that file is a shortcut to. + /// + FOS_NODEREFERENCELINKS = 0x00100000, + + /// + /// Do not add the item being opened or saved to the recent documents list (SHAddToRecentDocs). + /// + FOS_DONTADDTORECENT = 0x02000000, + + /// + /// Include hidden and system items. + /// + FOS_FORCESHOWHIDDEN = 0x10000000, + + /// + /// Indicates to the Save As dialog box that it should open in expanded mode. Expanded mode is the mode that is set and unset by clicking the button in the lower-left corner of the Save As dialog box that switches between Browse Folders and Hide Folders when clicked. This value is not supported as of Windows 7. + /// + FOS_DEFAULTNOMINIMODE = 0x20000000, + + /// + /// Indicates to the Open dialog box that the preview pane should always be displayed. + /// + FOS_FORCEPREVIEWPANEON = 0x40000000, + + /// + /// Indicates that the caller is opening a file as a stream (BHID_Stream), so there is no need to download that file. + /// + FOS_SUPPORTSTREAMABLEITEMS = 0x80000000, +} + + +[ComImport] +[ClassInterface(ClassInterfaceType.None)] +[Guid(CLSIDGuid.FileOpenDialog)] +internal class FileOpenDialog +{ +} + + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] +internal struct COMDLG_FILTERSPEC +{ + [MarshalAs(UnmanagedType.LPWStr)] + public string? PszName; + + [MarshalAs(UnmanagedType.LPWStr)] + public string? PszSpec; +} + + +/* [ComImport()] +[Guid(IIDGuid.IFileDialog)] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileDialog +{ + [PreserveSig] + int Show([In] IntPtr parent); + + void SetFileTypes([In] uint cFileTypes, [In][MarshalAs(UnmanagedType.LPArray)] COMDLG_FILTERSPEC[] rgFilterSpec); + + void SetFileTypeIndex([In] uint iFileType); + + void GetFileTypeIndex(out uint piFileType); + + void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie); + + void Unadvise([In] uint dwCookie); + + void SetOptions([In] FOS fos); + + void GetOptions(out FOS pfos); + + void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + + void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + + void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); + + void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); + + void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + + void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); + + void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + + void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, int alignment); + + void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + + void Close([MarshalAs(UnmanagedType.Error)] int hr); + + void SetClientGuid([In] ref Guid guid); + + void ClearClientData(); + + void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); +} */ + + +[ComImport()] +[Guid(IIDGuid.IFileOpenDialog)] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileOpenDialog +{ + [PreserveSig] + int Show([In] IntPtr parent); + + void SetFileTypes([In] uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); + void SetFileTypeIndex([In] uint iFileType); + void GetFileTypeIndex(out uint piFileType); + // void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie); + void Advise(); // incomplete signature + void Unadvise([In] uint dwCookie); + void SetOptions([In] FOS fos); + void GetOptions(out FOS pfos); + void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); + void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); + void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); + void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + // void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, FileDialogCustomPlace fdcp); + void AddPlace(); // incomplete signature + void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + void Close([MarshalAs(UnmanagedType.Error)] int hr); + void SetClientGuid([In] ref Guid guid); + void ClearClientData(); + void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); + // void GetResults([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppenum); + void GetResults([MarshalAs(UnmanagedType.Interface)] out object ppenum); + // void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppsai); + void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out object ppsai); +} + + +/* +[ComImport, +Guid(IIDGuid.IFileDialogEvents), +InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileDialogEvents +{ + // NOTE: some of these callbacks are cancelable - returning S_FALSE means that + // the dialog should not proceed (e.g. with closing, changing folder); to + // support this, we need to use the PreserveSig attribute to enable us to return + // the proper HRESULT + [PreserveSig] + int OnFileOk([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [PreserveSig] + int OnFolderChanging([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psiFolder); + + void OnFolderChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + void OnSelectionChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + void OnShareViolation([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, out FDE_SHAREVIOLATION_RESPONSE pResponse); + + void OnTypeChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + void OnOverwrite([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, out FDE_OVERWRITE_RESPONSE pResponse); +} + + + +[ComImport] +[Guid(IIDGuid.IShellItemArray)] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IShellItemArray +{ + // Not supported: IBindCtx + + void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, out IntPtr ppvOut); + + void GetPropertyStore([In] int flags, [In] ref Guid riid, out IntPtr ppv); + + void GetPropertyDescriptionList([In] ref PROPERTYKEY keyType, [In] ref Guid riid, out IntPtr ppv); + + void GetAttributes([In] SIATTRIBFLAGS dwAttribFlags, [In] uint sfgaoMask, out uint psfgaoAttribs); + + void GetCount(out uint pdwNumItems); + + void GetItemAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems); +} + +[StructLayout(LayoutKind.Sequential, Pack = 4)] +internal struct PROPERTYKEY +{ + public Guid Fmtid; + public uint Pid; +} + +internal enum SIATTRIBFLAGS +{ + SIATTRIBFLAGS_AND = 0x00000001, // if multiple items and the attributes together. + SIATTRIBFLAGS_OR = 0x00000002, // if multiple items or the attributes together. + SIATTRIBFLAGS_APPCOMPAT = 0x00000003, // Call GetAttributes directly on the ShellFolder for multiple attributes +} */ + +#endif diff --git a/RszTool.App/Themes/CommonTheme.xaml b/RszTool.App/Themes/CommonTheme.xaml new file mode 100644 index 0000000..b9b1825 --- /dev/null +++ b/RszTool.App/Themes/CommonTheme.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RszTool.App/Themes/Controls/ComboBox.xaml b/RszTool.App/Themes/Controls/ComboBox.xaml new file mode 100644 index 0000000..42d80fd --- /dev/null +++ b/RszTool.App/Themes/Controls/ComboBox.xaml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RszTool.App/Themes/Controls/MenuItem.xaml b/RszTool.App/Themes/Controls/MenuItem.xaml new file mode 100644 index 0000000..924b1f1 --- /dev/null +++ b/RszTool.App/Themes/Controls/MenuItem.xaml @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + M 0,0 L 3.5,4 L 7,0 Z + M 0,4 L 3.5,0 L 7,4 Z + M 0,0 L 4,3.5 L 0,7 Z + F1 M 10.0,1.2 L 4.7,9.1 L 4.5,9.1 L 0,5.2 L 1.3,3.5 L 4.3,6.1L 8.3,0 L 10.0,1.2 Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RszTool.App/ViewModels/BaseRszFileViewModel.cs b/RszTool.App/ViewModels/BaseRszFileViewModel.cs index b644b3a..8cfddd8 100644 --- a/RszTool.App/ViewModels/BaseRszFileViewModel.cs +++ b/RszTool.App/ViewModels/BaseRszFileViewModel.cs @@ -213,7 +213,7 @@ private static void OnArrayItemCopy(object arg) if (arg is RszFieldArrayInstanceItemViewModel item) { CopiedInstance = item.Instance; - Console.WriteLine(CopiedInstance?.Stringify()); + // Console.WriteLine(CopiedInstance?.Stringify()); } else if (arg is RszFieldArrayNormalItemViewModel normalItem) { diff --git a/RszTool.App/ViewModels/FileExplorerViewModel.cs b/RszTool.App/ViewModels/FileExplorerViewModel.cs new file mode 100644 index 0000000..b988bb2 --- /dev/null +++ b/RszTool.App/ViewModels/FileExplorerViewModel.cs @@ -0,0 +1,168 @@ +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.IO; +using RszTool.App.Common; + +namespace RszTool.App.ViewModels +{ + public class FileExplorerViewModel + { + public ObservableCollection Folders { get; } = new(); + public event Action? OnFileSelected; + + public RelayCommand RefreshRootDirectory => new(OnRefreshRootDirectory); + public RelayCommand RemoveRootDirectory => new(OnRemoveRootDirectory); + public RelayCommand OpenInExplorer => new(OnOpenInExplorer); + + public void Refresh() + { + foreach (var folder in Folders) + { + folder.Refresh(); + } + } + + public void AddFolder(string path) + { + if (!Folders.Any(item => item.Path == path)) + { + Folders.Add(new(path)); + App.Instance.SaveData.OpenedFolders.Add(path); + } + } + + public void SelectFile(FileItem fileItem) + { + OnFileSelected?.Invoke(fileItem); + } + + private void OnRefreshRootDirectory(object arg) + { + if (arg is RootDirectoryItem rootDirectory) + { + rootDirectory.Refresh(); + } + } + + private void OnRemoveRootDirectory(object arg) + { + if (arg is RootDirectoryItem rootDirectory) + { + Folders.Remove(rootDirectory); + App.Instance.SaveData.OpenedFolders.Remove(rootDirectory.Path); + } + } + + private void OnOpenInExplorer(object arg) + { + if (arg is BaseFileItem item) + { + System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{item.Path}\""); + } + } + } + + + public class BaseFileItem : INotifyPropertyChanged + { + public string Path { get; set; } + public string Name { get; set; } + public bool IsExpanded { get; set; } + + protected BaseFileItem(string path) + { + Path = path; + Name = System.IO.Path.GetFileName(path); + } + + public event PropertyChangedEventHandler? PropertyChanged; + } + + + public class FileItem(string path) : BaseFileItem(path) + { + } + + + public class DirectoryItem(string path) : BaseFileItem(path) + { + private static readonly IComparer comparer = + Comparer.Create((x, y) => x.Name.CompareTo(y.Name)); + private static readonly HashSet Filter = new() { ".pfb", ".scn", ".user" }; + + private ObservableCollection? children; + + public ObservableCollection Children + { + get + { + if (children == null) + { + children = new(); + Refresh(); + } + return children; + } + } + + public void Refresh() + { + if (children == null) return; + // // Console.WriteLine($"Refresh {Path}"); + List items = new(); + Dictionary childDict = new(); + foreach (BaseFileItem item in children) + { + childDict[item.Path] = item; + } + children.Clear(); + int directoryCount = 0; + foreach (var childPath in Directory.EnumerateDirectories(Path)) + { + if (childDict.TryGetValue(childPath, out var fileItem) && fileItem is DirectoryItem directoryItem) + { + items.Add(fileItem); + directoryItem.Refresh(); + } + else + { + items.Add(new DirectoryItem(childPath)); + } + directoryCount++; + } + foreach (var childPath in Directory.EnumerateFiles(Path)) + { + RszUtils.GetFileExtension(childPath, out string extension, out _); + if (!Filter.Contains(extension)) continue; + if (childDict.TryGetValue(childPath, out var fileItem) && fileItem is FileItem) + { + items.Add(fileItem); + } + else + { + items.Add(new FileItem(childPath)); + } + } + items.Sort(0, directoryCount, comparer); + items.Sort(directoryCount, items.Count - directoryCount, comparer); + if (directoryCount == 1) + { + items[0].IsExpanded = true; + ((DirectoryItem)items[0]).Refresh(); + } + foreach (var item in items) + { + if (item is DirectoryItem directoryItem) + { + directoryItem.Refresh(); + } + Children.Add(item); + } + } + } + + + public class RootDirectoryItem(string path) : DirectoryItem(path) + { + } +} diff --git a/RszTool.App/ViewModels/RszTestViewModel.cs b/RszTool.App/ViewModels/RszTestViewModel.cs index b66816a..00d435c 100644 --- a/RszTool.App/ViewModels/RszTestViewModel.cs +++ b/RszTool.App/ViewModels/RszTestViewModel.cs @@ -21,7 +21,7 @@ private static void OnCopyInstance(object arg) { if (arg is RszInstance instance) { - Console.WriteLine(instance.Stringify()); + // Console.WriteLine(instance.Stringify()); } } @@ -29,7 +29,7 @@ private static void OnCopyArrayItem(object arg) { if (arg is RszFieldArrayInstanceItemViewModel item) { - Console.WriteLine(item.Instance.Stringify()); + // Console.WriteLine(item.Instance.Stringify()); } } } diff --git a/RszTool.App/ViewModels/ThemeManager.cs b/RszTool.App/ViewModels/ThemeManager.cs new file mode 100644 index 0000000..578fd42 --- /dev/null +++ b/RszTool.App/ViewModels/ThemeManager.cs @@ -0,0 +1,57 @@ +using PropertyChanged; +using System.ComponentModel; +using System.Windows; +using System.Windows.Media; + +namespace RszTool.App.ViewModels +{ + public class ThemeManager : INotifyPropertyChanged + { + private bool isDarkTheme; + private static ThemeManager? instance; + public readonly SolidColorBrush LightForeground = + Application.Current.Resources["LightForeground"] as SolidColorBrush ?? Brushes.Black; + public readonly SolidColorBrush DarkForeground = + Application.Current.Resources["DarkForeground"] as SolidColorBrush ?? Brushes.White; + + public static ThemeManager Instance + { + get => instance ??= new(false); + private set => instance = value; + } + + [DoNotCheckEquality] + public bool IsDarkTheme + { + get => isDarkTheme; + set + { + isDarkTheme = value; + var mergedDictionaries = Application.Current.Resources.MergedDictionaries; + mergedDictionaries.Clear(); + mergedDictionaries.Add(new ResourceDictionary() + { + Source = new Uri(isDarkTheme ? "Themes/DarkTheme.xaml" : "Themes/LightTheme.xaml", UriKind.Relative) + }); + PropertyChanged?.Invoke(this, new(nameof(IsDarkTheme))); + } + } + + public SolidColorBrush Foreground => IsDarkTheme ? DarkForeground : LightForeground; + + public event PropertyChangedEventHandler? PropertyChanged; + + private ThemeManager(bool isDarkTheme) + { + IsDarkTheme = isDarkTheme; + var resources = Application.Current.Resources; + LightForeground = resources["LightForeground"] as SolidColorBrush ?? Brushes.Black; + DarkForeground = resources["DarkForeground"] as SolidColorBrush ?? Brushes.White; + } + + public static void Init(bool isDarkTheme = false) + { + Instance = new(isDarkTheme); + } + } +} diff --git a/RszTool.App/Views/FileExplorerTree.xaml b/RszTool.App/Views/FileExplorerTree.xaml new file mode 100644 index 0000000..8bde2d1 --- /dev/null +++ b/RszTool.App/Views/FileExplorerTree.xaml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RszTool.App/Views/FileExplorerTree.xaml.cs b/RszTool.App/Views/FileExplorerTree.xaml.cs new file mode 100644 index 0000000..21eeb16 --- /dev/null +++ b/RszTool.App/Views/FileExplorerTree.xaml.cs @@ -0,0 +1,39 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using RszTool.App.ViewModels; + +namespace RszTool.App.Views +{ + /// + /// FileExplorerTree.xaml 的交互逻辑 + /// + public partial class FileExplorerTree : UserControl + { + public FileExplorerTree() + { + InitializeComponent(); + } + + private void HandleTreeViewFileSelected() + { + if (DataContext is FileExplorerViewModel viewModel) + { + if (TreeView.SelectedItem is FileItem fileItem) + { + viewModel.SelectFile(fileItem); + } + } + } + + private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) + { + HandleTreeViewFileSelected(); + } + + private void FileItem_MouseDoubleClick(object sender, MouseButtonEventArgs e) + { + HandleTreeViewFileSelected(); + } + } +} diff --git a/RszTool.App/Views/TreeViewTemplate.xaml b/RszTool.App/Views/TreeViewTemplate.xaml new file mode 100644 index 0000000..6b4109b --- /dev/null +++ b/RszTool.App/Views/TreeViewTemplate.xaml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 50494dcd779316895bc1abb77c0c9f43571597ed Mon Sep 17 00:00:00 2001 From: namsku Date: Thu, 21 Nov 2024 21:20:51 +0100 Subject: [PATCH 3/4] Fix Console Verbose, Prefab Missing, Read Rsz error --- RszTool.Test/Program.cs | 34 ++++++++++++++++---------------- RszTool.sln | 12 ----------- RszTool/Common/Utils.cs | 2 +- RszTool/RszFile/BaseRszFile.cs | 6 +++--- RszTool/RszFile/MdfFile.cs | 3 --- RszTool/RszFile/PfbFile.cs | 3 --- RszTool/RszFile/RSZFile.cs | 6 +++--- RszTool/RszFile/RszFileOption.cs | 3 --- RszTool/RszFile/RszInstance.cs | 12 +++++------ RszTool/RszFile/RszUtils.cs | 4 ++-- RszTool/RszFile/ScnFile.cs | 24 +++++++++++----------- RszTool/RszParser.cs | 6 ------ 12 files changed, 44 insertions(+), 71 deletions(-) diff --git a/RszTool.Test/Program.cs b/RszTool.Test/Program.cs index 2e5176e..50b0f8a 100644 --- a/RszTool.Test/Program.cs +++ b/RszTool.Test/Program.cs @@ -27,8 +27,8 @@ private static void TestRszParser() record.Start("RszParser"); RszParser parser = new("rszre4.json"); record.End(); - Console.WriteLine(parser.GetRSZClassName(0x1001342f)); - Console.WriteLine(parser.GetFieldName(0x1004b6b4, 1)); + // Console.WriteLine(parser.GetRSZClassName(0x1001342f)); + // Console.WriteLine(parser.GetFieldName(0x1004b6b4, 1)); } static void TestParseUser() @@ -47,7 +47,7 @@ static void TestParseUser() { foreach (var item in newUserFile.RSZ.InstanceList) { - Console.WriteLine(item.Stringify()); + // Console.WriteLine(item.Stringify()); } } } @@ -60,7 +60,7 @@ static void TestParseUserRead() userFile.Read(); if (userFile.RSZ != null) { - Console.WriteLine(userFile.RSZ.ObjectsStringify()); + // Console.WriteLine(userFile.RSZ.ObjectsStringify()); } } @@ -81,7 +81,7 @@ static void TestParsePfb() { foreach (var item in newPfbFile.RSZ.InstanceList) { - Console.WriteLine(item.Stringify()); + // Console.WriteLine(item.Stringify()); } } } @@ -103,7 +103,7 @@ static void TestParsePfbRe2() { foreach (var item in newPfbFile.RSZ.InstanceList) { - Console.WriteLine(item.Stringify()); + // Console.WriteLine(item.Stringify()); } } } @@ -117,13 +117,13 @@ static void TestParsePfbRead() foreach (var item in pfbFile.UserdataInfoList) { - Console.WriteLine(item.pathOffset.ToString("X")); + // Console.WriteLine(item.pathOffset.ToString("X")); } foreach (var item in pfbFile.RSZ!.RSZUserDataInfoList) { if (item is RSZUserDataInfo userDataInfo) { - Console.WriteLine(userDataInfo.pathOffset.ToString("X")); + // Console.WriteLine(userDataInfo.pathOffset.ToString("X")); } } @@ -131,7 +131,7 @@ static void TestParsePfbRead() { foreach (var item in pfbFile.RSZ.InstanceList) { - Console.WriteLine(pfbFile.RSZ.InstanceStringify(item)); + // Console.WriteLine(pfbFile.RSZ.InstanceStringify(item)); } } } @@ -153,7 +153,7 @@ static void TestParseScn() { foreach (var item in newScnFile.RSZ.InstanceList) { - Console.WriteLine(item.Stringify()); + // Console.WriteLine(item.Stringify()); } } } @@ -167,13 +167,13 @@ static void TestParseScnRead() if (scnFile.RSZ != null) { - // Console.WriteLine(scnFile.RSZ.ObjectsStringify()); + // // Console.WriteLine(scnFile.RSZ.ObjectsStringify()); scnFile.SetupGameObjects(); if (scnFile.GameObjectDatas != null) { foreach (var item in scnFile.GameObjectDatas) { - Console.WriteLine(item.Name); + // Console.WriteLine(item.Name); } } @@ -189,12 +189,12 @@ static void TestScnExtractGameObjectRSZ() if (scnFile.RSZ != null) { - // Console.WriteLine(scnFile.RSZ.ObjectsStringify()); + // // Console.WriteLine(scnFile.RSZ.ObjectsStringify()); scnFile.SetupGameObjects(); FileHandler newFileHandler = new("test/gimmick_st66_101_new.rsz"); RSZFile newRSZ = new(option, newFileHandler); bool success = scnFile.ExtractGameObjectRSZ("設置機銃砦1", newRSZ); - Console.WriteLine(success); + // Console.WriteLine(success); } } @@ -212,7 +212,7 @@ static void TestScnExtractGameObjectToPfb() { pfbFile.Write(); } - Console.WriteLine(success); + // Console.WriteLine(success); } static void TestImportGameObject() @@ -272,7 +272,7 @@ static void TestMurMur3Hash() { uint hash = PakHash.GetHash(strings[i]); string result = hash == hashes[i] ? "" : $", expacted {hashes[i]:X}"; - Console.WriteLine($"hash of {strings[i]} is {hash:X}{result}"); + // Console.WriteLine($"hash of {strings[i]} is {hash:X}{result}"); } } @@ -294,7 +294,7 @@ RszFieldType.U8 or RszFieldType.U16 or RszFieldType.U32 or RszFieldType.U64 && } foreach (var item in enumSet) { - Console.WriteLine(item); + // Console.WriteLine(item); } } } diff --git a/RszTool.sln b/RszTool.sln index 5a99db0..38cc98e 100644 --- a/RszTool.sln +++ b/RszTool.sln @@ -3,30 +3,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34309.116 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RszTool.App", "RszTool.App\RszTool.App.csproj", "{2C5EC8A4-C5DD-41F4-B267-DBA1971194C7}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RszTool", "RszTool\RszTool.csproj", "{6F584A37-2D30-49AC-B47F-4604D32F2BE3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RszTool.Test", "RszTool.Test\RszTool.Test.csproj", "{25AC68C0-1445-4B64-B35F-78EF1A7A70EE}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2C5EC8A4-C5DD-41F4-B267-DBA1971194C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2C5EC8A4-C5DD-41F4-B267-DBA1971194C7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2C5EC8A4-C5DD-41F4-B267-DBA1971194C7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2C5EC8A4-C5DD-41F4-B267-DBA1971194C7}.Release|Any CPU.Build.0 = Release|Any CPU {6F584A37-2D30-49AC-B47F-4604D32F2BE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6F584A37-2D30-49AC-B47F-4604D32F2BE3}.Debug|Any CPU.Build.0 = Debug|Any CPU {6F584A37-2D30-49AC-B47F-4604D32F2BE3}.Release|Any CPU.ActiveCfg = Release|Any CPU {6F584A37-2D30-49AC-B47F-4604D32F2BE3}.Release|Any CPU.Build.0 = Release|Any CPU - {25AC68C0-1445-4B64-B35F-78EF1A7A70EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {25AC68C0-1445-4B64-B35F-78EF1A7A70EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {25AC68C0-1445-4B64-B35F-78EF1A7A70EE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {25AC68C0-1445-4B64-B35F-78EF1A7A70EE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/RszTool/Common/Utils.cs b/RszTool/Common/Utils.cs index e2422fd..8765f7a 100644 --- a/RszTool/Common/Utils.cs +++ b/RszTool/Common/Utils.cs @@ -20,7 +20,7 @@ public void Start(string name) public void End() { long endUs = DateTime.Now.Ticks / 10; - Console.WriteLine($"time of {Name}: {endUs - StartUs} us"); + // // Console.WriteLine($"time of {Name}: {endUs - StartUs} us"); } } diff --git a/RszTool/RszFile/BaseRszFile.cs b/RszTool/RszFile/BaseRszFile.cs index 319508f..5f19618 100644 --- a/RszTool/RszFile/BaseRszFile.cs +++ b/RszTool/RszFile/BaseRszFile.cs @@ -42,7 +42,7 @@ public bool Read() Start = FileHandler.Tell(); bool result = DoRead(); Size = FileHandler.Tell() - Start; - // Console.WriteLine($"{this} Start: {Start}, Read size: {Size}"); + // // // Console.WriteLine($"{this} Start: {Start}, Read size: {Size}"); return result; } @@ -64,7 +64,7 @@ public bool Write() Start = FileHandler.Tell(); bool result = DoWrite(); Size = FileHandler.Tell() - Start; - // Console.WriteLine($"{this} Start: {Start}, Write size: {Size}"); + // // // Console.WriteLine($"{this} Start: {Start}, Write size: {Size}"); return result; } @@ -110,7 +110,7 @@ public bool WriteTo(FileHandler handler, bool saveFile = true) } catch (Exception e) { - Console.WriteLine(e); + // // Console.WriteLine(e); result = false; } FileHandler = originHandler; diff --git a/RszTool/RszFile/MdfFile.cs b/RszTool/RszFile/MdfFile.cs index 74935c2..26e2f11 100644 --- a/RszTool/RszFile/MdfFile.cs +++ b/RszTool/RszFile/MdfFile.cs @@ -257,9 +257,6 @@ public MdfFile(RszFileOption option, FileHandler fileHandler) : base(option, fil GameName.re8 => ".19", GameName.re7 => ".6", GameName.re7rt => ".21", - GameName.dmc5 =>".10", - GameName.mhrise => ".23", - GameName.sf6 => ".31", _ => null }; } diff --git a/RszTool/RszFile/PfbFile.cs b/RszTool/RszFile/PfbFile.cs index 18151cc..21e3031 100644 --- a/RszTool/RszFile/PfbFile.cs +++ b/RszTool/RszFile/PfbFile.cs @@ -186,9 +186,6 @@ public PfbFile(RszFileOption option, FileHandler fileHandler) : base(option, fil GameName.re8 => ".17", GameName.re7 => ".16", GameName.re7rt => ".17", - GameName.dmc5 =>".16", - GameName.mhrise => ".17", - GameName.sf6 => ".17", _ => null }; } diff --git a/RszTool/RszFile/RSZFile.cs b/RszTool/RszFile/RSZFile.cs index e4e673c..f580604 100644 --- a/RszTool/RszFile/RSZFile.cs +++ b/RszTool/RszFile/RSZFile.cs @@ -242,7 +242,7 @@ public string ObjectsStringify() return sb.ToString(); } - private void FixInstanceObjectIndex(RszInstance instance) + private void FixObjectTableInstanceId(RszInstance instance) { if (instance.ObjectTableIndex >= 0 && instance.ObjectTableIndex < ObjectTableList.Count) { @@ -269,7 +269,7 @@ public void FixInstanceIndex(RszInstance instance) instance.Index = list.Count; list.Add(instance); } - FixInstanceObjectIndex(instance); + FixObjectTableInstanceId(instance); } } @@ -317,7 +317,7 @@ public void RebuildInstanceList() { item.Index = list.Count; list.Add(item); - FixInstanceObjectIndex(item); + FixObjectTableInstanceId(item); } } } diff --git a/RszTool/RszFile/RszFileOption.cs b/RszTool/RszFile/RszFileOption.cs index e519602..2456e83 100644 --- a/RszTool/RszFile/RszFileOption.cs +++ b/RszTool/RszFile/RszFileOption.cs @@ -20,9 +20,6 @@ public RszFileOption(GameName gameName) GameName.re7 => GameVersion.re7, GameName.re7rt => GameVersion.re7rt, GameName.re8 => GameVersion.re8, - GameName.dmc5 => GameVersion.dmc5, - GameName.mhrise => GameVersion.mhrise, - GameName.sf6 => GameVersion.sf6, _ => GameVersion.unknown, }; RszParser = RszParser.GetInstance($"rsz{gameName}.json"); diff --git a/RszTool/RszFile/RszInstance.cs b/RszTool/RszFile/RszInstance.cs index 7ef9067..c6aa929 100644 --- a/RszTool/RszFile/RszInstance.cs +++ b/RszTool/RszFile/RszInstance.cs @@ -81,7 +81,7 @@ protected override bool DoRead(FileHandler handler) if (RSZUserData != null || RszClass.fields.Length == 0) return true; AlignFirstField(handler); - // Console.WriteLine($"read {Name} at: {handler.Position:X}"); + // // // Console.WriteLine($"read {Name} at: {handler.Position:X}"); for (int i = 0; i < RszClass.fields.Length; i++) { Values[i] = ReadRszField(handler, i); @@ -100,7 +100,7 @@ public object ReadRszField(FileHandler handler, int index) { RszField field = RszClass.fields[index]; handler.Align(field.array ? 4 : field.align); - // Console.WriteLine($" read at: {handler.Position:X} {field.original_type} {field.name}"); + // // // Console.WriteLine($" read at: {handler.Position:X} {field.original_type} {field.name}"); if (field.array) { int count = handler.ReadInt(); @@ -108,7 +108,7 @@ public object ReadRszField(FileHandler handler, int index) { throw new InvalidDataException($"{field.name} count {count} < 0"); } - if (count > 2048) + if (count > 20000) { throw new InvalidDataException($"{field.name} count {count} too large"); } @@ -152,7 +152,7 @@ private bool DetectDataType(RszField field, ref object data) field.type = RszFieldType.Object; field.IsTypeInferred = true; data = intValue; - Console.WriteLine($"Detect {Name}.{field.name} as Object"); + // // Console.WriteLine($"Detect {Name}.{field.name} as Object"); return true; } // 检测float和int @@ -469,7 +469,7 @@ protected override bool DoWrite(FileHandler handler) // if has RSZUserData, it is external if (RSZUserData != null || RszClass.fields.Length == 0) return true; AlignFirstField(handler); - // Console.WriteLine($"write {Name} at: {(handler.Offset + handler.Tell()):X}"); + // // // Console.WriteLine($"write {Name} at: {(handler.Offset + handler.Tell()):X}"); for (int i = 0; i < RszClass.fields.Length; i++) { WriteRszField(handler, i); @@ -487,7 +487,7 @@ public bool WriteRszField(FileHandler handler, int index) { RszField field = RszClass.fields[index]; handler.Align(field.array ? 4 : field.align); - // Console.WriteLine($" write at: {handler.Position:X} {field.original_type} {field.name}"); + // // // Console.WriteLine($" write at: {handler.Position:X} {field.original_type} {field.name}"); if (field.array) { List list = (List)Values[index]; diff --git a/RszTool/RszFile/RszUtils.cs b/RszTool/RszFile/RszUtils.cs index 6ce6a96..d8d941c 100644 --- a/RszTool/RszFile/RszUtils.cs +++ b/RszTool/RszFile/RszUtils.cs @@ -120,11 +120,11 @@ public static void CheckFileExtension(string path, string extension, string? ver GetFileExtension(path, out string realExtension, out string realVersion); if (extension != realExtension) { - Console.Error.WriteLine($"extension should be {extension}, got {realExtension}"); + // Console.Error.WriteLine($"extension should be {extension}, got {realExtension}"); } if (version != realVersion) { - Console.Error.WriteLine($"extension should be {version}, got {realVersion}"); + // Console.Error.WriteLine($"extension should be {version}, got {realVersion}"); } } } diff --git a/RszTool/RszFile/ScnFile.cs b/RszTool/RszFile/ScnFile.cs index 05c3302..d770b7e 100644 --- a/RszTool/RszFile/ScnFile.cs +++ b/RszTool/RszFile/ScnFile.cs @@ -287,9 +287,6 @@ public ScnFile(RszFileOption option, FileHandler fileHandler) : base(option, fil GameName.re8 => ".20", GameName.re7 => ".18", GameName.re7rt => ".20", - GameName.dmc5 =>".19", - GameName.mhrise => ".20", - GameName.sf6 => ".20", _ => null }; } @@ -454,7 +451,9 @@ public void SetupGameObjects() { if (folderIdxMap.TryGetValue(info.Data.parentId, out var folder)) { - folder.Children.Add(folderIdxMap[info.Data.objectId]); + var childFolder = folderIdxMap[info.Data.objectId]; + folder.Children.Add(childFolder); + childFolder.Parent = folder; } } @@ -505,6 +504,7 @@ public static IEnumerable IterGameObjectInstances(GameObjectData ga } } } + /// /// 收集Folder以及子Folder的实例和组件实例 @@ -690,7 +690,7 @@ private void AddFolderInfoRecursion(FolderData folder) foreach (var prefab in folder.Prefabs) { prefab.parentId = infoData.objectId; - // PrefabInfoList.GetIndexOrAdd(prefab); + PrefabInfoList.GetIndexOrAdd(prefab); } } @@ -706,7 +706,7 @@ private void AddFolderInfoRecursion(FolderData folder) var children = parent?.Children ?? GameObjectDatas; if (children == null) { - Console.Error.WriteLine("GameObjectDatas and parent is null"); + // Console.Error.WriteLine("GameObjectDatas and parent is null"); return null; } foreach (var child in children) @@ -721,7 +721,7 @@ private void AddFolderInfoRecursion(FolderData folder) if (result != null) return result; } } - Console.Error.WriteLine($"GameObject {name} not found"); + // Console.Error.WriteLine($"GameObject {name} not found"); return null; } @@ -739,7 +739,7 @@ private void AddFolderInfoRecursion(FolderData folder) var folders = parent?.Children ?? FolderDatas; if (folders == null) { - Console.Error.WriteLine("FolderDatas and parent is null"); + // Console.Error.WriteLine("FolderDatas and parent is null"); return null; } foreach (var folder in folders!) @@ -758,7 +758,7 @@ private void AddFolderInfoRecursion(FolderData folder) if (result != null) return result; } } - Console.Error.WriteLine($"GameObject {name} not found"); + // Console.Error.WriteLine($"GameObject {name} not found"); return null; } @@ -773,7 +773,7 @@ public IEnumerable IterGameObjectsInFolder(FolderData? parent = var folders = parent?.Children ?? FolderDatas; if (folders == null) { - Console.Error.WriteLine("FolderDatas and parent is null"); + // Console.Error.WriteLine("FolderDatas and parent is null"); yield break; } foreach (var folder in folders) @@ -852,7 +852,7 @@ public bool ExtractGameObjectRSZ(GameObjectData gameObject, RSZFile newRSZ) { if (RSZ == null) { - Console.Error.WriteLine($"RSZ is null"); + // Console.Error.WriteLine($"RSZ is null"); return false; } List rszInstances = new(); @@ -863,7 +863,7 @@ public bool ExtractGameObjectRSZ(GameObjectData gameObject, RSZFile newRSZ) newRSZ.RebuildInstanceInfo(false); // foreach (var item in newRSZ.InstanceList) // { - // Console.WriteLine(newRSZ.InstanceStringify(item)); + // // // Console.WriteLine(newRSZ.InstanceStringify(item)); // } // write newRSZ.Write(); diff --git a/RszTool/RszParser.cs b/RszTool/RszParser.cs index 675458d..6901521 100644 --- a/RszTool/RszParser.cs +++ b/RszTool/RszParser.cs @@ -94,12 +94,6 @@ private void ReadPatch(string originalJsonPath) } if (fieldPatch.Type != RszFieldType.ukn_error) { - if (rszField.type != RszFieldType.Data) - { - Console.WriteLine( - $"Warning: {classPatch.Name}.{fieldPatch.Name} change type " + - $"from {rszField.type} to {fieldPatch.Type}"); - } rszField.type = fieldPatch.Type; rszField.IsTypeInferred = true; } From 9c3b7a0ce46ecc5de30372de504553d70b3f63c9 Mon Sep 17 00:00:00 2001 From: Namsku <144552240+Namsku@users.noreply.github.com> Date: Sun, 8 Dec 2024 23:17:21 +0100 Subject: [PATCH 4/4] Update readme.md --- readme.md | 48 +++++++----------------------------------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/readme.md b/readme.md index 8fda037..1a686e1 100644 --- a/readme.md +++ b/readme.md @@ -1,47 +1,13 @@ -# RszTool +# **RszToolEx** -## About this project +## **About This Project** -RszTool is a tool that edit and create resource file for RE ENGINE game. Currently support .user, .pfb and .scn files. -RszTool is inspired by [RE_RSZ](https://github.com/alphazolam/RE_RSZ) and [EMV-Engine/RE Engine Resource Editor](https://github.com/alphazolam/EMV-Engine) by alphazolam. -RszTool also provide some advanced operations like copy/paste/remove/duplicate for instance array/game object. -RszTool is developed with C# and WPF. You can also use RszTool.dll as a C# library to do some batch work. +RszToolEx is a refined and enhanced utility for editing and creating resource files for RE ENGINE games, with a particular focus on facilitating modding for Resident Evil titles. This tool builds upon the foundation laid by the original [RszTool](https://github.com/czastack/RszTool) by czastack, introducing significant improvements in performance, functionality, and user experience. -## Why I make this tool +Designed with modders in mind, RszToolEx simplifies the complex workflows associated with resource file manipulation, making it an essential tool for the RE ENGINE modding community. -- RE_RSZ is a good tool. But it is 010 Editor Binary Template, so it need refresh action when struct changed. And sometimes it take several minutes to open a complex file. Also it lacked some advanced operations like copy/paste for hierarchical instance/game object. You need manual create many instances and set object index to another instance. -- EMV-Engine/RE Engine Resource Editor is a reframework lua script. You need to open the game first to use it. It provide limited file access. For example, it is not convenient to open file or drop file into it. It provide some function like adding item inspire me. +--- -I want a faster and rich functional tool to edit resource file. So I make this tool. +### **License** - -## How to use this tool - -- Download the latest release [here](https://github.com/czastack/RszTool/releases). -- You need to copy rszxxx.json to the same folder of RszTool.App.exe from RE_RSZ manually. -- Currently, RszTool.App support Chinese and English, it will choose language according to your system culture. -- RszPatchs/rszxxx_patch.json will replace some data in rszxxx.json. Because sometimes auto detected type for "Data" type is not correct. -- You can Click File/Open menu or drag and drop file to RszTool.App window to open it. -- Right click for array item/game object to see some operation context menu. I think it is good to use. - ![how-to-use](Docs/images/how-to-use.png) -- You can search instances and game objects in bottom of the page. - -## How to build this project - -RszTool support .net framework 4.7.2 and .net8, you can also change it in .csproj file. -1. Install [.net8 SDK](https://dotnet.microsoft.com/zh-cn/download/dotnet/8.0) -2. cd RszTool.App folder and run "dotnet build -f net8.0-windows" or "dotnet build -f net472" -3. You can also build it by Visual Studio 2022. - -## project struct - -1. RszTool - - The core library of RszTool. Provide functions to read/write/edit resource file. -2. RszTool.App - - The gui application of RszTool. -3. RszTool.Test - - Some example to show basic usage of RszTool.dll, like file open/read/write/save. - -## License - -RszTool is under MIT license. See LICENSE for more detail. +RszToolEx is licensed under the permissive MIT License, allowing free use, modification, and distribution. For more details, refer to the `LICENSE` file.