ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RetroArch libretro 核心选项 API 实战指南:从 v0/v1 升级到 v2 分类与多语言支持

RetroArch libretro 核心选项 API 实战指南:从 v0/v1 升级到 v2 分类与多语言支持 RetroArch libretro 核心选项 API 实战指南从 v0/v1 升级到 v2 分类与多语言支持【免费下载链接】RetroArchCross-platform, sophisticated frontend for the libretro API. Licensed GPLv3.项目地址: https://gitcode.com/GitHub_Trending/re/RetroArch本篇指南以libretro-common/samples/core_options/README.md为核心系统讲解如何为 libretro core 接入增强版核心选项core options v1与带分类功能的 v2 接口。你将掌握模板文件的复制与改造、libretro_set_core_options()的注册时机、多语言翻译的组织方式、在不支持新 API 的前端上隐藏选项以及如何通过 v2 分类机制整理高级设置同时结合仓库中的示例源码与libretro.h定义理解其底层协商与降级逻辑。背景核心选项的三代接口在 libretro 生态中核心选项core options是 core 向前端如 RetroArch暴露可配置参数的标准途径。libretro-common/include/libretro.h中定义了三条相关环境调用构成三代接口版本环境调用宏值特点v0RETRO_ENVIRONMENT_SET_VARIABLES16最古老的接口把每个选项序列化为desc; default\|val2\|val3形式的字符串数组struct retro_variable已标记 deprecatedv1RETRO_ENVIRONMENT_SET_CORE_OPTIONS/_INTL53结构化定义struct retro_core_option_definition支持子标签sublabel与国际化v2RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2/_INTL—在 v1 基础上新增选项分类categories官方推荐新代码使用libretro.h明确建议Prefer usingRETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2for new code, as it offers more features such as categories and translation但核心也应在旧前端上回退到 v1、v0。本文介绍的正是一套完整的、自包含的降级方案模板。一、为 core 添加增强版核心选项v1libretro-common/samples/core_options/README.md给出了接入 v1 接口的五个基本步骤模板位于 example_default/将example_default/libretro_core_options.h复制到libretro.c/.cpp所在目录将example_default/libretro_core_options_intl.h复制到同一目录在libretro.c/.cpp中加入#include libretro_core_options.h把原有的RETRO_ENVIRONMENT_SET_VARIABLES调用替换为libretro_set_core_options(retro_environment_t environ_cb)打开libretro_core_options.h用实际需要的全部核心选项填充option_defs_us结构数组。关于注册时机README 特别强调libretro_set_core_options()应尽早调用——理想位置是retro_set_environment()内部最迟不得晚于retro_load_game()。这与模板源码注释Should be called as early as possible - ideally insideretro_set_environment(), and no later thanretro_load_game()完全一致。1.1 option_defs_us 结构字段详解模板中option_defs_us是struct retro_core_option_definition数组结构定义见 libretro.h包含key、desc、info、values[RETRO_NUM_CORE_OPTION_VALUES_MAX]、default_value五个字段数组以全零哨兵项{ NULL, NULL, NULL, {{0}}, NULL }结尾。模板给出了三种典型写法struct retro_core_option_definition option_defs_us[] { { mycore_region, /* key选项名序列化用 */ Console Region, /* description显示标签 */ Specify which region the system is from., /* sublabelinfo补充说明 */ { { auto, Auto }, /* value_1, value_1_label */ { ntsc-j, Japan }, /* value_2, value_2_label */ { ntsc-u, America }, /* value_3, value_3_label */ { pal, Europe }, /* value_4, value_4_label */ { NULL, NULL }, /* 哨兵结束 values */ }, auto /* default_value必须与某个 value 一致 */ }, { mycore_video_scale, Video Scale, Set internal video scale factor., { { 1x, NULL }, /* 值本身可读如数字时value_label 置 NULL */ { 2x, NULL }, { 3x, NULL }, { 4x, NULL }, { NULL, NULL }, }, 3x }, { mycore_overclock, Reduce Slowdown, Enable CPU overclock (unsafe)., { { enabled, NULL }, /* 值为 enabled/disabled 时value_label 置 NULL */ { disabled, NULL }, { NULL, NULL }, }, disabled }, { NULL, NULL, NULL, {{0}}, NULL }, /* 数组结束哨兵 */ };从 libretro.h 的注释可以提炼出如下约束key选项唯一标识前端序列化、RETRO_ENVIRONMENT_GET_VARIABLE查询均以它为准建议形如mycore_xxxvalue 与 labelvalue是实际写入配置的字符串label是显示文本。当 value 本身具备可读性数字、enabled/disabled 等时label 应置NULLdefault_value必须等于values数组中的某个 value否则libretro.h声明该选项will be ignored上限单个选项最多RETRO_NUM_CORE_OPTION_VALUES_MAX值为 128个取值哨兵定义数组与 values 数组都必须以 NULL 结尾前端据此确定边界。二、模板底层实现剖析版本协商与三级降级libretro_set_core_options()的实现被有意放在头文件内static INLINE注释说明这是为了避免额外增加 .c 文件让 core 开发者接入成本尽可能低。其核心逻辑在 example_default/libretro_core_options.h 中可分为三段2.1 探测前端支持的核心选项版本unsigned version 0; if (!environ_cb) return; if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, version) (version 1))通过RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION宏值 52见 libretro.h查询前端版本。模板历史注释表明v1.2 起判断条件从 1放宽为 1以兼容未来版本。2.2 v1 路径优先使用国际化接口struct retro_core_options_intl core_options_intl; unsigned language 0; core_options_intl.us option_defs_us; /* 英文默认定义 */ core_options_intl.local NULL; /* 本地化定义默认无 */ if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, language) (language RETRO_LANGUAGE_LAST) (language ! RETRO_LANGUAGE_ENGLISH)) core_options_intl.local option_defs_intl[language]; environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, core_options_intl);这段代码的关键设计也是 README默认语言注释的落地实现option_defs_us作为兜底当前端语言不是英文且option_defs_intl[language]对应的语言表存在时才把local指向该语言定义若前端语言不可用、或某语言表缺失前端会自动回退到us表编译期定义了HAVE_NO_LANGEXTRA时则直接走无翻译路径RETRO_ENVIRONMENT_SET_CORE_OPTIONS。2.3 v0 回退动态拼接字符串当version 1旧前端模板会动态构造struct retro_variable数组其字符串格式为desc; default_value|value2|value3...实现要点对应模板第 185-266 行先扫描option_defs_us统计选项数量并分配内存对每个选项先定位default_value在 values 中的下标strcmp匹配strcat时默认值排在最前其后用|分隔其余值所有分配均带goto error释放路径保证失败时无内存泄漏。这正是 v0 接口的限制它没有 label、sublabel、分类等概念因此模板在降级时只能尽力保留选项名 描述; 默认值|可选值的信息。理解这段代码有助于排查为什么旧前端上选项显示格式奇怪的问题。三、添加核心选项翻译README 给出了添加翻译的三个步骤以example_translation/中的法语翻译option_defs_fr为范例把libretro_core_options.h中option_defs_us的内容复制到libretro_core_options_intl.h构成带对应语言后缀的新结构数组如option_defs_fr翻译所有人类可读字符串desc、sublabel、value_labelkey 与 value 必须与英文表保持一致把新数组挂到libretro_core_options.h的option_defs_intl[RETRO_LANGUAGE_LAST]数组中对应语言索引位置。option_defs_intl数组下标与RETRO_LANGUAGE_*枚举严格一一对应英文、日文、法文、西文、德文……共 30 项未提供的语言保持NULL。默认语言表英文承担双重兜底职责既在前端语言不可用时使用也用于填补某语言表中缺失的条目。3.1 法语翻译示例的关键规则以 example_translation/libretro_core_options_intl.h 为例struct retro_core_option_definition option_defs_fr[] { { mycore_region, /* key 必须与 option_defs_us 一致 */ Région de la console, /* 已翻译的 description */ Spécifiez la région dorigine du système., /* 已翻译的 sublabel */ { { auto, Auto }, /* value 必须与英文表一致 */ { ntsc-j, Japon }, /* 只翻译 value_label */ { ntsc-u, Amérique }, { pal, LEurope }, { NULL, NULL }, }, NULL /* default_value 可为 NULL * 由前端从英文表继承 */ }, { NULL, NULL, NULL, {{0}}, NULL }, };要点归纳key 与 value 不翻译它们是序列化/持久化契约翻译 value 会导致配置读写错乱default_value 可省略置 NULL前端会回退到英文表的默认值数字类取值如1x/2x无需翻译时可写{ NULL, NULL }占位从英文表继承见模板中mycore_video_scale的法语条目。3.2 BOM、c89 与 HAVE_NO_LANGEXTRA 的限制README 特别给出了一条硬性约束翻译文件使用 UTF-8 字符并必须携带 BOM 标记而 BOM 与 c89 构建不兼容。因此进行 c89 构建时必须定义HAVE_NO_LANGEXTRA如-DHAVE_NO_LANGEXTRA这会禁用全部翻译libretro_core_options_intl.h头部还针对 MSVC 2010-2013 做了兼容处理#pragma execution_character_set(utf-8)与关闭 4566 警告模板版本注释显示该机制自 1.3 引入目的是fix for MSVC 2010-2013。四、在不支持新 API 的前端上隐藏选项v1 接口允许 core 动态显示/隐藏选项但对旧前端仅 v0没有对应能力。一个常见场景是创建显示高级设置类开关选项其本身依赖 v1 才能工作在旧前端上应整体隐藏。方案是改造libretro_set_core_options()在构造 v0 变量数组时跳过特定 key。example_hide_option/ 演示了该做法option_defs_us中新增mycore_show_speedhacks开关并在 v0 降级路径的循环中加入/* Skip options that are irrelevant when using the * old style core options interface */ if (strcmp(key, mycore_show_speedhacks) 0) continue;注释明确说明每需要省略一个选项就追加一个strcmp()比较。需要注意配套细节v1/v2 路径不受影响——该选项会在新前端上正常显示并发挥显示/隐藏高级项的作用模板注释提醒虽然数组按全部选项分配了空间但跳过项对应的values_buf[i]保持NULL且变量数组通过独立的option_index游标紧凑填充避免空洞。任何需要此能力的 core应直接以example_hide_option/libretro_core_options.h为模板替代example_default版本。五、v2 分类给选项分组收纳核心选项 v2 为选项引入了分类category机制支持分类的前端会把同分类选项显示在主选项菜单的子菜单/分区中从而减少视觉杂乱或在无需显示开关的前提下收纳高级设置。模板见 example_categories/。5.1 新增的数据结构v2 使用struct retro_core_option_v2_definition字段比 v1 多了categorised描述与 category key与分类表struct retro_core_option_v2_categorystruct retro_core_option_v2_category option_cats_us[] { { video, /* key分类名须被选项引用 */ Video, /* 分类显示名 */ Configure display options. /* 分类子标签 */ }, { hacks, Advanced, Options affecting low-level emulation performance and accuracy. }, { NULL, NULL, NULL }, /* 结束哨兵 */ }; struct retro_core_option_v2_definition option_defs_us[] { { mycore_video_scale, Video Scale, /* description无分类支持时用 Video 前缀模拟层级 */ Scale, /* categorised description有分类支持时在 Video 子菜单内显示 */ Set internal video scale factor., NULL, /* categorised sublabel可为 NULL回退普通 sublabel */ video, /* category key必须匹配 option_cats_us 中的某个 key */ { { 1x, NULL }, { 2x, NULL }, { 3x, NULL }, { 4x, NULL }, { NULL, NULL }, }, 3x }, { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }, };设计要点category key 双向约束选项的category_key必须能在option_cats_us中找到为NULL/空则选项保持无分类双描述机制desc与info用于无分类前端可用Video Scale前缀模拟层级desc_categorized/info_categorized用于有分类前端显示为子菜单内的简洁文案后者为 NULL 时回退前者分类表与定义表最后都以全 NULL 哨兵结束。5.2 categories_supported 输出参数与三级降级v2 模板的libretro_set_core_options()签名多了一个输出参数static INLINE void libretro_set_core_options( retro_environment_t environ_cb, bool *categories_supported)核心逻辑见 example_categories/libretro_core_options.h初始化*categories_supported false查询版本version 2时通过RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL或_V2注册并把环境调用返回值写入categories_supported——core 可据此决定是否选择性隐藏/重排选项否则降级把 v2 定义数组逐字段复制为struct retro_core_option_definitionv1 数组values 需逐个拷贝Values must be copied individually...再走SET_CORE_OPTIONS_INTL连 v1 也不支持version 1时降级到与 v1 模板相同的 v0 字符串拼接路径所有临时分配在error:标签处统一释放。由此一份 v2 定义即可自动覆盖 v2 / v1 / v0 三代前端这与libretro.h关于core 应同时支持版本 2、1 和 0的要求相吻合。六、翻译工作流与 Crowdin 自动化example_translation/还附带一套与 intl/ 配合的翻译工程化方案其使用说明见 instructions.txt前置条件core 须 libretro 合规libretro_core_options.h英文文本与libretro_core_options_intl.h已有翻译同目录存在无任何翻译时libretro_core_options_intl.h允许为空文件脚本不支持宏展开或运行时填充的文本——这些文本不会被纳入可翻译范围确认libretro_core_options.h中#ifdef HAVE_LANGEXTRA/#ifndef HAVE_NO_LANGEXTRA预处理指令存在且正确用于在受限平台如内存紧张上去掉多余语言引用检查options_intl或 v2 的options_intl是否正确引用了 intl 选项否则翻译不会生效。Crowdin 同步接入将intl目录与.github工作流crowdin_prep.yml、crowdin_translate.yml放入仓库根目录可运行intl/activate.py自动定位libretro_core_options.h并识别 core 名称填充占位符但必须人工复核结果crowdin_prep.yml需替换libretro_core_options.h的完整路径2 处与CORE_NAME并确认监听分支正确——只有该分支上的文件变更才会触发上传crowdin_translate.yml需替换定时同步的分钟/小时0-59 0-23脚本会生成随机时间避免同时刻请求过载、CORE_NAME与libretro_core_options_intl.h的完整路径2 处通过 Pull Request 向 Crowdin 项目管理申请 API 密钥并在 GitHub 仓库创建名为CROWDIN_API_KEY的 Actions secret手动运行一次 Crowdin Translations Initial Setup 上传源文本与既有翻译切勿重复运行可能污染尚未合入仓库的最新翻译之后建议手动执行一次 Crowdin Translation Sync 验证流程遇Permission to repository denied时需配置 GITHUB_TOKEN 权限对 Crowdin 项目经理为每个 core 单独创建 access tokenProjects 读Source files strings 读写Translations 读写可选 Translation status 读私密交付给 core 开发者配置完成后删除不得公开或明文长期保存。intl/目录还提供了core_option_regex.py、v1_to_v2_converter.py、core_option_translation.py、crowdin_*.py等脚本可用于正则校验选项定义、v1 到 v2 的机械转换以及 Crowdin 上传/下载流水线可直接复用。七、模板速查与仓库证据场景使用模板关键位置基础 v1 接入example_default/libretro_core_options.h旧前端隐藏选项example_hide_option/strcmp(key, mycore_show_speedhacks)跳过逻辑法语翻译演示example_translation/libretro_core_options_intl.hv2 分类 三级降级example_categories/libretro_core_options.hCrowdin 自动化example_translation/intl/instructions.txt底层契约均定义于 libretro.hretro_core_option_value、retro_core_option_definition、retro_core_options_intl、retro_core_option_v2_category、retro_core_option_v2_definition、retro_core_options_v2(_intl)等结构体以及RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION52、RETRO_ENVIRONMENT_SET_CORE_OPTIONS53等宏。各模板头部注释中的版本历史1.0 → 1.1 → 1.2 → 1.3 → 2.0完整记录了接口演进轨迹是理解兼容性策略的第一手资料。结语从 v0 的字符串拼接到 v1 的结构化定义与国际化再到 v2 的分类收纳核心选项接口的每一次演进都旨在降低 core 开发者负担、改善前端展示效果。以上四套模板覆盖了绝大多数 core 的需求默认场景用example_default需要隐藏选项用example_hide_option需要分类用example_categories其内置的三级降级已兼容全部前端需要多语言则配合intl/脚本与 Crowdin 实现全自动翻译流水线。接入时牢记两条铁律libretro_set_core_options()尽早注册retro_set_environment()内最佳翻译文件中 key 与 value 永不翻译。【免费下载链接】RetroArchCross-platform, sophisticated frontend for the libretro API. Licensed GPLv3.项目地址: https://gitcode.com/GitHub_Trending/re/RetroArch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表