加载INI文件致GTA5崩溃,求C++武器布局脚本修复方案
GTA5自定义武器布局加载崩溃问题修复方案
从你提供的调试信息、代码和INI文件来看,崩溃的直接原因是字符串转整数时抛出的std::invalid_argument异常,结合细节分析,核心问题有三点:十六进制字符串解析失败、64位Hash被截断、遍历不存在的组件键引发异常。以下是分步修复方案:
核心问题分析
- 十六进制字符串解析失败:保存时你将武器/组件Hash转成了
0x13532244这类十六进制字符串写入INI,但加载时用std::stoi默认按十进制解析,遇到0x前缀直接抛出异常。 - 64位武器Hash截断:武器Hash是
__int64(64位)类型,但保存时强行转成int(32位),导致高位数据丢失,加载后得到无效Hash。 - 无效键读取引发异常:遍历全部551个组件时,对INI中不存在的键,你的
Ini类返回"NULL",调用std::stoi("NULL")直接抛出异常。
修复步骤
1. 重构Ini类,支持十六进制读写与异常处理
修改Ini类,添加专门的64/32位Hash读写方法,同时处理键不存在的情况:
class Ini { private: std::string inifile; public: Ini(std::string file) { this->inifile = file; } void WriteString(std::string string, std::string app, std::string key) { WritePrivateProfileStringA(app.c_str(), key.c_str(), string.c_str(), this->inifile.c_str()); } std::string GetString(std::string app, std::string key) { char buf[256]; // 扩大缓冲区适配64位Hash GetPrivateProfileStringA(app.c_str(), key.c_str(), "", buf, sizeof(buf), this->inifile.c_str()); return std::string(buf); } // 写入64位Hash为十六进制字符串 void WriteUInt64(uint64_t value, std::string app, std::string key) { char buf[32]; sprintf(buf, "0x%llX", value); WriteString(buf, app, key); } // 写入32位Hash为十六进制字符串 void WriteUInt32(uint32_t value, std::string app, std::string key) { char buf[32]; sprintf(buf, "0x%X", value); WriteString(buf, app, key); } // 解析十六进制/十进制字符串为64位整数,无效返回0 uint64_t GetUInt64(std::string app, std::string key) { std::string str = GetString(app, key); if (str.empty()) return 0; try { return std::stoull(str, nullptr, 0); // 自动识别十六进制/十进制 } catch (...) { return 0; } } // 解析十六进制/十进制字符串为32位整数,无效返回0 uint32_t GetUInt32(std::string app, std::string key) { std::string str = GetString(app, key); if (str.empty()) return 0; try { return std::stoul(str, nullptr, 0); } catch (...) { return 0; } } };
2. 修复保存功能的Hash截断问题
修改SaveWeaponsLayout,用64位类型处理武器Hash,避免数据丢失:
void SaveWeaponsLayout() { Ini wpLayout(".\\Files\\Settings\\WeaponsLayout.ini"); Log::Msg("Reading Data for WeaponsLayout.ini!"); Player playerPed = PLAYER::PLAYER_PED_ID(); if (!ENTITY::IS_ENTITY_DEAD(playerPed)) { for (auto & wpID : weaponLayoutList) { uint64_t weapon = wpID.weaponHash; const char* wpName = wpID.WeaponName; if (WEAPON::HAS_PED_GOT_WEAPON(playerPed, weapon, 0)) { wpLayout.WriteUInt64(weapon, wpName, "WEAPONHASH"); for (auto & wpCompID : weaponComponentList) { uint32_t weaponComp = wpCompID.weaponCompHash; const char* wpCompName = wpCompID.weaponComponent; if (WEAPON::HAS_PED_GOT_WEAPON_COMPONENT(playerPed, weapon, weaponComp)) { wpLayout.WriteUInt32(weaponComp, wpName, wpCompName); } } } } } Log::Msg("Files WeaponsLayout.ini created!"); Notifications::MessageCentre6000("~p~Saved~s~: Weapons Layout"); }
3. 修复加载功能的异常逻辑
修改LoadWeaponsLayout,跳过无效Hash和不存在的组件键,同时确保武器加载完成后再添加组件:
void LoadWeaponsLayout() { Log::Msg("Files reading WeaponsLayout.ini!"); Ini wpLayout(".\\Files\\Settings\\WeaponsLayout.ini"); Player playerPed = PLAYER::PLAYER_PED_ID(); if (!ENTITY::IS_ENTITY_DEAD(playerPed)) { // 可选:清空现有武器避免冲突 WEAPON::REMOVE_ALL_PED_WEAPONS(playerPed, true); for (auto & wpID : weaponLayoutList) { const char* wpName = wpID.WeaponName; uint64_t weaponX = wpLayout.GetUInt64(wpName, "WEAPONHASH"); if (weaponX == 0) continue; // 跳过无效武器 WEAPON::GIVE_DELAYED_WEAPON_TO_PED(playerPed, weaponX, 9999, 0); WAIT(100); // 等待武器加载完成 for (auto & wpCompID : weaponComponentList) { const char* wpCompoName = wpCompID.weaponComponent; uint32_t weaponComp = wpLayout.GetUInt32(wpName, wpCompoName); if (weaponComp == 0) continue; // 跳过不存在的组件 if (WEAPON::DOES_WEAPON_TAKE_WEAPON_COMPONENT(weaponX, weaponComp)) { WEAPON::GIVE_WEAPON_COMPONENT_TO_PED(playerPed, weaponX, weaponComp); WAIT(0); } } } } Log::Msg("Files WeaponsLayout.ini loaded!"); Notifications::MessageCentre4000("~p~Loaded~s~: Weapons Layout"); }
4. 修正数据结构的类型匹配
确保武器/组件列表的Hash类型与读写逻辑一致:
// 武器列表用uint64_t存储Hash,字面量加ULL后缀 static struct wpList { uint64_t weaponHash; const char* WeaponName; }; static std::vector<wpList> weaponLayoutList{ { 0xFBAB5776ULL, "Parachute" }, { 0x99B507EAULL, "Knife" }, ... }; // 组件列表保持uint32_t static struct wpCompList { uint32_t weaponCompHash; const char* weaponComponent; }; static std::vector<wpCompList> weaponComponentList{ { 0x75414F30, "COMPONENT_AT_RAILCOVER_01" }, ... };
额外调试建议
- 添加日志输出跟踪武器和组件的加载情况,方便定位问题:
Log::Msg("Loaded weapon: %s (Hash: 0x%llX)", wpName, weaponX); - 测试时可以先只加载单个武器和少量组件,逐步排查问题。
内容的提问来源于stack exchange,提问作者Jessy-G
相关产品推荐
相关产品推荐

