UE4 VS system cannot find the file specified
You can right-click the solution to set the startup item Set as Startup Project
UE4 outputs Chinese garbled characters
VS uninstalls the Chinese language pack and installs the English language pack
UE4C++ project packaging pop-up web page
Because VS2022 is installed, you need to uninstall and reinstall VS2019
UE4 compile too card
You can install UE4 and VS on solid state drives, as well as projects. This can be several times faster
UE4 cannot find Interfaces/IPluginManager.h
Need to add "Projects" below
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
"Projects"
}
);
UE4C++ multithreading
1. The new UChessAIAsyncNode class inherits from UBlueprintAsyncActionBase
Note: Blueprint nodes with a clock icon are called asynchronous nodes, which need to be inherited from the above class
2. Declare dynamic multicast delegation
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FChessAIMuitDynamicDele, FBestMove, chessBest);
Description: Declared outside the class, this macro has three parameters (delegate to be bound, return value type, return value name)
For details, see: UE4 commission
3. Create a delegate that needs to be bound
public:
UPROPERTY(BlueprintAssignable)
FChessAIMuitDynamicDele Complete;
Explanation: This thing needs to be made public, otherwise it cannot be called elsewhere after it is private by default
Explanation 2: BlueprintAssignable means a dedicated entrusted node
Note 3: FChessAIMuitDynamicDele can be customized but it should be the same as step 2 above
Explanation 4: The name of Complete can be chosen casually, but it is actually the output parameter of the node
4. Declare asynchronous nodes
UFUNCTION(BlueprintCallable, Category = "ChessAI")
static UChessAIAsyncNode* ChessAIAlphaBeta(AChessAIBase *chess, const int max_depth);
Explanation: Similar to ordinary nodes, in fact, there is no need to return a value, just void, the main thing is to pay attention to the parameters that need to be used
5. Implement asynchronous nodes
UChessAIAsyncNode* UChessAIAsyncNode::ChessAIAlphaBeta(AChessAIBase *chess, const int max_depth)
{
UChessAIAsyncNode* BlueprintNode = NewObject<UChessAIAsyncNode>();
(new FAutoDeleteAsyncTask<MyAsyncTask>(BlueprintNode, chess, max_depth))->StartBackgroundTask();
return BlueprintNode;
}
Explanation: BlueprintNode is the class instance just now, which is mainly used to call the binding delegate Complete in the future, so it needs to be passed to the multi-thread
Explanation 2: new FAutoDeleteAsyncTask<MyAsyncTask> means to create a multi-thread, in which MyAsyncTask is defined by ourselves, which will be discussed later. The parameters in it are all needed, and you can also not pass them.
Note 3: The StartBackgroundTask function means to start the thread running
Note 4: FAutoDeleteAsyncTask is an available thread that can be automatically destroyed, it will be automatically allocated from the thread pool, and other reference videos can also be used
6. Create a thread class
First introduce the relevant header files in the header file
#include "Async/AsyncWork.h"
Then write a class as shown below
Description: 1 declare a friend class, do not know what it means
Note 2: The following variables can be customized, if necessary, add
Note 3: MyAsyncTask constructor, and initialize values for member variables, see step 5 above will pass in some parameters
Explanation 4: 2 needs to overload this DoWork function, which means calling when the thread is running
Explanation 5:3 is just written like this, I don’t know what it means, pay attention to replace MyAsyncTask with your own
7. Realize the thread running function DoWork
Explanation: The first two lines are calculations, which take a long time, so multi-threading is required
Explanation 2: ENamedThreads::GameThread means that the statements inside are called in the game thread
Explanation 3: Node is the UChessAIAsyncNode instance above, which was passed in through the constructor before
Note 4: Complete is the commission that needs to be bound just now, which is the output part of the blueprint node
Note 5: The Broadcast function should just call the delegate, and the blueprint node will output the calculation result at this time
8. Summary
Proxy-agent, multi-threaded, asynchronous nodes
h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "ChessAIBase.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Async/AsyncWork.h"
#include "ChessAIAsyncNode.generated.h"
//声明动态多播委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FChessAIMuitDynamicDele, FBestMove, chessBest);
/**
*
*/
UCLASS()
class CHESSAI_API UChessAIAsyncNode : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable)
FChessAIMuitDynamicDele Complete;
UFUNCTION(BlueprintCallable, Category = "ChessAI")
static UChessAIAsyncNode* ChessAIAlphaBeta(AChessAIBase *chess, const int max_depth);
};
class MyAsyncTask : public FNonAbandonableTask
{
// 1
friend class FAutoDeleteAsyncTask<MyAsyncTask>;
UChessAIAsyncNode *Node;
AChessAIBase *chess;
const int max_depth;
MyAsyncTask(UChessAIAsyncNode *WaitNode,AChessAIBase *WaitChess,const int Waitmax_depth)
: Node(WaitNode), chess(WaitChess), max_depth(Waitmax_depth){}
// 2
void DoWork();
// 3
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(MyAsyncTask, STATGROUP_ThreadPoolAsyncTasks);
}
};
cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ChessAIAsyncNode.h"
UChessAIAsyncNode* UChessAIAsyncNode::ChessAIAlphaBeta(AChessAIBase *chess, const int max_depth)
{
UChessAIAsyncNode* BlueprintNode = NewObject<UChessAIAsyncNode>();
(new FAutoDeleteAsyncTask<MyAsyncTask>(BlueprintNode, chess, max_depth))->StartBackgroundTask();
return BlueprintNode;
}
void MyAsyncTask::DoWork()
{
FBestMove chessBest;
chessBest = chess->AlphaBeta(max_depth);
AsyncTask(ENamedThreads::GameThread, [=]()
{
Node->Complete.Broadcast(chessBest);
});
}
UE4C++ crashes after multi-threaded packaging
The editor runs normally, but it crashes after packaging
A follow-up to the above multi-threaded approach (just to solve the problem and not the best way):
1. Do not use dynamic multicast in multithreading, whether with parameters or without parameters
2. Do not use it in the DoWork function
// AsyncTask(ENamedThreads::GameThread, [=]()
// {
// Node->Complete.Broadcast();
// });
I don't know the details, but it will crash after adding it
So the question is, how to return the value? I use a blueprint timer to wait for the calculation to end, and use a boolean member variable of a class to determine whether it is over.
Replenish:
It has nothing to do with multicast, mainly because it cannot be written like this
Indicates that it runs on the game thread, so that it will not crash after packaging
After UE4C++ is packaged, the DLL cannot be called and the path cannot be found
The FPlatformProcess::PushDllDirectory() function can tell the program the path of the required dll
FPlatformProcess::PushDllDirectory(*(FPaths::ProjectDir() / TEXT("Plugins/ChessAI/Source/ThirdParty/ChessAIDLL/x64/Release/")));
FPlatformProcess::PushDllDirectory(*(FPaths::ProjectDir() / TEXT("Plugins/ChessAI/Binaries/ThirdParty/ChessAIDLL/Win64/")));
Pay attention to these two lines, the paths are different, the second path is the plug-in directory after packaging, the first path will be invalid after packaging
for example
These three paths are all output in the first line above, 1 is the editor state, 2 is the editor build and running state, and 3 is the state after packaging
If there is no second line of code on both sides, you need to manually copy the relevant dll to the directory at the same level as the exe, which is troublesome. There is also a code that automatically copies the dll to the specified path on the Internet, which will not be discussed here.
If it crashes pay attention to the dependencies of the dll.