资讯动态

YimMenuV2 多语言支持实现教程:13 种会话语言伪装全解析

发布时间:2026/10/23 1:50:52 来源:尧图企业网站定制
YimMenuV2 多语言支持实现教程13 种会话语言伪装全解析【免费下载链接】YimMenuV2Experimental menu for GTA 5: Enhanced项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenuV2YimMenuV2 是一款面向 GTA 5: Enhanced 的模组菜单以 DLL 形式注入游戏进程提供刷车、刷钱、会话控制等功能。它的多语言支持i18n和网站教程里那种 UI 翻译完全是两回事核心能力是让玩家在 GTA Online 的匹配流程里从 13 种语言中挑选一个会话语言让匹配系统优先为你找到说该语言的玩家。下面把这条链路从数据表、数据结构、Hook 拦截到 UI 接入拆开讲清楚。这个项目的多语言场景长什么样先说痛点GTA Online 的会话有语言属性写进匹配请求的MatchmakingAttributes结构体里。原版游戏只按客户端自身设置决定这个值玩家没法主动选择我要进一个简体中文会话或我要进一个日语会话。YimMenuV2 在 Network 子菜单里补了这个缺口一个 Spoof Language 开关加一个 13 项的语言下拉框覆盖 English、French、German 直到 Chinese (Simplified) 等语言。需要说明的是菜单界面本身没有做界面翻译——所有标签都是硬编码英文。这是注入类工具常见的取舍用户规模有限、界面文本量小搭一套完整 i18n 的投入产出比不高所以项目把多语言的精力花在了更实际的会话语言伪装上。整体思路Command 承载数据Hook 承载执行整个方案分成两层理解这个分层是读懂后面所有代码的前提数据层语言选项被定义成项目通用的ListCommand一种命令对象带 name、label、description 和 int 型状态值负责选了什么以及记住选了什么。执行层游戏在创建、更新、应答会话匹配时各有一个函数出口项目用 Detour Hook 把这三个出口都拦下来把选中的语言值写进发出去的匹配属性里。数据层和执行层只靠一个开关命令的名字耦合互不感知。这种状态与生效时机分离的写法是这个项目所有功能的公共骨架。13 种语言表与 ListCommand 数据模型语言清单是一张游戏内部枚举值 界面显示名的映射表定义在 CustomMatchmaking.cpp 里static std::vectorstd::pairint, const char* g_LanguageTypes { {0, English}, {1, French}, {2, German}, {3, Italian}, {4, Spanish (Spain)}, {5, Portuguese (Brazil)}, {6, Polish}, {7, Russian}, {8, Korean}, {9, Chinese (Traditional)}, {10, Japanese}, {11, Spanish (Mexico)}, {12, Chinese (Simplified)}, }; ListCommand _Language{mmlanguage, Language, The language to spoof the session to, g_LanguageTypes};这里有个关键的类型选择pair 里存的是int而不是字符串。int 是游戏匹配协议里的枚举值const char*只给 ImGui 下拉框显示用。两者解耦后UI 文案随便改都不会碰协议值。ListCommand的状态就是一个 int选中后由 ListCommand.hpp 里的SaveState/LoadState以 JSON 数字形式持久化——重启游戏后你选的语言还在。伪装值如何写进匹配属性执行层的全部逻辑集中在PatchMatchmakingAttrs一个函数里static void PatchMatchmakingAttrs(MatchmakingAttributes* attrs) { if (Features::_SpoofRegionType.GetState()) attrs-m_ParamValues[4] Features::_RegionType.GetState(); if (Features::_SpoofLanguage.GetState()) attrs-m_ParamValues[3] Features::_Language.GetState(); if (Features::_SpoofPlayerCount.GetState()) attrs-m_ParamValues[2] Features::_PlayerCount.GetState(); }注意m_ParamValues是裸下标写入3 是语言、4 是区域、2 是玩家数。这个偏移来自 MatchmakingAttributes.hpp 对游戏结构体的逆向文件末尾用static_assert(sizeof(MatchmakingAttributes) 0x10C)锁住了结构体大小——一旦游戏更新导致布局变化编译期就会报警。Advertise 与 Update两个主出口游戏广播会话advertise和周期性刷新update时都会携带匹配属性。项目在 MatchmakingAdvertise.cpp 这类钩子里先调CustomMatchmaking::OnAdvertise完成补丁写入再放行原函数bool Matchmaking::MatchmakingAdvertise(int profile_index, int num_slots, int available_slots, MatchmakingAttributes* data, ...) { if (!CustomMatchmaking::OnAdvertise(num_slots, available_slots, info, data, out_id, status)) return true; return BaseHook::GetMatchmaking::MatchmakingAdvertise, ...()-Original()( profile_index, num_slots, available_slots, data, ...); }钩子只做了先改参数、再透传这一件事不吞掉原函数除非启用了多倍会话广播功能那条路径才需要接管整个任务状态机。Detail 响应容易漏掉的第三个出口还有一处藏得更深别的玩家客户端来查询你这个会话的详情时游戏会发一条 session detail 应答报文里面同样内嵌了MatchmakingAttributes。项目钩了MatchmakingSessionDetailSendResponse在报文发出去之前再跑一遍PatchMatchmakingAttrs。只改 advertise 不改这里的话伪装只对自己生效别人看到的还是原值——这类同构数据从多个出口流出的问题是伪装类功能最常见的翻车点。UI 接入开关打开才显示语言下拉框界面侧的接线在 Network.cpp 里只有三行auto srvSpoofLanguage std::make_sharedGroup(, 1); srvSpoofLanguage-AddItem(std::make_sharedBoolCommandItem(mmspooflanguage_J)); srvSpoofLanguage-AddItem(std::make_sharedConditionalItem( mmspooflanguage_J, std::make_sharedListCommandItem(mmlanguage_J, ##mmlanguage)));ConditionalItem监听mmspooflanguage开关为 true 时才绘制下拉框避免用户看到一堆没启用的死控件_J后缀是把命令名做一次 Joaat 哈希Rage 引擎沿用的字符串哈希UI 和命令定义之间靠哈希值而非指针绑定编译期就能防拼写错误。下拉框的绘制在ListCommandItem::Draw()里用ImGui::BeginCombo实现有个小细节控件宽度不是定死的而是遍历选项找出最长字符串后CalcTextSize加 40px 边距。13 个语言名里Portuguese (Brazil)最长如果不做这个计算短名字的列表会把长名字截断。容易踩的坑与细节⚠️ 几个读代码时容易忽略的点客户端伪装 vs 服务端伪装的区分。Network 菜单里 Matchmaking (Client) 和 Matchmaking (Server) 是两个组。Client 侧的spoofmmregion是LoopedCommand启用时先存旧值之后每个游戏 tick 覆写*Pointers.RegionCode禁用时还原Server 侧的mmspooflanguage走的是报文补丁。前者改的是本地内存后者改的是发出去的字节手段完全不同不要混为一谈。持久化只存 int。语言选择在 JSON 里就是一个数字列表本身不入库。这意味着如果后续版本给g_LanguageTypes调整了顺序比如把 index 3 从 Italian 换成别的老配置会静默变成错误语言——这类存值不存名的持久化方案在枚举变更时天然有坑。菜单 UI 的字体是内嵌的。Fonts.hpp里MainFont约 77KB和IconFont约 1MB是编译进二进制的字节数组不含 CJK 字形。设置页只开放了FontGlobalScale缩放0.5–2.0 倍没有任何换字体入口。这也解释了为什么界面不翻译想支持中文界面光有翻译字符串表没用字体管线得先动。可以搬到自己项目的两点这套实现里真正通用的不是 GTA 相关的部分而是两个模式一是命令对象 状态 持久化 UI 标签的统一抽象任何需要选项 记住选项 可选显示的功能都能套用YimMenuV2 里颜色、浮点、向量命令全是同一套骨架二是多出口一致性——只要一份数据会从 N 个函数流出去补丁就得打 N 次少打一次就是一次静默失效。反过来说如果你做的是需要真正 UI i18n 的项目比如 Web 或桌面应用YimMenuV2 恰好提供了反面参照在动手写翻译表之前先确认字体能不能渲染目标文字、文本控件宽度会不会被长文案撑爆这两件事在这个项目里分别对应内嵌字体和CalcTextSize取最长项的做法顺序颠倒了会返工。【免费下载链接】YimMenuV2Experimental menu for GTA 5: Enhanced项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenuV2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑