-
Notifications
You must be signed in to change notification settings - Fork 805
Description
前置阅读 | Pre-reading
Puer的版本 | Puer Version
Master(>1.0.9)
UE的版本 | UE Version
5.6.1
发生在哪个平台 | Platform
Editor(win)
错误信息 | Error Message
以QuickJS作为后端的时候,创建一个蓝图并在其中定义一个和某个已有方法同名,但大小写不同的函数,例如SetForcedLODModel,这会导致和C++的UStaticMeshComponent::SetForcedLodModel同名,但大小写不同。
class StartupGameMode extends UE.GameModeBase {
override ReceiveBeginPlay(): void {
const bpPath = "/Game/BP_Test.BP_Test_C";
const bpClass = UE.Class.Load(bpPath);
const bpInstance = UE.GameplayStatics.BeginDeferredActorSpawnFromClass(
this,
bpClass,
null,
UE.ESpawnActorCollisionHandlingMethod.AlwaysSpawn
) as UE.Game.Data.BP_Test.BP_Test_C;
UE.GameplayStatics.FinishSpawningActor(bpInstance, undefined);
bpInstance.SetForcedLODModel();
}
}例如这里调用SetForcedLODModel,会提示函数找不到。似乎是因为SetForcedLODModel的调用在QuickJS中被转换成了SetForcedLodModel,然后QuickJs会使用SetForcedLodModel这个版本去调用蓝图的函数产生找不到的情况。
不确定是因为FName或者某个符号的转换的时候出现的问题。
关注了FAQ中关于打包后运行时报一些字段找不到的回答,但是这个情况是v8表现和quickjs不同。目前是跨BP,整个UE工程的所有FName相互之间都不能大小写冲突了。例如一个BP的某个函数的参数名和另外一个BP的函数名如果字母相同大小写不同也会出现问题,这样的限制会导致无法维护。另外是此现象只在quickjs的backend中出现,v8下没有问题。感觉有可能是代码中关于WITH_QUICKJS的宏导致。
问题重现 | Bug reproduce
构建任意蓝图,创建任意一个和已有符号(无论蓝图还是C++)同名但大小写不同的方法,例如SetForcedLODModel。
在JavaScript中创建这个对象并调用其方法。开启使用QuickJs并构建WIndows的包,执行会发现无法访问的错误:
[2025.11.19-04.06.46:833][ 0]Puerts: Error: (0x000001C7849F8F70) call StartupGameMode_C::ReceiveBeginPlay of 000001C7848FAA80 fail: TypeError: not a function
at ReceiveBeginPlay (..\..\..\PuertsTest\Content\JavaScript\StartupGameMode.js:18:20)
我在FFunctionTranslator::Init中追加了一些日志:
void FFunctionTranslator::Init(UFunction* InFunction, bool IsDelegate)
{
if (InFunction->GetFName().ToString().Equals("SetForcedLODModel", ESearchCase::IgnoreCase))
{
UE_LOG(LogTemp, Warning, TEXT("## FFunctionTranslator::Init: %s::%s"), *InFunction->GetOuterUClass()->GetName(), *InFunction->GetFName().ToString());
}
// ...
}
v8::Local<v8::FunctionTemplate> FStructWrapper::ToFunctionTemplate(v8::Isolate* Isolate, v8::FunctionCallback Construtor)
{
for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
{
UFunction* Function = *FuncIt;
// ...
UE_LOG(LogTemp, Warning, TEXT("## Bind %s::%s"), *Class->GetName(), *FuncName);
if (Function->HasAnyFunctionFlags(FUNC_Static))
// ...
}
}发现编辑器中打印
## Bind BP_Test_C::SetForcedLODModel
## FFunctionTranslator::Init: BP_Test_C::SetForcedLODModel
QuickJs的包体打印:
## Bind BP_Test_C::SetForcedLodModel
## FFunctionTranslator::Init: BP_Test_C::SetForcedLodModel
v8的包体打印:
## Bind BP_Test_C::SetForcedLodModel
## FFunctionTranslator::Init: BP_Test_C::SetForcedLodModel
v8和QuickJs打印的符号都是SetForcedLodModel,但实际v8却调用SetForcedLODModel成功了