diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b7164f..84f13fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,10 @@ -# GhTrTool 0.11w ~ [2024-05-29] +# GhTrTool 0.11x ~ [2024-06-02] ## 完整更新日志 -### 特性 -- 重构"允许创建Unbalanced难度存档"功能 +### 更新 +- 支持0.16n的游戏版本,取消对之前版本的支持 ### 正在进行 -- 地址常数化 +- 地址数值常数化 -![image](https://github.com/Xcating/GhTrTool/assets/82816129/0c7d40cd-d8d8-4367-838e-f3a12b841c3e) +![MainGUI](https://github.com/Xcating/GhTrTool/assets/82816129/42f63f91-314f-4457-a53a-e23779d1c7ca) -![image](https://github.com/Xcating/GhTrTool/assets/82816129/685daa33-4945-452a-8491-9440c166f619) \ No newline at end of file +![GameTest](https://github.com/Xcating/GhTrTool/assets/82816129/6665c762-5e7b-44b7-b322-b0ea3b89d0e7) \ No newline at end of file diff --git a/GhTrTool/Constant.h b/GhTrTool/Constant.h index 517a20b..0fe578d 100644 --- a/GhTrTool/Constant.h +++ b/GhTrTool/Constant.h @@ -1,18 +1,18 @@ #pragma once -CONST DWORD GAME_BASE_OFFSET = 0x29CD20; //游戏LawnAPP* 实例偏移 [BaseAddress+GAME_BASE_OFFSET] +CONST DWORD GAME_BASE_OFFSET = 0x2A0DD0; //游戏LawnAPP* 实例偏移 [BaseAddress+GAME_BASE_OFFSET] CONST DWORD GAME_BOARD_OFFSET = 0x708; //游戏Board*板 实例偏移 [[BaseAddress+GAME_BASE_OFFSET]+GAME_BOARD_OFFSET] CONST DWORD GAME_SUN_OFFSET = 0x384; //阳光 偏移 [[[BaseAddress+GAME_BASE_OFFSET]+GAME_BOARD_OFFSET]+GAME_SUN_OFFSET] CONST DWORD GAME_CARD_OFFSET = 0x14C; //卡槽 实例偏移 [[[BaseAddress+GAME_BASE_OFFSET]+GAME_BOARD_OFFSET]+GAME_CARD_OFFSET] CONST DWORD GAME_CARD_NUMBER_OFFSET = 0x24; //卡槽个数 偏移 [[[[BaseAddress+GAME_BASE_OFFSET]+GAME_BOARD_OFFSET]+GAME_CARD_OFFSET]+GAME_CARD_NUMBER_OFFSET] CONST DWORD GAME_CARD_ID_OFFSET = 0x2C; //卡槽ID 偏移 [[[[BaseAddress+GAME_BASE_OFFSET]+GAME_BOARD_OFFSET]+GAME_CARD_OFFSET]+GAME_CARD_ID_OFFSET] CONST DWORD GAME_CARD_SIZE = 0x38; //卡槽类大小 -CONST DWORD GAME_CARD_ID_START_OFFSET = 0x1C; //卡槽ID特殊起始点 偏移 [!疑似多余] [[[[[BaseAddress+GAME_BASE_OFFSET]+GAME_BOARD_OFFSET]+GAME_CARD_OFFSET]+GAME_CARD_ID_OFFSET]+GAME_CARD_ID_START_OFFSET] -CONST DWORD GAME_PLANT_SUB_SUN_OFFSET = 0x9C519; //种植植物阳光减少 偏移 [BaseAddress+GAME_PLANT_SUB_SUN_OFFSET] +CONST DWORD GAME_CARD_ID_START_OFFSET = 0x1C; //卡槽ID特殊起始点 偏移 [[[[[BaseAddress+GAME_BASE_OFFSET]+GAME_BOARD_OFFSET]+GAME_CARD_OFFSET]+GAME_CARD_ID_OFFSET]+GAME_CARD_ID_START_OFFSET] +CONST DWORD GAME_PLANT_SUB_SUN_OFFSET = 0x9C709;//种植植物阳光减少 偏移 [BaseAddress+GAME_PLANT_SUB_SUN_OFFSET] CONST CHAR* GAME_PLANT_SUB_SUN_PATCH_OPCODE = "\x90\x90\x90\x90\x90\x90"; //种植植物阳光减少_阳光不减少 操作码 CONST CHAR* GAME_PLANT_SUB_SUN_ORIGINAL_OPCODE = "\x29\xBE\x84\x03\x00\x00"; //种植植物阳光减少_原码 操作码 -CONST DWORD GAME_PLANT_NO_CD_OFFSET = 0xEBA99; //重新种植更新当前冷却 偏移 [BaseAddress+GAME_PLANT_NO_CD_OFFSET] +CONST DWORD GAME_PLANT_NO_CD_OFFSET = 0xEE299; //重新种植更新当前冷却 偏移 [BaseAddress+GAME_PLANT_NO_CD_OFFSET] CONST CHAR* GAME_CARD_NO_CD_PATCH_OPCODE = "\xC7\x42\x24\x00\x00\x00\x00\x90\x90\x90"; //重新种植更新当前冷却_重置冷却设为0 操作码 CONST CHAR* GAME_CARD_NO_CD_ORIGINAL_OPCODE = "\x89\x42\x24\xC7\x42\x20\x00\x00\x00\x00"; //重新种植更新当前冷却_原码 操作码 -CONST DWORD GAME_PLANT_IGNORE_CD_OFFSET = 0xEBD3D; //判断冷却是否结束 偏移 [BaseAddress+GAME_PLANT_IGNORE_CD_OFFSET] +CONST DWORD GAME_PLANT_IGNORE_CD_OFFSET = 0xEE53D; //判断冷却是否结束 偏移 [BaseAddress+GAME_PLANT_IGNORE_CD_OFFSET] CONST CHAR* GAME_CARD_IGNORE_CD_PATCH_OPCODE = "\x90\x90"; //判断冷却是否结束_不判断 操作码 CONST CHAR* GAME_CARD_IGNORE_CD_ORIGINAL_OPCODE = "\x39\x08"; //判断冷却是否结束_原码 操作码 \ No newline at end of file diff --git a/GhTrTool/GhTr.cpp b/GhTrTool/GhTr.cpp index 906668a..8e9edff 100644 --- a/GhTrTool/GhTr.cpp +++ b/GhTrTool/GhTr.cpp @@ -222,14 +222,14 @@ BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM l_param) { #ifdef _DEBUG std::wstring wstr = (std::wstringstream() << L"Plants Vs Zombies GhTr ~ Perfect Voyage " - << L"ver.0.16m - [Debug] [已被GhTrTool修改] " - << L"[βver.] [" + << L"ver.0.16n - [Debug] [已被GhTrTool修改] " + << L"[βver.0.11x] [" << millis << L"]") .str(); #else std::wstring wstr = (std::wstringstream() << L"Plants Vs Zombies GhTr ~ Perfect Voyage " - << L"ver.0.16m - [已被GhTrTool修改] [ver.0.11w] [" + << L"ver.0.16n - [已被GhTrTool修改] [ver.0.11x] [" << millis << L"]" << L" [Save" << dwNum<pNext) { - CString outputFilePath = unpackFolderName + _T("\\") + CString(pNode->pPathname); + CString outputFilePath = FolderName + _T("\\") + CString(pNode->pPathname); { char* pSlash = pNode->pPathname; @@ -1852,7 +1849,7 @@ void GhTrManager::UnpackGrpFile() if (*pSlash == '\0') break; *pSlash = '\0'; - CString folderPath = unpackFolderName + _T("\\") + CString(pNode->pPathname); + CString folderPath = FolderName + _T("\\") + CString(pNode->pPathname); std::filesystem::path dir(folderPath.GetString()); std::filesystem::create_directories(dir); *pSlash = '\\'; @@ -1875,11 +1872,14 @@ void GhTrManager::UnpackGrpFile() } free(pMainPak); pMainPak = NULL; - MessageBox(NULL, L"解包成功!点击确认打开文件夹",L"提示", MB_OK); - OpenFolder(unpackFolderName); + MessageBox(NULL, L"解包成功!点击确认打开输出文件夹",L"提示", MB_OK); + OpenFolder(FolderName); return; } - +/** + * 打包grp文件 [DEBUG ONLY] + * + */ void GhTrManager::PackGrpFile() { std::filesystem::path folderPath = SelectFolder(); @@ -2015,6 +2015,7 @@ void GhTrManager::PackGrpFile() delete[] buffer; } CloseHandle(hfw); - MessageBox(NULL, L"打包成功,点击确认选择文件", L"提示", MB_OK); + MessageBox(NULL, L"打包成功,点击确认选择输出文件", L"提示", MB_OK); OpenFolderAndSelectItem(dst_file); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/GhTrTool/GhTr.h b/GhTrTool/GhTr.h index 668ef13..e5fc702 100644 --- a/GhTrTool/GhTr.h +++ b/GhTrTool/GhTr.h @@ -1,7 +1,7 @@ #pragma once #include #include "json.hpp" -#define GAME_NAME L"Plants Vs Zombies GhTr ~ Perfect Voyage ver.0.16m" +#define GAME_NAME L"Plants Vs Zombies GhTr ~ Perfect Voyage ver.0.16n" class GhTrManager { @@ -126,9 +126,11 @@ class GhTrManager void SwitchToRedStingerMode(); //Ub不碎档 void DisableUbSaveDestroy(bool isFeatureEnabled); +#ifdef _DEBUG //解包grp void UnpackGrpFile(); //打包grp void PackGrpFile(); +#endif }; diff --git a/GhTrTool/GhTrTool.rc b/GhTrTool/GhTrTool.rc index bf49a22..3b0933a 100644 Binary files a/GhTrTool/GhTrTool.rc and b/GhTrTool/GhTrTool.rc differ diff --git a/GhTrTool/GhTrToolDlg.cpp b/GhTrTool/GhTrToolDlg.cpp index 8f43b9a..e6a0653 100644 --- a/GhTrTool/GhTrToolDlg.cpp +++ b/GhTrTool/GhTrToolDlg.cpp @@ -99,8 +99,13 @@ BEGIN_MESSAGE_MAP(CGhTrToolDlg, CDialogEx) ON_BN_CLICKED(IDC_BTN_MakePlantsInvincible, &CGhTrToolDlg::OnBnClickedBtnMakePlantsInvincible) ON_BN_CLICKED(IDC_BTN_PreventItemDeterioration, &CGhTrToolDlg::OnBnClickedBtnPreventItemDeterioration) ON_BN_CLICKED(IDC_BTN_DisableUbSaveDestroy, &CGhTrToolDlg::OnBnClickedBtnDisableUbSaveDestroy) +#ifdef _DEBUG ON_BN_CLICKED(IDC_BTN_UnpackGrpFile, &CGhTrToolDlg::OnBnClickedBtnUnpackGrpFile) ON_BN_CLICKED(IDC_BTN_PackGrpFile, &CGhTrToolDlg::OnBnClickedBtnPackGrpFile) +#else + ON_BN_CLICKED(IDC_BTN_UnpackGrpFile, &CGhTrToolDlg::DebugOnlyMessageBox) + ON_BN_CLICKED(IDC_BTN_PackGrpFile, &CGhTrToolDlg::DebugOnlyMessageBox) +#endif ON_BN_CLICKED(IDC_BTN_EnableOpticaltropFrameDamage, &CGhTrToolDlg::OnBnClickedBtnEnableOpticaltropFrameDamage) ON_BN_CLICKED(IDC_BTN_PlantWithoutSunCost, &CGhTrToolDlg::OnBnClickedBtnPlantWithoutSunCost) ON_BN_CLICKED(IDC_BTN_CompleteLevelWithTrophy, &CGhTrToolDlg::OnBnClickedBtnCompleteLevelWithTrophy) @@ -198,14 +203,15 @@ BOOL CGhTrToolDlg::OnInitDialog() { CDialogEx::OnInitDialog(); UpdateText(); - GetDlgItem(IDC_BTN_UnpackGrpFile)->ShowWindow(SW_HIDE); - GetDlgItem(IDC_BTN_PackGrpFile)->ShowWindow(SW_HIDE); - GetDlgItem(IDC_STATIC_PACK)->ShowWindow(SW_HIDE); - #ifdef _DEBUG +#ifdef _DEBUG GetDlgItem(IDC_BTN_UnpackGrpFile)->ShowWindow(SW_SHOW); GetDlgItem(IDC_BTN_PackGrpFile)->ShowWindow(SW_SHOW); GetDlgItem(IDC_STATIC_PACK)->ShowWindow(SW_SHOW); - #endif +#else + GetDlgItem(IDC_BTN_UnpackGrpFile)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_BTN_PackGrpFile)->ShowWindow(SW_HIDE); + GetDlgItem(IDC_STATIC_PACK)->ShowWindow(SW_HIDE); +#endif CMenu* pMenu = new CMenu(); pMenu->LoadMenu(IDR_MENU1); // 使用实际的菜单资源ID代替 SetMenu(pMenu); @@ -285,6 +291,13 @@ HCURSOR CGhTrToolDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } +#ifdef _DEBUG +#else +void CGhTrToolDlg::DebugOnlyMessageBox() +{ + MessageBoxA(NULL, "该功能仅供DEBUG使用,RELEASE编译模式无法使用。", "提示", MB_OK | MB_ICONERROR); +} +#endif void CGhTrToolDlg::ToggleFeature(UINT nID, void (GhTrManager::* featureFunc)(bool)) { GhTrManager GhTr; @@ -521,6 +534,7 @@ void CGhTrToolDlg::OnBnClickedBtnDisableUbSaveDestroy() { ToggleFeature(IDC_BTN_DisableUbSaveDestroy, &GhTrManager::DisableUbSaveDestroy); } +#ifdef _DEBUG void CGhTrToolDlg::OnBnClickedBtnUnpackGrpFile() { @@ -533,7 +547,7 @@ void CGhTrToolDlg::OnBnClickedBtnPackGrpFile() GhTrManager GhTr = GhTrManager(); GhTr.PackGrpFile(); } - +#endif void CGhTrToolDlg::OnBnClickedBtnInstantSunGeneration() { ToggleFeature(IDC_BTN_InstantSunGeneration, &GhTrManager::InstantSunGeneration); diff --git a/GhTrTool/GhTrToolDlg.h b/GhTrTool/GhTrToolDlg.h index cf3e28d..f264f1e 100644 --- a/GhTrTool/GhTrToolDlg.h +++ b/GhTrTool/GhTrToolDlg.h @@ -35,6 +35,7 @@ class CGhTrToolDlg : public CDialogEx afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); + void DebugOnlyMessageBox(); void ToggleFeature(UINT nID, void(GhTrManager::* featureFunc)(bool)); void PlantAtPositions(GhTrManager& GhTr, DWORD dwXP, DWORD dwYP, DWORD dwID); DECLARE_MESSAGE_MAP() @@ -78,8 +79,10 @@ class CGhTrToolDlg : public CDialogEx afx_msg void OnBnClickedBtnMaintainMaximumPowerPlantSize(); afx_msg void OnBnClickedBtnPreventItemDeterioration(); afx_msg void OnBnClickedBtnDisableUbSaveDestroy(); +#ifdef _DEBUG afx_msg void OnBnClickedBtnUnpackGrpFile(); afx_msg void OnBnClickedBtnPackGrpFile(); +#endif afx_msg void OnBnClickedBtnInstantSunGeneration(); afx_msg void OnBnClickedBtnDeployFormationInstantly(); afx_msg void OnBnClickedBtnModifyEnableFrameDamageData(); diff --git a/GhTrTool/InfoDialog.cpp b/GhTrTool/InfoDialog.cpp index 5b46cfb..f701f10 100644 --- a/GhTrTool/InfoDialog.cpp +++ b/GhTrTool/InfoDialog.cpp @@ -43,8 +43,10 @@ BOOL InfoDialog::OnInitDialog() {_T("苹果鼓瑟手"), _T("11")}, {_T("滇池牡丹"), _T("12")}, {_T("导藓"), _T("13")}, - {_T("土豆地雷"), _T("14")}, - {_T("淀粉海"), _T("15")}, + {_T("淀粉海"), _T("14")}, + {_T("伶初玫瑰"), _T("15")}, + {_T("磁力菇"), _T("16")}, + {_T("土豆地雷"), _T("17")}, }; // 插入列 m_List.InsertColumn(0, _T("植物名称"), LVCFMT_LEFT, 100); @@ -92,6 +94,7 @@ BOOL InfoDialog::OnInitDialog() {_T("迷蒙之沼"), _T("6")}, {_T("迷蒙神隐"), _T("7")}, {_T("绽凌原野"), _T("8")}, + {_T("绽凌殿"), _T("9")}, }; // 插入列 m_List3.InsertColumn(0, _T("背景名称"), LVCFMT_LEFT, 100); diff --git a/GhTrTool/macro.h b/GhTrTool/macro.h index b0b357d..149bc56 100644 --- a/GhTrTool/macro.h +++ b/GhTrTool/macro.h @@ -11,14 +11,18 @@ struct FileInfoNode { } }; -const wchar_t* GAME_TITLE = L"Plants Vs Zombies GhTr ~ Perfect Voyage ver.0.16m"; +const wchar_t* GAME_TITLE = L"Plants Vs Zombies GhTr ~ Perfect Voyage ver.0.16n"; const wchar_t* GAME_PROCESS_NAME_CAPITAL = L"PlantsVsZombies.exe"; const wchar_t* GAME_PROCESS_NAME_LOWER = L"plantsvszombies.exe"; constexpr auto MAGIC_NUM = 0xC04AC0BA; constexpr auto VERSION_NUM = (0xFFFFFFFF ^ 0xFFFFFFFF); constexpr auto XOR_KEY = (0xFFFFFFFF ^ 0x14141414); - +/** + * 转码UTF8 + * + * @param wstr 目标转换字符串 + */ std::string utf8_encode(const std::wstring& wstr) { if (wstr.empty()) @@ -28,7 +32,11 @@ std::string utf8_encode(const std::wstring& wstr) WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str[0], size_needed, nullptr, nullptr); return str; } - +/** + * 解码UTF8 + * + * @param str 目标转换字符串 + */ std::wstring utf8_decode(const std::string& str) { if (str.empty()) @@ -38,6 +46,14 @@ std::wstring utf8_decode(const std::string& str) MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstr[0], size_needed); return wstr; } +/** + * 查找文件夹内所有文件并建表 + * + * @param find_path 查找的目录 + * @param files_name 文件名数组 + * @param files_size 文件大小数组 + * @param files_time 文件修改时间数组 + */ void find_files(const std::wstring find_path, std::vector& files_name, std::vector& files_size, @@ -80,6 +96,11 @@ void find_files(const std::wstring find_path, FindClose(hf); } } +/** + * 创建目标解包路径文件夹 + * + * @param path 要创建的目录地址 + */ bool create_path(const std::wstring& path) { if (path == L"") @@ -94,7 +115,10 @@ bool create_path(const std::wstring& path) return false; return CreateDirectoryW(path.c_str(), nullptr); } - +/** + * 弹出选择文件夹对话框 + * + */ std::filesystem::path SelectFolder() { CFolderPickerDialog folderPickerDialog(NULL, OFN_ENABLESIZING | OFN_OVERWRITEPROMPT, NULL, 0); @@ -105,9 +129,19 @@ std::filesystem::path SelectFolder() } return resultPath; } +/** + * 交换字节顺序 + * + * @param x 要交换的字节 + */ unsigned char swapNibbles(unsigned char x) { return (x << 4) | (x >> 4); } +/** + * 交换DWORD所有字节的顺序 + * + * @param val 要交换的DWORD变量 + */ unsigned long swapBytesInLong(unsigned long val) { unsigned long result = 0; result |= (unsigned long)swapNibbles((unsigned char)(val & 0xFF)) << 24; @@ -116,10 +150,20 @@ unsigned long swapBytesInLong(unsigned long val) { result |= (unsigned long)swapNibbles((unsigned char)((val >> 24) & 0xFF)); return result; } -void OpenFolder(const CString& unpackFolderName) +/** + * 打开一个文件夹 + * + * @param FolderName 要打开的文件夹地址 + */ +void OpenFolder(const CString& FolderName) { - ShellExecute(NULL, _T("open"), LPCTSTR(unpackFolderName), NULL, NULL, SW_SHOWDEFAULT); + ShellExecute(NULL, _T("open"), LPCTSTR(FolderName), NULL, NULL, SW_SHOWDEFAULT); } +/** + * 打开一个文件夹并选中文件 + * + * @param itemName 要选中的文件地址 + */ void OpenFolderAndSelectItem(const std::wstring& itemName) { wchar_t buffer[MAX_PATH]; diff --git a/GhTrTool/resource.h b/GhTrTool/resource.h index 1d81e92..a6d6405 100644 Binary files a/GhTrTool/resource.h and b/GhTrTool/resource.h differ diff --git a/Image/AboutGUI.png b/Image/AboutGUI.png index 359f8f1..ebafee9 100644 Binary files a/Image/AboutGUI.png and b/Image/AboutGUI.png differ diff --git a/Image/GameTest.png b/Image/GameTest.png index b862f0c..50c4c47 100644 Binary files a/Image/GameTest.png and b/Image/GameTest.png differ diff --git a/Image/InfoGUI.png b/Image/InfoGUI.png index 63f20c9..f4afcae 100644 Binary files a/Image/InfoGUI.png and b/Image/InfoGUI.png differ diff --git a/Image/MainGUI.png b/Image/MainGUI.png index bf709d9..0b3e9bc 100644 Binary files a/Image/MainGUI.png and b/Image/MainGUI.png differ diff --git a/README.md b/README.md index ecdf627..ba5df18 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,13 @@ PlantsVsZombies ~ GhTr *PersonGames Tools* [+]what *functions* r needed, pls click [here](https://github.com/Xcating/GhTrTool/issues) propose and **TRY** todo it as well as ***possible*** ### [#]修改 Modified -[+]修改了偏移,适配于GhTr.0.16m版本 +[+]修改了偏移,适配于GhTr.0.16n版本 -[+]Modify offset handling to support GhTr 0.16m version +[+]Modify offset handling to support GhTr 0.16n version ### [#]工具截图 Screenshot -[+]工具版本:0.11w +[+]工具版本:0.11x -[+]Tools Version: 0.11w +[+]Tools Version: 0.11x ![MainGUI](/Image/MainGUI.png "MainGUI") ![GameTest](/Image/GameTest.png "GameTest")