语言 / Language: English
Super Mario Worker Project(GM8.2) 使用的 编码转换 DLL(32 位原生,无 .NET 依赖)。
基于 Windows API MultiByteToWideChar / WideCharToMultiByte 实现字符编码互转,
主要解决“旧版 GM8.0 关卡文本为 GB2312/GBK,新版 GM8.2 使用 UTF-8”的兼容问题:
读取旧关卡时用 GB2312 解码,保存新版时转成 UTF-8。
const char* __stdcall convert_encoding(
const char* input,
const char* from_encoding,
const char* to_encoding);把 input 从 from_encoding 转成 to_encoding 并返回结果字符串。
支持的编码名(大小写不敏感):
UTF-8/UTF8(65001)、GB2312(936)、GBK(936)、GB18030(54936)、ASCII(ACP)。
未知编码回退到 CP_ACP。
返回值是进程内静态堆缓冲,仅在下次调用本 DLL 任意字符串函数前有效 (见下方“内存与线程注意”)。
const char* __stdcall encoding_conv_version(); // 返回如 "1.1.0"double __stdcall convert_file_gb2312_to_utf8(const char* file_path);就地把 file_path 指向的文件从 GB2312 转成 UTF-8 写回(路径按 UTF-8 → UTF-16 转换后
用 CreateFileW 打开,可处理中文路径)。返回码含义:
| 返回值 | 含义 |
|---|---|
0.0 |
成功(或文件已是合法 UTF-8,跳过转换) |
-1.0 |
空路径 |
-2.0 |
文件打开失败 |
-3.0 |
文件大小为 0 或获取失败 |
-4.0 ~ -10.0 |
内存分配 / 读写 / 转码中间步骤失败(含内部错误码) |
double __stdcall is_cjk(const char* utf8_char); // 是 CJK(宽字符)返回 1.0,否则 0.0判断一个 UTF-8 字符是否为 CJK / 东亚宽字符(按 Unicode 码点区间判断,覆盖 CJK 统一表意、 扩展 A~H、假名、谚文、全角符号等)。用于逐字符判断排版宽度。
const char* __stdcall key_to_byte_string(const char* utf8_key);把 UTF-8 密钥字符串先转成 GB2312 字节,再把每个字节编码为 2 字节 UTF-8 序列
(U+00xx)。因为 GM8.2 把 char* 当作 UTF-8 读取,这样每个字节 b 会被 GM 解码成
ord() == b 的单字符,便于在 GML 侧做 XOR 密钥验证(与 script_text_crypt.gml 中的
40 元素密钥数组配合)。
- 所有导出函数均为
__stdcall,且通过.def以未修饰名导出 (如convert_encoding)。 - GameMaker 8.2 的
external_define默认调用约定即 stdcall,直接对接,无需额外参数。
convert_encoding/key_to_byte_string/encoding_conv_version返回的是同一个 进程内静态堆缓冲(HeapAlloc,按需扩容)。结果只在下一次调用同组函数前有效; 在 GM 中通常是“调用后立即使用 / 拷贝”,没有问题。- 该缓冲非每调用独立分配,因此不要在两个并发线程中交替调用这些函数 (GM 单机运行是单线程,实际无此问题)。
- Visual Studio 2022,工具集
v143。 - 目标平台 Win32(32 位) —— GameMaker 8.x 是 32 位进程。
- 无 .NET 依赖,纯原生 C++。
- 配置:Release。
- 产物:
EncodingConv.dll。
- 把编译出的
EncodingConv.dll复制到游戏可执行文件所在目录。 - 在 GML 中通过
external_define注册各导出函数(指明参数为string, 调用约定 stdcall),即可调用。
// 注册(只需一次,通常在初始化脚本)
conv_dll = "EncodingConv.dll"
f_conv = external_define(conv_dll, "convert_encoding", 0, 3, "s", "s", "s", "s")
f_ver = external_define(conv_dll, "encoding_conv_version", 0, 1, "s", "")
f_is_cjk = external_define(conv_dll, "is_cjk", 0, 1, "d", "s")
// 使用
utf8_text = external_call(f_conv, gb2312_text, "GB2312", "UTF-8")
show_message(external_call(f_ver))当前 encoding_conv_version() 返回 1.1.0。