意思是Unity无法加载PuerTS的Native Plugin,比如windows下的.dll
,macOS下的.dylib
或.bundle
,其它平台下的.a
、.so
等。
出现该问题的可能性如下:
- 你确实没有把PuerTS的Native Plugin放到Assets目录下
- Native Plugin的Import Setting,即平台设置,没有设置对。请在Unity里点击对应的文件设置好平台。或者你可以将官方demo项目里对应的meta文件拷过来用。
- Native Plugin所依赖的系统库不存在。Mac下可以使用
otool
、Linux下可以使用objdump
,Windows下可以使用Dependencies查看NativePlugin文件的依赖。查出来后自行补充安装即可。
相关issue:Tencent#941
PuerTS在加载js文件时没有能够找到对应的js文件,具体来说,是调用ILoader的FileExists
返回了false,或是调用IResolvableLoader的Resolve
时返回了空字符串或null。
如果遇到这个问题,先确认你使用的loader是DefaultLoader(即创建JsEnv时没有传任何参数)还是你自己编写的自定义Loader。然后检查这个Loader的FileExists
函数或是Resolve
函数,看看为什么会返回不正确的值。
如果你用js,可能是输错参数了。
如果你用typescript,可能是子类同名,但不同参数的函数覆盖了父类。以System.Text.Encoding.UTF8.GetBytes为例,你直接调用会报错。
System.Text.Encoding.UTF8.GetBytes("你好");
System.Text.Encoding.UTF8指向的对象System.Text.UTF8Encoding,有GetBytes的其它重载,按目前的实现找到当前类有同名函数就不再找基类导致的。这时候你可以手动指定下用其基类接口访问该对象。
Object.setPrototypeOf(System.Text.Encoding.UTF8, System.Text.Encoding.prototype);//只需要调用过一次即可。后续调用GetBytes都不用再调用。
System.Text.Encoding.UTF8.GetBytes("你好");
可能是没调用JsEnv.Tick
这是vscode,其它IDE的看各IDE的指引,按nodejs的调试来处理即可。
ts/js中调用require('./a/b')时,ILoader会被调用并传入字符串".../a/b.js"(相对rootPath的完整路径),你需要理解这字符串并(从文件/内存/网络等)加载好js文件并直接返回。而debugpath需要返回调试器可以理解的路径(比如js文件的绝对路径: D:/.../a/b.js),通过设置out string debuggpath参数返回,调试器后续根据这个文件路径来匹配文件上的断点。
Windows平台不区分文件大小写名称且使用反斜杠"\"代替"/"
你将一个js函数映射为一个delegate有时会报这错误,XXX就是要映射的delegate,可能的情况如下:
-
该delegate带了值类型参数或者返回值,解决办法:如果没有返回值,用JsEnv.UsingAction声明下,有返回值就用JsEnv.UsingFunc声明。关于做这项工作的必要性,可参见这个stackoverflow问题
-
参数数量超过4个,解决办法:官方目前只支持4个,如果有需要,可以依葫芦画瓢写更多的参数支持。
-
参数含ref,out的修饰,目前尚未支持,解决办法:填写issues来提需求
执行
sudo xattr -r -d com.apple.quarantine puerts.bundle
因为这些方法是编辑器独有的,可以通过filter过滤掉,filter使用参考使用手册
unity默认会进行代码剪裁,简而言之unity发现某引擎api,系统api没有被业务c#使用,就不编译倒cpp。 解决办法:1、对要调用的api生成wrap代码,这样c#里头就有了引用;2、通过link.xml告知unity别剪裁,link.xml的配置请参考unity官方文档。
往往是由于该方法/属性/字段是扩在条件编译里头,只在UNITY_EDITOR下有效,这时需要把这方法/属性/字段通过Filter标签过滤,之后重新执行代码生成并打包。(discussions说明)
默认打包后不再使用反射获取扩展函数, 可使用PUERTS_REFLECT_ALL_EXTENSION
宏来开启反射.(反射速度慢, 建议在任何时候都应该生成静态代码)
其实那C#对象并不为null,是UnityEngine.Object重载的==操作符。当一个对象被Destroy,未初始化等情况,obj == null返回true;GetComponent<XXX>()
如果组件不存在,Unity重载==的结果也会让其返回null。但这些C#对象并不为null,可以通过System.Object.ReferenceEquals(null, obj)来验证下。
对应这种情况,可以为UnityEngine.Object写一个扩展方法,需要判空的时候统一用它解决:
public static bool IsNull(this UnityEngine.Object o)
{
return o == null;
}
安装模块
npm install source-map-support --save-dev
然后执行如下代码:
puer.registerBuildinModule("path", {
dirname(path) {
return CS.System.IO.Path.GetDirectoryName(path);
},
resolve(dir, url) {
url = url.replace(/\\/g, "/");
while (url.startsWith("../")) {
dir = CS.System.IO.Path.GetDirectoryName(dir);
url = url.substr(3);
}
return CS.System.IO.Path.Combine(dir, url);
},
});
puer.registerBuildinModule("fs", {
existsSync(path) {
return CS.System.IO.File.Exists(path);
},
readFileSync(path) {
return CS.System.IO.File.ReadAllText(path);
},
});
(function () {
let global = this ?? globalThis;
global["Buffer"] = global["Buffer"] ?? {};
//使用inline-source-map模式, 需要额外安装buffer模块
//global["Buffer"] = global["Buffer"] ?? require("buffer").Buffer;
})();
require('source-map-support').install();
注: source-map-support是nodejs模块, 需要自定义path和fs模块.
将自定义模块加入external module
module.exports = {
// other...
/** 忽略编辑的第三方库 */
externals: {
csharp: "commonjs2 csharp",
puerts: "commonjs2 puerts",
path: "commonjs2 path",
fs: "commonjs2 fs",
}
};