Puerts插件开发指南:自定义TypeScript绑定生成器实现
你是否还在为手动编写TypeScript绑定代码而烦恼?是否希望有更灵活的方式来控制UE或Unity项目中的TypeScript类型定义生成?本文将带你从零开始实现一个自定义TypeScript绑定生成器,让TypeScript与原生代码的交互变得更加高效可控。
读完本文后,你将能够:
- 理解Puerts绑定生成器的工作原理
- 配置自定义的类型绑定规则
- 实现函数过滤与属性扩展
- 优化生成的TypeScript声明文件
绑定生成器基础原理
Puerts通过静态绑定生成(StaticWrapper)技术,将C#/C++接口转换为TypeScript可调用的格式,避免了运行时反射带来的性能开销。默认情况下,Puerts会根据预设规则生成绑定代码,但在实际开发中,我们常常需要根据项目需求自定义生成逻辑。
绑定生成器的核心工作流程包括:
- 扫描指定的C#/C++类型
- 根据配置规则过滤和转换
- 生成静态调用包装类(StaticWrapper)
- 输出TypeScript声明文件(.d.ts)
相关实现代码位于unreal/Puerts/Source/DeclarationGenerator/目录,该模块负责解析原生类型并生成对应的TypeScript定义。
配置基础:绑定规则定义
所有绑定配置类都需要放置在Editor目录下,并使用[Configure]标签标记。最基础的配置包括指定需要绑定的类型列表,这通过[Binding]属性实现。
[Configure]
public class GameplayCfg
{
[Binding]
static IEnumerable<Type> Bindings
{
get
{
return new List<Type>()
{
typeof(UnityEngine.GameObject),
typeof(UnityEngine.Transform),
typeof(MyGame.PlayerController)
};
}
}
}
上述代码会生成GameObject、Transform和自定义PlayerController的TypeScript绑定。完整的配置标签说明可参考doc/unity/zhcn/wrapper/all_attribute.md。
动态类型收集
对于大型项目,手动维护类型列表效率低下,可通过反射动态收集类型:
[Binding]
static IEnumerable<Type> Bindings
{
get
{
return Assembly.Load("Assembly-CSharp")
.GetTypes()
.Where(t => t.Namespace.StartsWith("MyGame") &&
t.GetCustomAttributes(typeof(ExportAttribute), false).Length > 0);
}
}
这种方式会自动收集所有标记了[Export]属性的自定义类型,极大减少了配置维护成本。
高级过滤:函数与属性定制
成员过滤
使用[Filter]标签可以精确控制哪些成员需要生成绑定。例如,我们可能希望隐藏某些内部方法:
[Filter]
static bool Filter(MemberInfo memberInfo)
{
// 排除以"Internal"开头的方法
if (memberInfo is MethodInfo method && method.Name.StartsWith("Internal"))
return false;
// 排除Editor专用属性
if (memberInfo is PropertyInfo prop && prop.Name == "EditorOnlyData")
return false;
return true;
}
详细的过滤规则配置可参考doc/unity/zhcn/wrapper/filter.md。
blittable类型优化
对于Vector3等 blittable 类型(内存布局连续的值类型),可启用内存拷贝优化,大幅减少GC开销:
[BlittableCopy]
static IEnumerable<Type> Blittables
{
get
{
return new List<Type>()
{
typeof(Vector3),
typeof(Quaternion),
typeof(Color)
};
}
}
启用此特性需要在项目中开启unsafe编译选项,具体配置方法见doc/unity/zhcn/wrapper/blittablecopy.md。
自定义TypeScript类型生成
类型名称映射
当原生类型名称与TypeScript习惯用法冲突时(如C#中的object类型),可通过扩展生成器实现名称映射。创建自定义生成器需要继承Puerts的ICustomCodeGenerator接口:
class TypeNameMapper implements ICustomCodeGenerator {
GenerateCode(type: TypeInfo): string {
// 将C#的"Object"映射为TypeScript的"any"
if (type.Name === "Object" && type.Namespace === "System") {
return "any";
}
// 保留默认生成逻辑
return null;
}
}
方法签名转换
对于重载方法,TypeScript不支持参数类型重载,需要生成不同名称的函数。可通过自定义生成器实现自动重命名:
class MethodOverloadHandler implements ICustomCodeGenerator {
GenerateCode(method: MethodInfo): string {
if (method.Overloads.Length > 1) {
// 为每个重载生成带参数类型后缀的方法名
const paramTypes = method.Parameters.map(p => p.Type.Name);
return `${method.Name}_${paramTypes.join('_')}`;
}
return null;
}
}
生成流程与调试
触发生成
在Unity中,通过菜单Tools/PuerTS/Generate Code手动触发生成;在UE中,可通过执行GenerateTypeScriptDeclarations命令。生成的TypeScript声明文件默认输出到项目的Content/Scripts目录。
调试技巧
- 开启生成日志:在配置类中添加
[LogLevel(LogLevel.Debug)]查看详细生成过程 - 检查临时文件:生成器会在Temp目录保留中间处理结果
- 使用
[Typing]标签:仅生成TypeScript声明而不生成静态包装,加快调试迭代
[Typing]
static IEnumerable<Type> Typings
{
get { return new List<Type> { typeof(MyDebugType) }; }
}
实战案例:网络模块绑定优化
假设我们有一个网络模块,需要将C#的网络消息类型转换为TypeScript接口,并自动添加序列化逻辑。
自定义属性标记
[AttributeUsage(AttributeTargets.Class)]
public class NetworkMessageAttribute : Attribute { }
[NetworkMessage]
public class LoginRequest
{
public string Username;
public string PasswordHash;
}
自定义生成器实现
class NetworkMessageGenerator implements ICustomCodeGenerator {
GenerateCode(type: TypeInfo): string {
if (!type.HasAttribute("NetworkMessage")) return null;
// 生成TypeScript接口
let code = `export interface ${type.Name} {\n`;
// 添加字段定义
type.Fields.forEach(field => {
code += ` ${field.Name}: ${ConvertType(field.Type)};\n`;
});
// 添加序列化方法
code += `\n toBytes(): Uint8Array {\n`;
code += ` const buffer = new ArrayBuffer(${CalculateSize(type)});\n`;
code += ` const view = new DataView(buffer);\n`;
// 字段序列化逻辑...
code += ` return new Uint8Array(buffer);\n }\n}`;
return code;
}
}
通过这种方式,我们实现了网络消息类型的自动转换与序列化代码生成,大幅减少了手动编写的工作量。
总结与扩展方向
自定义TypeScript绑定生成器是提升Puerts项目开发效率的关键技术。通过本文介绍的配置方法,你可以实现:
- 根据项目需求定制类型绑定规则
- 优化生成代码的性能与体积
- 自动生成重复性代码(如序列化、事件分发)
- 统一团队的代码规范与接口设计
未来可以进一步探索的方向:
- 实现基于注释的文档自动生成
- 添加类型验证与错误检查
- 开发可视化配置工具
希望本文能帮助你更好地掌握Puerts的高级用法,让TypeScript与游戏引擎的交互更加顺畅高效。如有任何问题,可参考官方文档doc/unity/zhcn/wrapper/wrapper.md或加入社区讨论获取支持。
记得点赞收藏本文,关注后续关于Puerts性能优化的进阶教程!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




