最近抽空把 Bluelua 計劃的最後一部分功能內容做完了,就是在 lua 中重載 UE4 中的網路事件,這樣就可以直接在 lua 中重寫網路相關的邏輯了。還有就是將之前重載純藍圖函數和事件幾個崩潰修復了。網路相關的重寫示例在 BlueluaDemo 的 NetTest 文件夾中

UE4 中網路事件分兩種,一種是 C++ 中的網路事件,就是在 UFUNCTION 中帶上 Server/NetMulticast/Client 關鍵字,另一種是在藍圖中,創建一個 Custom Event,然後在這個事件的複製屬性中選擇 Run On Server/Multicast/Run on owning Client,如圖

這兩種是互相獨立的,也就是 C++ 中的 Server/NetMulticast/Client 函數是無法在藍圖中進行重寫,所以如果有這樣的需求就需要在 C++ 的 Server/NetMulticast/Client 函數中去調用其它 BlueprintNativeEvent/BlueprintImplementable 函數,將這個事件拋到藍圖中,略顯麻煩。Bluelua 中就不用這麼麻煩了,現在可以直接在 lua 中分別重寫這兩類網路事件

重寫 C++ 網路事件

首先在 ANetCharacter 的 C++ 類中定義三個函數,一個可複製屬性和屬性的修改通知函數

UFUNCTION(Unreliable, Server, WithValidation)
void TestNativeServerFunction();

UFUNCTION(Unreliable, NetMulticast)
void TestNativeNetMulticastFunction();

UFUNCTION(Unreliable, Client)
void TestNativeClientFunction();

UPROPERTY(ReplicatedUsing=OnRep_Counter)
int32 Counter;

UFUNCTION(BlueprintNativeEvent)
void OnRep_Counter();

實現這幾個函數

void ANetCharacter::TestNativeClientFunction_Implementation()
{
UE_LOG(LogTemp, Display, TEXT("%sTestNativeClientFunction get called"), *GetPrefix(this));
}

void ANetCharacter::TestNativeNetMulticastFunction_Implementation()
{
UE_LOG(LogTemp, Display, TEXT("%sTestNativeNetMulticastFunction get called"), *GetPrefix(this));
}

void ANetCharacter::TestNativeServerFunction_Implementation()
{
UE_LOG(LogTemp, Display, TEXT("%sTestNativeServerFunction get called"), *GetPrefix(this));

TestNativeNetMulticastFunction(); // will run on local and remote
TestNativeClientFunction(); // will run on remote
}

bool ANetCharacter::TestNativeServerFunction_Validate()
{
return true;
}

void ANetCharacter::OnRep_Counter_Implementation()
{
UE_LOG(LogTemp, Display, TEXT("%sNative OnRep_Counter: %d"), *GetPrefix(this), Counter);
}

// 在伺服器的 Tick 中每隔 1 秒遞增 Counter
void ANetCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

if (Role == ROLE_Authority)
{
static float UpdateTime = 0;
UpdateTime += DeltaTime;

if (UpdateTime > 1.f)
{
++Counter;
UpdateTime = 0.f;
}
}
}

在 ANetCharacter 的子類 lua 中綁定一個 P 鍵輸入事件,按下 P 鍵後從客戶端調用 TestNativeServerFunction/TestNativeNetMulticastFunction/TestNativeClientFunction 幾個函數進行測試

function m:OnSetupPlayerInputComponent()
local BlueluaLibrary = LoadClass(BlueluaLibrary)

local EInputEvent = {
IE_Pressed = 0,
IE_Released = 1,
IE_Repeat = 2,
IE_DoubleClick = 3,
IE_Axis = 4,
IE_MAX = 5,
}

-- Press P key to start ent test
BlueluaLibrary:BindKeyAction(Super, { Key = { KeyName = P } }, EInputEvent.IE_Pressed, true, false, CreateFunctionDelegate(Super, self, self.OnKeyPressed))
end

function m:OnKeyPressed()
-- test net event in c++
Super:TestNativeClientFunction() -- will run on current client
Super:TestNativeNetMulticastFunction() -- will run on current client
Super:TestNativeServerFunction() -- will run on remote server
end

在測試前需要在編輯器中勾選 Run Dedicated Server,如圖

在沒有重寫的情況下,調用的是 C++ 中的實現,輸出的 log 為

LogTemp: Display: Client 1: Native OnRep_Counter: 1
LogTemp: Display: Client 1: Native OnRep_Counter: 2
LogTemp: Display: Client 1: Native OnRep_Counter: 3
LogTemp: Display: Client 1: Native OnRep_Counter: 4
LogTemp: Display: Client 1: Native OnRep_Counter: 5
LogTemp: Display: Client 1: Native OnRep_Counter: 6
LogTemp: Display: Client 1: Native OnRep_Counter: 7
LogTemp: Display: Client 1: TestNativeClientFunction get called
LogTemp: Display: Client 1: TestNativeNetMulticastFunction get called
LogTemp: Display: Server: TestNativeServerFunction get called
LogTemp: Display: Server: TestNativeNetMulticastFunction get called
LogTemp: Display: Client 1: TestNativeClientFunction get called
LogTemp: Display: Client 1: TestNativeNetMulticastFunction get called
LogTemp: Display: Client 1: Native OnRep_Counter: 8
LogTemp: Display: Client 1: Native OnRep_Counter: 9
LogTemp: Display: Client 1: Native OnRep_Counter: 10

從 log 中可以看出,當客戶端調用 Client/NetMulticast 函數時,是在本地執行的,當調用 Server 函數時,會在伺服器執行。伺服器上調用 NetMulticast 函數會在伺服器本地和客戶端上執行,調用 Client 函數會在對應的主控(Autonomous)客戶端上執行

現在在 lua 中重寫這些函數的實現,方法就是直接聲明一個同名的函數,如下

-- override Server replicated event in c++
function m:TestNativeClientFunction()
print(TestNativeClientFunction get called)
end

-- override NetMulticast replicated event in c++
function m:TestNativeNetMulticastFunction()
print(TestNativeNetMulticastFunction get called)
end

-- override Client replicated event in c++
function m:TestNativeServerFunction()
print(TestNativeServerFunction get called)
Super:TestNativeNetMulticastFunction() -- will run on local server and remote client
Super:TestNativeClientFunction() -- will run on remote client
end

-- override property replicated event in c++
function m:OnRep_Counter()
print(OnRep_Counter:, Super.Counter)
end

按 P 鍵進行測試,得到得 log 輸出為

LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 1
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 2
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 3
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 4
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 5
LogBluelua: Display: Client 1: Lua log: TestNativeClientFunction get called
LogBluelua: Display: Client 1: Lua log: TestNativeNetMulticastFunction get called
LogBluelua: Display: Server: Lua log: TestNativeServerFunction get called
LogBluelua: Display: Server: Lua log: TestNativeNetMulticastFunction get called
LogBluelua: Display: Client 1: Lua log: TestNativeClientFunction get called
LogBluelua: Display: Client 1: Lua log: TestNativeNetMulticastFunction get called
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 6
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 7
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 8
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 9
LogBluelua: Display: Client 1: Lua log: OnRep_Counter: 10

從 log 中可以看出,所有的網路事件都正確調到 lua 中重寫的實現中了,並且執行一致

重寫藍圖網路事件

同樣在 NetCharacter 藍圖中創建三個 Custom Event,並分別選擇 Run On Server/Multicast/Run on owning Client。創建一個 BPCounter 屬性,選擇 RepNotify,之後藍圖中會自動創建一個函數 OnRep_BPCounter,在這些函數中分別列印一句 log,如圖

同樣在 lua 的按鍵事件中調用這三個網路事件

function m:OnKeyPressed()
-- test net event in c++
--Super:TestNativeClientFunction() -- will run on current client
--Super:TestNativeNetMulticastFunction() -- will run on current client
--Super:TestNativeServerFunction() -- will run on remote server

-- test net event in blueprint
Super:TestBPClientFunction() -- will run on current client
Super:TestBPNetMulticastFunction() -- will run on current client
Super:TestBPServerFunction() -- will run on remote server
end

在 lua 沒有重載的情況下的 log 輸出為

LogBlueprintUserMessages: [NetCharacter_C_0] Server: BP OnRep_BPCounter: 1
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: BP OnRep_BPCounter: 1
LogBlueprintUserMessages: [NetCharacter_C_0] Server: BP OnRep_BPCounter: 2
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: BP OnRep_BPCounter: 2
LogBlueprintUserMessages: [NetCharacter_C_0] Server: BP OnRep_BPCounter: 3
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: BP OnRep_BPCounter: 3
LogBlueprintUserMessages: [NetCharacter_C_0] Server: BP OnRep_BPCounter: 4
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: BP OnRep_BPCounter: 4
LogBlueprintUserMessages: [NetCharacter_C_0] Server: BP OnRep_BPCounter: 5
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: BP OnRep_BPCounter: 5
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: TestBPClientFunction get called
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: TestBPNetMulticastFunction get called
LogBlueprintUserMessages: [NetCharacter_C_0] Server: TestBPServerFunction get called
LogBlueprintUserMessages: [NetCharacter_C_0] Server: TestBPNetMulticastFunction get called
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: TestBPClientFunction get called
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: TestBPNetMulticastFunction get called
LogBlueprintUserMessages: [NetCharacter_C_0] Server: BP OnRep_BPCounter: 6
LogBlueprintUserMessages: [NetCharacter_C_0] Client 1: BP OnRep_BPCounter: 6

從 log 中可以看出,藍圖的 Run On Server/Multicast/Run on owning Client 事件和 C++ 的 Server/NetMulticast/Client 函數的執行規則是一致的,唯一的區別是可複製屬性的 RepNotify 和 ReplicatedUsing,RepNotify 會在伺服器本地也調用 OnRep_BPCounter 函數,而 ReplicatedUsing 不會,這一點需要注意

現在在 lua 中重寫這些事件,同樣只要聲明一個同名的函數就行了,如下

-- override Server replicated event in blueprint
function m:TestBPClientFunction()
print(TestBPClientFunction get called)
end

-- override NetMulticast replicated event in blueprint
function m:TestBPNetMulticastFunction()
print(TestBPNetMulticastFunction get called)
end

-- override Client replicated event in blueprint
function m:TestBPServerFunction()
print(TestBPServerFunction get called)
Super:TestBPNetMulticastFunction() -- will run on local server and remote client
Super:TestBPClientFunction() -- will run on remote client
end

-- override property replicated event in blueprint
function m:OnRep_BPCounter()
print(OnRep_BPCounter:, Super.BPCounter)
end

重新按 P 鍵進行測試,得到得 log 輸出為

LogBluelua: Display: Server: Lua log: OnRep_BPCounter: 1
LogBluelua: Display: Client 1: Lua log: OnRep_BPCounter: 1
LogBluelua: Display: Server: Lua log: OnRep_BPCounter: 2
LogBluelua: Display: Client 1: Lua log: OnRep_BPCounter: 2
LogBluelua: Display: Server: Lua log: OnRep_BPCounter: 3
LogBluelua: Display: Client 1: Lua log: OnRep_BPCounter: 3
LogBluelua: Display: Server: Lua log: OnRep_BPCounter: 4
LogBluelua: Display: Client 1: Lua log: OnRep_BPCounter: 4
LogBluelua: Display: Server: Lua log: OnRep_BPCounter: 5
LogBluelua: Display: Client 1: Lua log: OnRep_BPCounter: 5
LogBluelua: Display: Client 1: Lua log: TestBPClientFunction get called
LogBluelua: Display: Client 1: Lua log: TestBPNetMulticastFunction get called
LogBluelua: Display: Server: Lua log: TestBPServerFunction get called
LogBluelua: Display: Server: Lua log: TestBPNetMulticastFunction get called
LogBluelua: Display: Client 1: Lua log: TestBPClientFunction get called
LogBluelua: Display: Client 1: Lua log: TestBPNetMulticastFunction get called

可以看出,藍圖的網路事件也調到了 lua 中了,並且執行規則一致


推薦閱讀:
相關文章