You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

加载INI文件致GTA5崩溃,求C++武器布局脚本修复方案

GTA5自定义武器布局加载崩溃问题修复方案

从你提供的调试信息、代码和INI文件来看,崩溃的直接原因是字符串转整数时抛出的std::invalid_argument异常,结合细节分析,核心问题有三点:十六进制字符串解析失败、64位Hash被截断、遍历不存在的组件键引发异常。以下是分步修复方案:


核心问题分析

  1. 十六进制字符串解析失败:保存时你将武器/组件Hash转成了0x13532244这类十六进制字符串写入INI,但加载时用std::stoi默认按十进制解析,遇到0x前缀直接抛出异常。
  2. 64位武器Hash截断:武器Hash是__int64(64位)类型,但保存时强行转成int(32位),导致高位数据丢失,加载后得到无效Hash。
  3. 无效键读取引发异常:遍历全部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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:23:08