Posted onInUnrealEngineViews: Symbols count in article: 13kReading time ≈32 mins.
In daily development and learning, I have encountered and resolved some issues and collected some materials, which I have casually written down in notes. I have accumulated a fair amount related to UE, while other topics are mixed together and relatively chaotic. I have organized them into this article. Unlike the UE4 and VR Development Technical Notes, the content here is more focused on actual problem records and material collection within projects.
UE4 Error: The game module ‘xxx’ could not be loaded.
If the project shows the following error when starting:
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.
One of the reasons for this issue is that this module references an external Plugin, and you need to add the Plugins dependency item in this module’s uplugin file.
UE4 Error: must include the same precompiled header first.
If such an error occurs during compilation:
1 2 3 4 5 6 7 8 9 10 11 12
1>------ Build started: Project: NetExampleDemo, Configuration: Development_Game x64 ------ 1>Performing full C++ include scan (building a new target) 1>Creating makefile for NetExampleDemo (changes to module files) 1>EXEC : error : All source files in module "WebBrowserEx" must include the same precompiled header first. Currently "C:\Users\visionsmile\Documents\Unreal Projects\Examples\NetExampleDemo\Plugins\WebBrowserEx\Source\WebBrowserEx\Public\WebBrowserEx.h" is included by most of the source files. The following source files are not including "C:\Users\visionsmile\Documents\Unreal Projects\Examples\NetExampleDemo\Plugins\WebBrowserEx\Source\WebBrowserEx\Public\WebBrowserEx.h" as their first include: 1> 1> C:\Users\visionsmile\Documents\Unreal Projects\Examples\NetExampleDemo\Plugins\WebBrowserEx\Source\WebBrowserEx\Private\WebBrowserExWidget.cpp (including C:\Users\visionsmile\Documents\Unreal Projects\Examples\NetExampleDemo\Plugins\WebBrowserEx\Source\WebBrowserEx\Public\WebBrowserExWidget.h) 1> 1> 1> To compile this module without implicit precompiled headers, add "PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;" to WebBrowserEx.build.cs. 1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\VC\VCTargets\Microsoft.MakeFile.Targets(44,5): error MSB3075: The command""C:\Program Files\Epic Games\UE_4.18\Engine\Build\BatchFiles\Build.bat" NetExampleDemo Win64 Development "C:\Users\visionsmile\Documents\Unreal Projects\Examples\NetExampleDemo\NetExampleDemo.uproject" -waitmutex" exited with code 5. Please verify that you have sufficient rights to run this command. 1>Done building project "NetExampleDemo.vcxproj" -- FAILED. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The UWebBrowser in UE does not support Chinese input by default. You can enable it using the following method. Inherit from UWebBrowser and override RebuildWidget, adding the following code:
Instance Stereo Rendering was introduced in UE4.11, its principle is to draw both eyes with a single draw call, thereby shortening the render thread’s time and enhancing GPU performance.
To enable it (ProjectSetting-Engine-Rendering):
UE4: HandleNetworkFailure
When there is a network error in UE, UEngine::HandleNetworkFailure is called to receive error messages and handle errors. The error type is enumerated as ENetworkFailure::Type, indicating several types of network errors. Taking the server rejecting a player’s join request as an example, in this networking architecture of UE, the way to create/join a game is by using CreateSession/JoinSession, and players can be rejected by AGameModeBase::Prelogin, with the method being that returning an ErrorMessage that is not empty indicates rejection:
1 2 3 4 5 6 7 8 9 10
/** * Accept or reject a player attempting to join the server. Fails login if you set the ErrorMessage to a non-empty string. * PreLogin is called before Login. Significant game time may pass before Login is called * * @param Options The URL options (e.g. name/spectator) the player has passed * @param Address The network address of the player * @param UniqueId The unique id the player has passed to the server * @param ErrorMessage When set to a non-empty value, the player will be rejected using the error message set */ virtualvoidPreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage);
The call stack for GameMode’s PreLogin is:
When a player is rejected from joining the game, the server sends an error message to the currently connected client:
1 2 3
// call in server send to client // function is UWorld::NotifyControlMessage FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
PS: The implementation of FNetControlMessage<T>::Send is wrapped by the macro DEFINE_CONTROL_CHANNEL_MESSAGE_ONEPARAM, defined in the file DataChannel.h. This message is sent to the client, which handles the error through UEngine::HandleNetworkError, and it notifies UGameInstance::HandleNetworkError, but does not pass the ErrorMessage to GameInstance. We can override UGameEngine to pass the ErrorMessage to the outside.
PS: After players are rejected, they will return to the Game Default Map in the project settings.
UGameInstance::HandleNetworkError
This function is called when a network link error occurs (and it will also be called when the server rejects a player’s join request).
The call stack (you can inherit UEngine to replace the Engine implementation) is:
// Only handle failure at this level for game or pending net drivers. FName NetDriverName = NetDriver->NetDriverName; if (NetDriverName == NAME_GameNetDriver || NetDriverName == NAME_PendingNetDriver) { // If this net driver has already been unregistered with this world, then don't handle it. if (World) { if (!FindNamedNetDriver(World, NetDriverName)) { // This netdriver has already been destroyed (probably waiting for GC) return; } }
// Give the GameInstance a chance to handle the failure. HandleNetworkFailure_NotifyGameInstance(World, NetDriver, FailureType);
ENetMode FailureNetMode = NetDriver->GetNetMode(); // NetMode of the driver that failed bool bShouldTravel = true;
switch (FailureType) { case ENetworkFailure::FailureReceived: break; case ENetworkFailure::PendingConnectionFailure: // TODO stop the connecting movie break; case ENetworkFailure::ConnectionLost: // Hosts don't travel when clients disconnect bShouldTravel = (FailureNetMode == NM_Client); break; case ENetworkFailure::ConnectionTimeout: // Hosts don't travel when clients disconnect bShouldTravel = (FailureNetMode == NM_Client); break; case ENetworkFailure::NetGuidMismatch: case ENetworkFailure::NetChecksumMismatch: // Hosts don't travel when clients have actor issues bShouldTravel = (FailureNetMode == NM_Client); break; case ENetworkFailure::NetDriverAlreadyExists: case ENetworkFailure::NetDriverCreateFailure: case ENetworkFailure::OutdatedClient: case ENetworkFailure::OutdatedServer: default: break; }
if (bShouldTravel) { CallHandleDisconnectForFailure(World, NetDriver); } } }
if (World != nullptr && World->GetGameInstance() != nullptr) { World->GetGameInstance()->HandleNetworkError(FailureType, bIsServer); } else { // Since the UWorld passed in might be null, as well as the NetDriver's UWorld, // go through the world contexts until we find the one with this net driver. for (auto& Context : WorldList) { if (Context.PendingNetGame != nullptr && Context.PendingNetGame->NetDriver == NetDriver && Context.OwningGameInstance != nullptr) { // Use the GameInstance from the current context. Context.OwningGameInstance->HandleNetworkError(FailureType, bIsServer); } } } }
// Runtime\Engine\Classes\Engine\EngineBaseType.h /** Types of network failures broadcast from the engine */ UENUM(BlueprintType) namespace ENetworkFailure { enumType { /** A relevant net driver has already been created for this service */ NetDriverAlreadyExists, /** The net driver creation failed */ NetDriverCreateFailure, /** The net driver failed its Listen() call */ ConnectionLost, /** A connection to the net driver has timed out */ ConnectionTimeout, /** The net driver received an NMT_Failure message */ FailureReceived, /** The client needs to upgrade their game */ OutdatedClient, /** The server needs to upgrade their game */ OutdatedServer, /** There was an error during connection to the game */ PendingConnectionFailure, /** NetGuid mismatch */ NetGuidMismatch, /** Network checksum mismatch */ NetChecksumMismatch }; }
UE4: Max Agent
The number of AI supported by UE is configured in Project Settings-Engine-Crowd Manager-Config-Max Agents, which defaults to 50. I thought the issue in the project was logical but didn’t expect such a configuration to exist.
MakeRotFromXY
The purpose of the MakeRotFrom** functions declared in UKismetMathSystem is to pass an axis (XY/YZ/YX, etc.) and then calculate the rotation from the default axis (0,0,0) to that axis.
UE4 Error: C1853 precompiled header file
The following error occurred when compiling the engine:
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)
Solution: Delete the folder generated under Engine\Intermediate\Build\Win64 for that module and recompile.
UE4 Error: C4577: ‘noexcept’ used
I encountered an error when compiling UE 4.18.3 with VS2017:
1
error C4577: 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc
This error arises from attempting to use exceptions, as UE4 does not allow exceptions by default, leading to this error. The solution is to add:
1
bEnableExceptions = true;
to the build.cs of the module that reported the error, then recompile.
UE4 Error: error : ‘’: Bad command or expression
Check the encoding format of the reported file:
Change it to UTF-8:
UE4: Break a C++ Struct in BP
To create a USTRUCT structure in C++, and be able to Break/Make in Blueprints, the following operations are required:
Mark the USTRUCT as BlueprintType.
Add BlueprintReadWrite to the UPROPERTY of member variables (EditAnyWhere does not control whether it can be Broken).
// Add interface functions to this class. This is the class that will be inherited to implement this interface. public: // ... UFUNCTION(BlueprintImplementableEvent, BlueprintCallable) FClampData GetAssetClampData()const; };
According to previous articles: Some Misunderstandings about Compiler-Generated Default Constructors, if our structure FClampData does not provide a default constructor, then the structure INetPlayerState_eventGetAssetClampData_Parms will also not generate a default constructor, hence its object will not be initialized. Therefore, to solve this problem, we can define a default constructor for our defined USTRUCT:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#pragma once #include"CoreMinimal.h" #include"FClampData.generated.h"
USTRUCT(BlueprintType) structFClampData { GENERATED_USTRUCT_BODY() FORCEINLINE FClampData():bUseClamp(false),iMin(0),iMax(0){}; UPROPERTY(BlueprintReadWrite) bool bUseClamp; UPROPERTY(BlueprintReadWrite) int iMin; UPROPERTY(BlueprintReadWrite) int iMax; };
Another, simpler method is to use reference parameters for the interface’s return value (the exposed & parameter in Blueprint nodes will be on the right, const& on the left), but for C++ calls, a real argument must be passed:
// GameplayStatics.cpp class APlayerController* UGameplayStatics::GetPlayerController(const UObject* WorldContextObject, int32 PlayerIndex ) { if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull)) { uint32 Index = 0; for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PlayerController = Iterator->Get(); if (Index == PlayerIndex) { return PlayerController; } Index++; } } returnnullptr; }
ACharacter* UGameplayStatics::GetPlayerCharacter(const UObject* WorldContextObject, int32 PlayerIndex) { APlayerController* PC = GetPlayerController(WorldContextObject, PlayerIndex); return PC ? Cast<ACharacter>(PC->GetPawn()) : nullptr; }
APawn* UGameplayStatics::GetPlayerPawn(const UObject* WorldContextObject, int32 PlayerIndex) { APlayerController* PC = GetPlayerController(WorldContextObject, PlayerIndex); return PC ? PC->GetPawnOrSpectator() : nullptr; }
APlayerCameraManager* UGameplayStatics::GetPlayerCameraManager(const UObject* WorldContextObject, int32 PlayerIndex) { APlayerController* const PC = GetPlayerController(WorldContextObject, PlayerIndex); return PC ? PC->PlayerCameraManager : nullptr; }
UE: Editor crashes on exit in Online Mode
In the editor, when simulating online, the engine crashes upon exit. The log is as follows:
1
[2019.04.30-06.43.04:039][512]LogPlayLevel: Error: No PIE world was found when attempting to gather references after GC.
This happens because an RPC event was invoked in the level blueprint. Removing it will solve the issue.
UE4: AI culled when not in player’s view in online game
In online games, if monsters are out of the player’s view, they will be culled, and their collision events will not be triggered. The solution is to change the SkeletonMeshComponent’s update skeleton configuration to always so that they will not be culled.
In recent days, a colleague encountered a synchronization issue: the client grabs an item, uses AttachToComponent to hold it, and uses DetachFromComponent to release it when discarding. It works perfectly in single-player mode, but there’s an issue in network synchronization (UE’s network architecture) as follows (for testing, I wrote a very simple example, using the most basic C/S architecture, completely handled by the server (the client only initiates RPC calls and receives variable synchronization)):
This is due to the Attach component itself and the Attach Parent‘s Component Replication being set, and detaching in the variable synchronization event OnRep_ received from the server will trigger this. Essentially, this issue can be summarized in one sentence: Detaching itself from the AttachParent will check if it exists in the AttachChildren list of the parent being detached. The assertion is triggered because its parent exists (Parent != nullptr), but the parent object’s AttachChildren does not include itself. In C/S architecture, the client should primarily handle presentation, not logic. The above issue arises from the implementation thought under online mode, as UE’s Attach and Detach are synchronized. I’ll analyze this issue from the code later.
UE Package: Couldn’t save package, filename is too long
When packing, this error occurs because the absolute path length of certain resources on Windows exceeds 260 characters, which is an NTFS limitation. Therefore, moving the project path to the root directory of the disk or reducing the directory levels will help. The relevant code in the engine is:
1 2 3 4 5 6 7 8 9 10 11
// Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp(UE4.18.3) // need to subtract 32 because the SavePackage code creates temporary files with longer file names then the one we provide // projects may ignore this restriction if desired const int32 CompressedPackageFileLengthRequirement = bConsiderCompressedPackageFileLengthRequirements ? 32 : 0; const FString FullFilename = FPaths::ConvertRelativePathToFull(PlatFilename); if (FullFilename.Len() >= (PLATFORM_MAX_FILEPATH_LENGTH - CompressedPackageFileLengthRequirement)) { LogCookerMessage(FString::Printf(TEXT("Couldn't save package, filename is too long: %s"), *PlatFilename), EMessageSeverity::Error); UE_LOG(LogCook, Error, TEXT("Couldn't save package, filename is too long :%s"), *PlatFilename); Result = ESavePackageResult::Error; }
The PLATFORM_MAX_FILEPATH_LENGTH is defined under Runtime/Core/Public for each platform. For Windows, another macro WINDOWS_MAX_PATH is used:
The WINDOWS_MAX_PATH macro is defined in Runtime/Core/Private/Windows/MinimalWindowsApi.h:
1
#define WINDOWS_MAX_PATH 260
Clearly, UE does not use Windows’ MAX_PATH macro, hardcoding it to 260, meaning the maximum file path length on Windows in UE is 260 characters (32 characters must be subtracted if bConsiderCompressedPackageFileLengthRequirements is enabled). Although Windows 10 aims to [remove the 260 character limit](Microsoft removes 260 character limit for NTFS Path in new Windows 10 Insider Preview), the engine has already supported it, and (UE4.22 Released supported long file name features experimentally).
Sets the type of Module. Valid options are Runtime, RuntimeNoCommandlet, Developer, Editor, EditorNoCommandlet, and Program. 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.
// Engine\Programs\UnrealBuildTool\System\ModuleDescriptor.cs // The type of host that can load a module publicenum ModuleHostType { Default,
// Any target using the UE4 runtime Runtime,
// Any target except for commandlet RuntimeNoCommandlet,
// Any target or program RuntimeAndProgram,
// Loaded only in cooked builds CookedOnly,
// Loaded only when the engine has support for developer tools enabled Developer,
// Loaded only by the editor Editor,
// Loaded only by the editor, except when running commandlets EditorNoCommandlet,
// Loaded only by programs Program,
// Loaded only by servers ServerOnly,
// Loaded only by clients ClientOnly, }
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, and PostConfigInit. 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.
If no LoadingPhase item is specified in the .upugin, the default is Default:
// Engine\Programs\UnrealBuildTool\System\ModuleDescriptor.cs // Indicates when the engine should attempt to load this module publicenum ModuleLoadingPhase { /// Loaded at the default loading point during startup (during engine init, after game modules are loaded.) Default,
// Right after the default phase PostDefault,
// Right before the default phase PreDefault,
// Loaded before the engine is fully initialized, immediately after the config system has been initialized. Necessary only for very low-level hooks PostConfigInit,
// After PostConfigInit and before coreUobject initialized. used for early boot loading screens before the uobjects are initialized PreEarlyLoadingScreen, // Since 4.20
// Loaded before the engine is fully initialized for modules that need to hook into the loading screen before it triggers PreLoadingScreen,
// After the engine has been initialized PostEngineInit,
// Do not automatically load this module None, }
The Difference Between GENERATED_BODY and GENERATED_UCLASS_BODY
GENERATED_BODY:
Does not include any access specifiers; class defaults to private; struct defaults to public.
Declares and defines a constructor that takes const FObjectInitializer&.
GENERATED_UCLASS_BODY:
Includes public access specifier.
Contains a declaration for a constructor with parameter const FObjectInitializer&, requiring a definition in the code.
If we create a T C++ native pointer through MakeShareable to construct an FRawPtrProxy<T> and use it to construct a TSharedPtr<t>, we may sometimes see the following error:
1 2 3 4
Engine\Source\Programs\UE4Launcher\Source\Private\UI\WidgetUELauncher.cpp(620): error C2672: 'MakeShareable': no matching overloaded function found Engine\Source\Programs\UE4Launcher\Source\Private\UI\WidgetUELauncher.cpp(620): error C2780: 'SharedPointerInternals::FRawPtrProxy<ObjectType> MakeShareable(ObjectType *,DeleterType &&)': expects 2 arguments - 1 provided Engine\Source\Runtime\Core\Public\Templates/SharedPointer.h(1666): note: see declaration of 'MakeShareable' Engine\Source\Programs\UE4Launcher\Source\Private\UI\WidgetUELauncher.cpp(620): error C2784: 'SharedPointerInternals::FRawPtrProxy<ObjectType> MakeShareable(ObjectType *)': could not deduce template argument for'ObjectType *' from 'TSharedRef<ObjectType,0>'
This is because the destructor access of type T is set to protected, and these reference-counted smart pointers call the destructor when the count reaches 0, leading to a compilation error. If it’s necessary to create a TSharedPtr<T>, and T is a derived class of SWidget, you can make struct SharedPointerInternals::FRawPtrProxy<T> a friend (as Makeshareable() constructs this object):
1 2
// SEditableBoxWraper is a custom Widget derived by SWidget friendstructSharedPointerInternals::FRawPtrProxy<SEditableBoxWraper>;
UE Auto-Save Resources on Editor Compile
UE Run-time Dynamic Update Navigation
UE EditorModule Not Loading in Standalone
Note: If the Module Type is set to Editor, it will not load in Standalone. It may work well in editor mode, but have no effect when running Standalone. Newly created plugins should ideally be of Developer or Runtime type.
// 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 // newer than a 4.11.* version, regardless of the changelist that it was built with) #define ENGINE_MAJOR_VERSION 4 #define ENGINE_MINOR_VERSION 19 #define ENGINE_PATCH_VERSION 0
The engine version information is also recorded in the Engine\Build\Build.version file:
The loop limit in UE blueprints needs to be set in ProjectSetting - Engine - Blueprints (default is 1000000):
UE: Primary Asset Id
First, add the resource path in Project Setting - Game - Asset Manager:
Then you can select it in the blueprint’s PrimaryAssetId:
UE Package Error: noexcept
If you encounter the following error during packaging:
1
C4577: 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc
Add the following in *.target.cs:
1
bForceEnableExceptions = true;
UE Package: Create Compressed Cooked Packages
Compress pak during packaging:
UE Package: Use Log in Shipping
In my previous article Macro defined by UBT in UE4#USE_LOGGING_IN_SHIPPING, I mentioned that you can use bUseLoggingInShipping in the Module’s *.target.cs to control whether logging is enabled for packages in Shipping mode. Note: Currently, only supported in source version engines. If using the Engine installed via Launcher, it will report a linking error:
1
error LNK2001: unresolved external symbol "struct FLogCategoryLogSerialization LogSerialization" (?LogSerialization@@3UFLogCategoryLogSerialization@@A)
Additionally, if you encounter the following error:
1
C4577: 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc
Then add this in *.target.cs:
1
bForceEnableExceptions = true;
UE4 Package: LogLinker Error: xxxx has an inappropriate outermost
Encountered the following error during packaging:
1 2 3 4 5
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) 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) 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) 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) 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)
This resource references some invalid resources:
The solution is to casually modify something in the blueprint, then click to save and compile. Finally, reopen its Reference Viewer to ensure that there are no invalid resources.
UE4 Package: FMemoryWriter does not support data larger than 2GB. Archive name: None.
This is because the baked lighting file for the scene exceeded 2GB, while UE’s FMemoryWriter only supports files up to 2GB. Therefore, it is necessary to change the scene’s lighting parameters (PackedLightAndShadowMapTextureSize or split the scene into multiple sub-levels, ensuring that each sub-level’s *_BuildData.uasset is less than 2GB).
UE Crash: DestructibleMesh causes crashes
In recent usage, creating a DestructibleMesh on the server, then destroying it on the server after it is broken, causes a crash on the client. If it is just hidden after breaking without destruction, it does not crash. This issue exists in UE4.18.3; I will record this and study it in-depth later.