最近抽空把 Bluelua 計劃的最後一部分功能內容做完了,就是在 lua 中重載 UE4 中的網路事件,這樣就可以直接在 lua 中重寫網路相關的邏輯了。還有就是將之前重載純藍圖函數和事件幾個崩潰修復了。網路相關的重寫示例在 BlueluaDemo 的 NetTest 文件夾中
這兩種是互相獨立的,也就是 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 中了,並且執行規則一致
推薦閱讀: