在平时的开发和学习中遇到和解决的一些问题以及摘录的一些资料,都随手写在了notes中,UE相关的积攒了不少,其他的混在一起比较混乱,整理到本篇文章中。
与UE4和VR开发技术笔记不同的是,这里的内容更偏向于项目中实际的问题记录和资料收集。
UE4 Error:The game module 'xxx' could not be loaded.
如果项目启动时弹窗以下错误:
1 | The game module 'WebBrowserEx' could not be loaded. There may be an operating system error or the module may not be properly set up. |
造成这个问题的原因之一是这个模块中引用了外部的Plugin,需要在这个模块的uplugin
文件中增加Plugins
依赖项。
1 | { |
UE4 Error:must include the same precompiled header first.
编译时如果出现这样的错误:
1 | 1>------ Build started: Project: NetExampleDemo, Configuration: Development_Game x64 ------ |
则需要在*.build.cs
中添加:
1 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; |
UE4:UWebBrowser支持中文输入
UE的UWebBrowser
打开的页面不支持中文输入,可以使用以下办法开启。
继承UWebBrowser
重写RebuildWidget
,增加以下代码:
1 | TSharedRef<SWidget> UWebBrowserExWidget::RebuildWidget() |
我把它单独做了一个插件,GitHub地址为:hxhb/WebBrowserEx418.
UE4:UnrealBuildTool Dependancy Warning
1 | UnrealBuildTool: Warning: Plugin 'A' does not list plugin 'B' as a dependency, but module 'A' depends on 'B' |
在插件A的.uplugin
文件中添加Plugins
项:
1 | { |
UE4:Instanced Stereo Rendering
在UE4.11中引入了Instanced Stereo Rendering,其原理是通过单次draw call来绘制双眼,进而来缩短渲染线程的时间和提高GPU的性能。
开启方式(ProjectSetting
-Engine
-Rending
):
UE4:HandleNetworkFailure
在UE中当网络连接出现错误时会调用UEngine::HandleNetworkFailure
来接收错误消息和处理错误,错误的类型为枚举ENetworkFailure::Type,标识了几种网络的错误类型。
以Server拒绝玩家的加入为例,在UE的这套网络架构中,使用CreateSession
/JoinSession
的方式来创建/加入游戏,可以通过AGameModeBase::Prelogin
以及overwrite
了该成员函数的子类来拒绝玩家的加入,方法为返回的ErrorMessage
不为空即为拒绝:
1 | /** |
GameMode的PreLogin调用栈为:
当玩家被拒绝加入游戏时,服务器会发送给当前连接的客户端错误消息:
1 | // call in server send to client |
PS:FNetControlMessage<T>::Send
的实现是由DEFINE_CONTROL_CHANNEL_MESSAGE_ONEPARAM
宏包裹的,其定义在文件DataChannel.h
中。
该消息会发送到客户端上,通过UEngine::HandleNetworkError
来使客户端来处理该错误,在其中会通知到UGameInstance::HandleNetworkError
,但是并没有把ErrorMessage
传递给GameInstance,我们可以通过继承UGameEngine
重写HandleNetworkError
来将ErrorMessage
传递给外部。
PS:玩家被拒绝之后会回到项目设置里的Game Default Map
中。
UGameInstance::HandleNetworkError
当网络链接出现错误时,会调用该函数(服务端拒绝玩家加入时也会调用)。
调用栈为(可以继承UEngine来替换Engine实现):
1 | UEngine::HandleNetworkError -> UEngine::HandleNetworkFailure_NotifyGameInstance -> GameInstance->HandleNetworkError(FailureType, bIsServer); |
VS断点调用栈:
UEngine::HandleNetworkFailure
实现为:
1 | // Runtime\Source\Runtime\Engine\Private\UnrealEngine.cpp |
ENetworkFailure的声明:
1 | // Runtime\Engine\Classes\Engine\EngineBaseType.h |
UE4:Max Agent
UE对AI支持的数量配置在Project Settings
-Engine
-Crowd Manager
-Config
-Max Agents
,默认为50,在项目里出现的问题还以为是逻辑有问题,没想到还有这么个配置。
MakeRotFromXY
声明在UKismetMathSystem
的MakeRotFrom**
函数的作用是,传递轴向(XY/YZ/YX等等)然后计算出从默认轴向(0,0,0)到该轴向的旋转。
UE4 Errpr:C1853 precompiled header file
在编译引擎时遇到以下错误:
1 | fatal error C1853: 'C:\Program Files\Epic Games\UE_4.19\Engine\Intermediate\Build\Win64\UE4Editor\Development\Engine\SharedPCH.Engine.h.pch' precompiled header file is from a previous version of the compiler, or the precompiled header is C++ and you are using it from C (or vice versa |
解决办法:删掉该模块在Engine\Intermediate\Build\Win64
下生成的文件夹,重新编译即可。
UE4 Error:C4577: 'noexcept' used
我在使用VS2017编译UE 4.18.3的时候编译器报了一个错误:
1 | error C4577: 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc |
这个错误是尝试使用异常,因为UE4默认情况下不允许使用异常,所以会产生这个错误。
解决的办法为,为报错的Module的build.cs
中添加:
1 | bEnableExceptions = true; |
重新编译即可。
UE4 Error: error : '': Bad command or expression
检查一下报错的文件的编码格式:
改为UTF-8即可:
UE4:Break a C++ Struct in BP
在C++中新建一个USTRUCT结构,在蓝图中可以Break/Make需要有以下操作:
- 将USTRUCT标记为BlueprintType
- 对成员变量的UPROPERTY增加
BlueprintReadWrite
(EditAnyWhere
并不控制是否可以Break)
UE4 Error:C4700: uninitialized local variable 'Parms' used
我在一个未实现的接口中返回自定义的结构类型会产生下列错误:
1 | inetplayerstate.gen.cpp(36): error C4700: uninitialized local variable 'Parms' used |
代码如下:
1 | // struct declare |
使用的接口:
1 |
|
报错的位置在inetplayerstate.gen.cpp
中,其代码为:
1 | FClampData IINetPlayerState::GetAssetClampData() const |
INetPlayerState_eventGetAssetClampData_Parms
的定义为包裹返回值的结构:
1 |
|
根据之前的文章:关于编译器生成默认构造函数的一些误区,如果我们的结构FClampData
没有提供默认构造函数,则INetPlayerState_eventGetAssetClampData_Parms
这个结构也不会生成默认的构造函数,所以它的对象是没有初始化的。
所以,为了解决这个问题,我们对自己定义的USTRUCT
结构定义一个默认构造函数就可以了:
1 |
|
还有另一种更简单的方法是,把接口的返回值使用引用参数(暴露给蓝图的&
参数会在蓝图节点的右侧,const&
在左侧),不过这种方式对于C++的调用来说必须要传递一个实参:
1 | UFUNCTION(BlueprintImplementableEvent, BlueprintCallable) |
引用本质也是指针来实现的。
UE4:GetPlayerController
UE的Player是以PlayerController为中心的,PlayerCharacter/PlayerPawn/PlayerCameraManager都是从PlayerController上获取的。
1 | // GameplayStatics.cpp |
UE:编辑器联机模式下退出崩溃
在编辑器中模拟联机的情况下退出后引擎崩溃,Log如下:
1 | [2019.04.30-06.43.04:039][512]LogPlayLevel: Error: No PIE world was found when attempting to gather references after GC. |
这是因为在关卡蓝图里调了RPC的事件,去掉即可。
UE4:联机游戏中AI不在视野被裁剪
在联机游戏如果怪物不在玩家的视野中,会被裁剪,其碰撞事件不会被触发,解决办法是将SkeletonMeshComponent的update骨架的配置改成always,就不会剪裁了。
UE:未包含CoreUObject.h的错误
相关链接:How to modify these errors in plugin?thanks
UE:C4668 Error '' is not defined as a prepeocessor macro
如果在UE中出现类似这样的错误:
1 | error C4668: '__GUNC__' is not defined as a prepeocessor macro, replicing with '0' for '#if/#elif' |
解决方案是在*.Build.cs
文件里加上bEnableUndefinedIdentifierWarnings=false;
(默认为true
).
在UBT的代码中:
1 | // Source\Programs\UnrealBuildTool\Configuration\ModuleRules.cs |
通过它来控制是否在编译参数中加入/we4668
:
1 | // Source\Programs\UnrealBuildTool\Platform\Windows\VCToolChain.cs |
UE:Detach Error in Net
这两天同事碰到这样一个同步问题:客户端抓取某样道具,使用AttachToComponent
将其抓到手中,在丢弃时使用DetachFromComponent
脱离。
在单机模式下毫无问题,但是涉及到网络同步时(UE的网络架构),有下面这样一个问题(为了测试我写了一个最简单的例子,使用最基础的C/S架构,完全由服务端处理(客户端只负责发起RPC调用和接收变量的同步)):
1 | LogOutputDevice: Error: === Handled ensure: === |
这是由于Attch
组件自身和Attach Parent
的Component Replication
被设置了,然后在从Server收到的变量同步事件OnRep_
中再做Detach
操作就会触发。
其实问题一句话可以概括:将自己从AttachParent上Detach掉,会判断将要Detach父级的AttachChildren
列表中判断自己存不存在,这个断言触发的是,自己的父级存在(Parent!=nullptr
),但是父级对象的AttachChildren
中不包含自己。
其实在C/S架构中,C端应该只做表现,而不处理逻辑,出现上面的问题也是联机模式下的实现思路问题,因为UE的Attach和Detach是会同步的,具体细节先按下不表,后续我会从代码分析一下这个问题。
UE Package:Couldn't save package,filename is too long
在打包的时候遇到这个错误,是因为某些资源在Windows上的绝对路径长度超过了260个字符,这是NTFS的限制。
所以,将项目路径移动到磁盘根目录,或者减少目录层级即可。
引擎中相关的代码在:
1 | // Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp(UE4.18.3) |
而各个平台的PLATFORM_MAX_FILEPATH_LENGTH
均定义在Runtime/Core/Public
相关的平台下。
Windows是使用的另一个宏WINDOWS_MAX_PATH
:
1 | D:\UnrealEngine\Offical_Source\4.18\Engine\Source\Runtime\Core\Public\Windows\WIndowsPlatform.h: |
WINDOWS_MAX_PATH
这个宏定义在Runtime/Core/Private/Windows/MinimalWindowsApi.h
中:
1 |
显然UE并没有使用Windows提供的MAX_PATH
宏,硬编码为了260,即在UE中Windows上的文件路径最大长度为260个字符(在启用bConsiderCompressedPackageFileLengthRequirements
时还要减去32个字符),虽然Windows10要移除260字符的限制,~但是貌似UE没有跟进的打算~(UE4.22 Released支持了长文件名的特性(实验性))。bConsiderCompressedPackageFileLengthRequirements
选项可以加在Saved/Config/Windows/Engine.ini
下(默认为true
):
1 | [CookSettings] |
这个配置是在Cook时会被加载用来判断是否考虑引擎生成的文件名长度:
1 | // Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp(UE4.18.3) |
在UCookOnTheFlyServer::SaveCookedPackage
中需要通过它来决定将系统支持的MAX_PATH
减去32之后的结果,用来判断资源路径是否超出限制。
外部阅读:
UE开启多重采样和前向渲染
ProjectSetting
-Rendering
-ForwardRenderer
/DefaultSetting-Anti
-Aliasing Method
UE4 Plugin:ModuleType(Required)
.uplugin
Module Type Descriptors.
Sets the type of Module. Valid options are
Runtime
,RuntimeNoCommandlet
,Developer
,Editor
,EditorNoCommandlet
, andProgram
. This type determines which types of applications this Plugin's Module is suitable for loading in. For example, some plugins may include modules that are only designed to be loaded when the editor is running. Runtime modules will be loaded in all cases, even in shipped games. Developer modules will only be loaded in development runtime or editor builds, but never in shipping builds. Editor modules will only be loaded when the editor is starting up. Your Plugin can use a combination of modules of different types.
1 | // Engine\Programs\UnrealBuildTool\System\ModuleDescriptor.cs |
UE4 Plugin:LoadingPhase(Optional)
.uplugin
Module LoadingPhase Descriptors.
If specified, controls when the plugin is loaded at start-up. This is an advanced option that should not normally be required. The valid options are
Default
(which is used when no LoadingPhase is specified),PreDefault
, andPostConfigInit
.PostConfigInit
enables the module to be loaded before the engine has finished starting up key subsystems.PreDefault
loads just before the normal phase. Typically, this is only needed if you expect game modules to depend directly on content within your plugin, or types declared within the plugin's code.
如果.upugin
中没有指定LoadingPhase
项,则默认是Default
:
1 | // Engine\Programs\UnrealBuildTool\System\ModuleDescriptor.cs |
GENERATED_BODY和GENERATED_UCLASS_BODY的区别
GENERATED_BODY:
- 不包含任何访问标识符,
class
默认是private
;struct
默认是public
. - 没有声明任何构造函数(constructor)
GENERATED_UCLASS_BODY:
- 包含
public
访问标识符 - 具有一个构造函数的声明,其参数为
const FObjectInieializer&
:
1 | // .h file |
参考链接:GENERATED_BODY vs GENERATED_UCLASS_BODY
Extensibility in UE4
UE4 Slate UI Framedowk
Networking in UE4
UE4 Engine Overview
Epic's Build Tools & Infrastructure
UHT的宏定义
GENERATED_BODY
以及UPROPERTY
和UFUNCTION
等宏的定义均是在:
1 | Engine\Source\Runtime\CoreUObject\Public\UObject\ObjectMacros.h |
UE Build:MakeShareable no matching
如果我们将一个类为T
的C++原生指针通过MakeShareable
的方式创建一个FRawPtrProxy<T>
然后用来构造一个TSharedPtr<t>
,有时会产生下列错误:
1 | Engine\Source\Programs\UE4Launcher\Source\Private\UI\WidgetUELauncher.cpp(620): error C2672: 'MakeShareable': no matching overloaded function found |
这是因为类型T的析构函数访问权限设置了保护,而这些引用计数的智能指针在计数为0时就会调用该对象的析构函数,所以会出现编译错误。
如果必须要创建一个TSharedPtr<T>
,如果T为自己创建的SWidget
派生类,可以把struct SharedPointerInternals::FRawPtrProxy<T>
设置为友元(Makeshareable()
就是构造了这个对象):
1 | // SEditableBoxWraper is a custom Widget derived by SWidget |
UE在编辑器内点Compile时自动保存资源
UE运行时动态更新寻路
UE EditorModule在Standalone下不会加载
注意:Module的Type如果为Editor则在Standalone下是不加载的。会出现在编辑器模式下是正常的,但是在Standalone运行时没有任何效果,新建的插件最好以Developer或者Runtime。
1 | { |
UE版本号的宏定义
引擎中标记引擎版本的宏:
- ENGINE_MAJOR_VERSION
- ENGINE_MINOR_VERSION
- ENGINE_PATCH_VERSION
等,是在Engine/Source/Runtime/Launch/Resources/Version.h中定义:
1 | // These numbers define the banner UE4 version, and are the most significant numbers when ordering two engine versions (that is, a 4.12.* version is always |
引擎的版本信息也记录在Engine\Build\Build.version
文件中:
1 | { |
UE蓝图的循环迭代最大计数
UE蓝图里面的循环上限是需要在ProjectSetting
-Engine
-Blueprints
里设置(默认是1000000):
UE:Primary Asset Id
先在Project Setting
-Game
-Asset Manager
里添加资源路径:
然后就可以在蓝图的PrimaryAssetId
中选择了:
UE Package Error: noexcept
如果打包时遇到下列错误:
1 | C4577: 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc |
在*.target.cs
中添加:
1 | bForceEnableExceptions = true; |
即可。
UE Package: Create Compressed Cooked Packages
打包时压缩pak:
UE Package:Use Log in Shipping
在我之前的文章Macro defined by UBT in UE4#USE_LOGGING_IN_SHIPPING中写道,可以在Module的*.target.cs
中使用bUseLoggingInShipping
来控制打包模式为Shipping的包是否启用日志。
注意:目前只支持源码版引擎,如果在Launcher安装的Engine会报链接错误:
1 | error LNK2001: unresolved external symbol "struct FLogCategoryLogSerialization LogSerialization" ([email protected]@[email protected]@A) |
同时,如果出现下列错误:
1 | C4577: 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc |
则在*.target.cs
中添加:
1 | bForceEnableExceptions = true; |
即可。
##UE4 Package: LogLinker Error: xxxx has an inappropriate outermos
在打包时遇到以下错误:
1 | UATHelper: Packaging (Windows (64-bit)): LogLinker: Error: HOTRELOADED_INetGameMode_1 has an inappropriate outermost, it was probably saved with a deprecated outer (file: ../../../../../../SanguoWarriors/Content/CoreBP/GamePlayFramework/GameMode/Net_GameMode_VR_Ex.uasset) |
这是该资源引用了一些无效的资源:
解决办法是,随便在蓝图内修改一点东西,点保存编译即可。
最后再打开它的Reference Viewer
确定没有无效资源即可。
UE4 Package:FMemoryWriter does not support data larger than 2GB. Archive name: None.
打包时出现了这个错误:
1 | UATHelper: Packaging (Windows (64-bit)): LogWindows: Error: begin: stack for UAT |
这是因为场景的烘培文件大于了2G,而UE的FMemoryWriter最大支持2G的文件,所以需要更改场景的光照参数(PackedLightAndShadowMapTextureSize
或者将场景拆分为多个子关卡,保证烘焙之后每个子关卡的*_BuildData.uasset
小于2G)。
UE Crash:破碎组件(DestructibleMesh)导致的崩溃
在最近的使用中,在服务端创建出来的DestructibleMesh,破碎之后再服务端销毁,在客户端会崩溃,不销毁只是破碎后隐藏就不会Crash,这在UE4.18.3上存在这个问题,先记录一下,有时间再深度研究一下。