ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

PuerTS for Unity:Configure、Binding、Typing、BlittableCopy、Filter 配置标签完全指南

PuerTS for Unity:Configure、Binding、Typing、BlittableCopy、Filter 配置标签完全指南 PuerTS for UnityConfigure、Binding、Typing、BlittableCopy、Filter 配置标签完全指南【免费下载链接】puertsPUER(普洱) Typescript. Lets write your game in UE or Unity with TypeScript.项目地址: https://gitcode.com/GitHub_Trending/pu/puerts本文系统讲解 PuerTSUnity 端代码生成体系中的五个 C# 配置标签[Configure]、[Binding]、[Typing]、[BlittableCopy]、[Filter]。读完本文你能掌握如何在 Editor 目录下编写配置类、控制哪些类型生成 StaticWrapper 与 TypeScript 声明、如何过滤不可生成的成员、以及如何用 BlittableCopy 减少值类型跨语言传递的 GC并理解这些标签在生成器源码中的真实解析流程与菜单入口。一、配置标签在整个代码生成流程中的位置PuerTS 在 JS/TS 调用 C# 时默认通过反射按字符串查找类与函数并Invoke效率较低。为此 PuerTS 提供了 StaticWrapper 机制对预先声明好的类/函数生成可被 V8 直接调用的 C# 包装代码使后续调用绕过反射同时还能避免 IL2CPP 裁剪丢失接口并为这些接口生成index.d.ts声明供 TypeScript 侧import使用机制详见 生成StaticWrapper。所有配置必须放在Editor 目录下且须集中在一个打了[Configure]标签的类中。这一约定在配置标签定义文件的源码注释中同样被明确强调1、Binding、BlittableCopy、Filter 须放到一个打了 Configure 标签的类里 2、Binding、BlittableCopy、Filter 均用打了相应标签的属性来表示 3、Binding、BlittableCopy、Filter 配置须放到 Editor 目录下。见 Configure.cs 头部注释。之所以限定 Editor 目录是因为 StaticWrapper 的生成程序运行在 Editor 中会按编译时可见的 API 反射枚举成员若配置类进入 Runtime 程序集反而可能把 Editor 专有接口带入生成结果导致打包编译报错相关背景见 生成控制 (Filter)。五个标签的AttributeUsage约束在源码 Configure.cs 中定义得非常严格标签允许作用目标AttributeUsage作用[Configure]AttributeTargets.Class标记配置类本身[Binding]AttributeTargets.Property指定需要生成 StaticWrapper 的类型列表静态类 dts 声明[Typing]AttributeTargets.Property仅生成 dts 声明不生成静态包装类[BlittableCopy]AttributeTargets.Property指定走内存拷贝传递的 Blittable 值类型列表[Filter]AttributeTargets.Method标记过滤函数控制成员是否生成/是否允许调用二、[Configure]配置类的入口标记[Configure]是唯一作用于类的标签。生成器启动时会扫描当前AppDomain中所有程序集排除动态生成的ModuleBuilder程序集查找所有打了该标签的类型再把其内部的[Binding]/[Typing]/[BlittableCopy]属性与[Filter]方法收集起来。最小示例[Configure] public class ExamplesCfg { }一个空的[Configure]类是合法的——它只是配置容器的声明。真正的生效点在于类内部带标签的静态属性/方法下文逐一说明。三、[Binding]生成 StaticWrapper 的类型列表[Binding]用在静态属性上属性类型须是可枚举集合IEnumerable元素为目标Type。它产生两个效果生成静态类wrapperJS 调用时可静态调用不走反射加快调用速度生成 dts 声明在index.d.ts中写出函数/类的声明使 TS 侧import时能够找到。静态列表写法[Configure] public class ExamplesCfg { [Binding] static IEnumerableType Bindings { get { return new ListType() { typeof(GameObject), typeof(Component), }; } } }动态列表写法列表不要求写死可以运行时分析程序集动态构造。例如只绑定MyNamespace命名空间下的所有导出类型[Configure] public class ExamplesCfg { [Binding] static IEnumerableType Bindings { get { return (from type in Assembly.Load(Assembly-CSharp).GetExportedTypes() where type.Namespace MyNamespace select type); } } }源码级解析流程生成入口在 StaticWrapperMenu.cs 的GenerateStaticWrappersTo中流程为调用Puerts.Configure.GetConfigureByTags(new Liststring { typeof(BindingAttribute).ToString() })收集配置GetConfigureByTags见 Configure.cs遍历所有[Configure]类读取其中Static Public/NonPublic DeclaredOnly且类型可实现IEnumerable的属性将属性 getter 求值后逐项登记到以标签全名Puerts.BindingAttribute为键的字典中生成器取BindingAttribute对应的条目筛出Type并Distinct()若无任何类型直接输出警告[PuerTS] No types found with [Binding] attribute. Nothing to generate.并退出对每个类型生成包装代码逐个写出{ClassName}.cs最后生成RegisterInfo_Gen.cs注册信息与扩展方法信息StaticWrapperMenu.cs。由此可知两点实现事实[Binding]属性无论public还是非公开静态都会被读取列表求值发生在生成阶段因此动态 LINQ 写法是官方支持的源码直接对prop.GetValue(null, null) as IEnumerable迭代。四、[Typing]只生成 TS 声明不生成包装类[Typing]与[Binding]用法完全一致静态属性 IEnumerableType区别在于只面向 TS 调用场景仅在index.d.ts中生成声明不生成静态类因此 JS 侧调用仍走反射路径只是 TS 侧能拿到类型提示。源码中的注释直接写明这一语义——相比 Binding这标签仅生成ts声明Configure.cs。[Configure] public class ExamplesCfg { [Typing] static IEnumerableType Typings { get { // 静态或动态列表写法同 [Binding] } } }适用场景调用频次不高、不值得付出静态包装代码体积的类型但 TS 开发体验上仍需要声明。五、[BlittableCopy]用内存拷贝消除值类型 GCPuerTS 提供 C# 与 C 共享结构体内存的传递方式从 C# 往 JavaScript 传递 Blittable 值类型如Vector3时通过内存拷贝传递避免每次传递产生的装箱/GC。前提是需要开启 unsafe 编译选项详细说明见 BlittableCopy 内存优化。[Configure] public class ExamplesCfg { [Binding] static IEnumerableType Bindings { get { return new ListType() { typeof(Vector3), }; } } [BlittableCopy] static IEnumerableType Blittables { get { return new ListType() { // 打开这个可以优化Vector3的GC但需要开启unsafe编译 typeof(Vector3), }; } } }注意示例中[Binding]与[BlittableCopy]同时列出了Vector3前者保证生成可快速调用的静态包装与 dts 声明后者在其基础上把值传递切换为内存拷贝模式。源码定义处注释同样强调对 blittable 值类型通过内存拷贝传递需要开启 unsafe 编译选项Configure.cs。六、[Filter]控制成员级生成与访问权限[Filter]是唯一作用于方法的标签用于过滤会导致编译错误的成员典型如 Editor 专有接口如MonoBehaviour.runInEditMode权限控制——禁止某些成员被 JS 访问。最简形式布尔过滤返回true表示过滤掉不生成/不参与该标签对应的生成public class TestFilter { public void print() { Debug.Log(test Filter); } public void add(int a, int b) { Debug.Log(test add (a b)); } } [Configure] public class ExamplesCfg { [Binding] static IEnumerableType Bindings { get { return new ListType() { typeof(TestFilter), }; } } [Filter] static bool Filter(System.Reflection.MemberInfo memberInfo) { return memberInfo.DeclaringType.Name TestFilter memberInfo.Name print; } }上述例子中TestFilter的两个方法只有add会进入生成结果print被过滤。源码支持两种签名、两种返回值从生成器实现StaticWrapperMenu.cs可以确认[Filter]方法被反射收集后按参数个数与返回类型分派单参数签名static bool Filter(MemberInfo memberInfo)/static BindingMode Filter(MemberInfo memberInfo)双参数签名static bool Filter(FilterAction filterAction, MemberInfo mbi)/static BindingMode Filter(FilterAction filterAction, MemberInfo mbi)返回booltrue即过滤返回BindingModeBindingMode.DontBinding即不生成 StaticWrapper且 JS 侧获取该字段会得到undefinedBindingMode.FastBinding等同于不过滤。FilterAction枚举定义了过滤器所处的作用域Configure.csBindingMode 1普通成员绑定决策、MethodInInstructions 2il2cpp 全量生成时遍历方法指令搜索类型的场景、DisallowedType 3类型级禁用的决策。针对 il2cpp 场景的典型用法详见 生成控制 (Filter)[Filter] static bool GetFilterClass(FilterAction filterAction, MemberInfo mbi) { if (filterAction FilterAction.MethodInInstructions) return skipAssembles.Contains(mbi.DeclaringType.Assembly.GetName().Name); return false; }白名单模式默认禁止放行少数接口当禁用大部分、放行少数时可为默认模式做反转var env new JsEnv(); env.SetDefaultBindingMode(BindingMode.DontBinding)再配合 Filter 将需要放行的类型显式返回FastBinding例如使Vector3可用、其余保持禁止完整示例见 生成控制 (Filter) 权限控制一节。七、生成入口与配套菜单配置写好后在 Unity 菜单Tools/PuerTS下触发生成。从源码 UnityMenu.cs 可见菜单前缀常量PUERTS_MENU_PREFIX Tools/PuerTS其中与本文标签直接相关的入口包括Tools/PuerTS/Generate C# Static Wrappers—— 基于[Binding]配置生成 C# 静态包装即本文主体流程Tools/PuerTS/Generate il2cpp/Static Wrapper Mode与Reflection Mode—— il2cpp 打包场景下的两种生成策略Tools/PuerTS/Advanced/...—— 生成原生插件文件、扩展方法信息Extension Method Infos、Link.xml 等辅助产物Tools/PuerTS/Clear Generated Code—— 清理已生成代码。生成产物默认落在Assets/Gen/目录该目录可由同为[Configure]类内静态属性上的[CodeOutputDirectory]标签重定向Configure.cs 中GetCodeOutputDirectory返回配置值缺省为Application.dataPath /Gen/。对于项目中已存在的 C# 扩展方法把它加入[Binding]列表后生成器会在生成时遍历整个 assembly将扩展目标类的扩展函数一并塞入 StaticWrapperJS 侧即可直接调用另两种处理方式见 使用extension函数。这与源码中LoadExtensionMethodInfo()在生成流程里的调用相对应。八、配置速查与常见约束小结问题原因与解决配置不生效配置类未打[Configure]或没放在 Editor 目录标签写在了错误的目标上如把[Binding]用在方法上AttributeUsage不允许生成结果为空日志出现 No types found with [Binding] attribute说明[Binding]属性没有返回任何Type注意属性须为静态且实现IEnumerable打包后编译报错Editor 专有接口被生成进了包装代码用[Filter]过滤掉对应成员JS 调用某成员得到 undefined该成员被 Filter 返回了BindingMode.DontBinding开启 BlittableCopy 后编译失败未开启 unsafe 编译选项实践建议与 生成StaticWrapper 保持一致开发阶段可只依赖反射、不生成包装代码以控制代码内存在游戏发布或回归测试前对实际用到的接口做排查并生成 StaticWrapper兼顾防裁剪与类型声明完整性。【免费下载链接】puertsPUER(普洱) Typescript. Lets write your game in UE or Unity with TypeScript.项目地址: https://gitcode.com/GitHub_Trending/pu/puerts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表