發(fā):局域網(wǎng)測(cè)試與藍(lán)圖網(wǎng)絡(luò)事件核心機(jī)制解析)
1. 項(xiàng)目概述從藍(lán)圖到網(wǎng)絡(luò)構(gòu)建多人游戲的基石如果你正在學(xué)習(xí)《UE5_C多人游戲開(kāi)發(fā)實(shí)戰(zhàn)》并卡在了P4這一章感覺(jué)藍(lán)圖網(wǎng)絡(luò)事件和局域網(wǎng)測(cè)試既熟悉又陌生那么這篇筆記正是為你準(zhǔn)備的。很多朋友在從單機(jī)邏輯轉(zhuǎn)向多人聯(lián)機(jī)時(shí)會(huì)陷入一個(gè)誤區(qū)認(rèn)為只要把功能做出來(lái)在編輯器里按“播放”能跑通聯(lián)機(jī)就萬(wàn)事大吉了。實(shí)際上從“功能實(shí)現(xiàn)”到“網(wǎng)絡(luò)同步”之間隔著一道巨大的鴻溝而局域網(wǎng)聯(lián)機(jī)測(cè)試就是檢驗(yàn)?zāi)闶欠癯晒邕^(guò)這道鴻溝的唯一金標(biāo)準(zhǔn)。這一章的核心遠(yuǎn)不止是教你點(diǎn)擊幾個(gè)按鈕創(chuàng)建會(huì)話、加入會(huì)話它是在訓(xùn)練你建立一種“網(wǎng)絡(luò)思維”——你的每一個(gè)游戲行為都需要思考“誰(shuí)發(fā)起”、“誰(shuí)執(zhí)行”、“誰(shuí)看見(jiàn)結(jié)果”?;谠n程內(nèi)容我將結(jié)合自己趟過(guò)的坑深入拆解兩個(gè)核心部分一是如何快速、可靠地搭建一個(gè)用于迭代測(cè)試的局域網(wǎng)環(huán)境避免在虛幻編輯器自帶的“Play as Client”模擬測(cè)試中產(chǎn)生虛假的安全感二是徹底厘清藍(lán)圖網(wǎng)絡(luò)事件如“事件開(kāi)始運(yùn)行”、“事件Tick”、“復(fù)制事件”、“RPC”的執(zhí)行順序、觸發(fā)條件和適用場(chǎng)景。你會(huì)發(fā)現(xiàn)很多詭異的網(wǎng)絡(luò)Bug比如客戶端看不到角色移動(dòng)、傷害計(jì)算不一致、UI狀態(tài)不同步其根源往往是對(duì)這些基礎(chǔ)事件機(jī)制的理解偏差。本文將不僅復(fù)現(xiàn)課程步驟更會(huì)補(bǔ)充大量官方文檔未提及的、但在實(shí)戰(zhàn)中至關(guān)重要的細(xì)節(jié)和排查技巧。2. 局域網(wǎng)聯(lián)機(jī)測(cè)試環(huán)境搭建全解析在虛幻引擎中開(kāi)發(fā)多人游戲絕不能依賴單機(jī)模式下的邏輯正確性。網(wǎng)絡(luò)復(fù)制、所有權(quán)、RPC調(diào)用等因素會(huì)徹底改變代碼的執(zhí)行環(huán)境。因此建立一個(gè)隔離、可控的局域網(wǎng)測(cè)試環(huán)境是開(kāi)發(fā)流程中不可或缺的一環(huán)。2.1 為何要搭建獨(dú)立局域網(wǎng)測(cè)試環(huán)境你可能習(xí)慣在編輯器中使用“Play”旁邊的下拉菜單選擇“Play as Client”或“Play as Dedicated Server”進(jìn)行模擬。這種方式快捷但存在嚴(yán)重局限性模擬不完整編輯器內(nèi)模擬的客戶端和服務(wù)器共享同一進(jìn)程一些底層網(wǎng)絡(luò)行為和性能問(wèn)題如帶寬、延遲模擬無(wú)法真實(shí)再現(xiàn)。資源沖突模擬客戶端可能會(huì)意外修改到服務(wù)器進(jìn)程的資源狀態(tài)導(dǎo)致難以復(fù)現(xiàn)的幽靈Bug。打包后行為不一致最大的陷阱在于許多網(wǎng)絡(luò)問(wèn)題只在打包成可執(zhí)行文件后才會(huì)暴露。編輯器環(huán)境下的網(wǎng)絡(luò)層處理可能與打包版本有細(xì)微差別。因此搭建一個(gè)由獨(dú)立的服務(wù)器進(jìn)程和多個(gè)獨(dú)立的客戶端進(jìn)程構(gòu)成的真實(shí)局域網(wǎng)環(huán)境是驗(yàn)證網(wǎng)絡(luò)功能可靠性的必經(jīng)之路。這能讓你提前發(fā)現(xiàn)并解決90%以上的網(wǎng)絡(luò)同步問(wèn)題。2.2 三種主流局域網(wǎng)測(cè)試方案對(duì)比與實(shí)操根據(jù)項(xiàng)目階段和團(tuán)隊(duì)規(guī)模可以選擇不同的方案。方案一單機(jī)多進(jìn)程測(cè)試最常用、最快捷這是個(gè)人開(kāi)發(fā)者和小團(tuán)隊(duì)最高效的測(cè)試方式。在一臺(tái)物理機(jī)上運(yùn)行一個(gè)服務(wù)器實(shí)例和多個(gè)客戶端實(shí)例。操作流程打包項(xiàng)目首先在UE5編輯器中選擇“打包項(xiàng)目”目標(biāo)平臺(tái)選擇Windows或你的開(kāi)發(fā)平臺(tái)。確保打包設(shè)置中啟用了“使用Pak文件”以加快后續(xù)打包速度。啟動(dòng)專用服務(wù)器導(dǎo)航到打包輸出目錄通常是YourProject/Saved/StagedBuilds/Windows找到Y(jié)ourProjectServer.exe如果項(xiàng)目名稱為MyGame則為MyGameServer.exe。直接雙擊運(yùn)行它將以無(wú)窗口或命令行窗口形式啟動(dòng)一個(gè)專用服務(wù)器并監(jiān)聽(tīng)默認(rèn)端口如7777。你可以在命令行后添加參數(shù)例如MyGameServer.exe -log來(lái)查看日志。啟動(dòng)客戶端在同一個(gè)目錄下找到Y(jié)ourProject.exe即客戶端。雙擊運(yùn)行第一個(gè)客戶端。在游戲主菜單或控制臺(tái)按~鍵中輸入連接命令如open 127.0.0.1:7777連接到本地服務(wù)器。啟動(dòng)更多客戶端再次雙擊YourProject.exe啟動(dòng)第二個(gè)、第三個(gè)客戶端進(jìn)程同樣連接127.0.0.1:7777。這樣你就在一臺(tái)機(jī)器上模擬了多玩家聯(lián)機(jī)。注意單機(jī)多進(jìn)程測(cè)試時(shí)每個(gè)進(jìn)程都會(huì)占用CPU、內(nèi)存和GPU資源。如果你的游戲資源消耗較大同時(shí)運(yùn)行多個(gè)實(shí)例可能會(huì)導(dǎo)致機(jī)器卡頓。建議測(cè)試時(shí)關(guān)閉不必要的程序并適當(dāng)降低游戲畫(huà)面設(shè)置。方案二使用虛擬局域網(wǎng)Virtual LAN工具當(dāng)需要跨多臺(tái)真實(shí)物理機(jī)進(jìn)行測(cè)試時(shí)比如測(cè)試不同硬件性能、輸入設(shè)備可以使用虛擬局域網(wǎng)軟件如Radmin VPN或Hamachi。它們能在互聯(lián)網(wǎng)上創(chuàng)建一個(gè)虛擬的局域網(wǎng)讓身處不同物理位置的電腦像在同一個(gè)路由器下一樣互訪。操作流程在所有測(cè)試機(jī)器上安裝同一款虛擬局域網(wǎng)軟件。創(chuàng)建一個(gè)網(wǎng)絡(luò)所有機(jī)器加入該網(wǎng)絡(luò)。軟件會(huì)為每臺(tái)機(jī)器分配一個(gè)虛擬局域網(wǎng)IP如192.168.xxx.xxx。在一臺(tái)機(jī)器上運(yùn)行專用服務(wù)器。在其他機(jī)器上運(yùn)行客戶端并使用服務(wù)器所在機(jī)器的虛擬局域網(wǎng)IP進(jìn)行連接。優(yōu)缺點(diǎn)優(yōu)點(diǎn)是能進(jìn)行真實(shí)的多機(jī)測(cè)試。缺點(diǎn)是引入第三方軟件可能增加網(wǎng)絡(luò)延遲和復(fù)雜性且需要處理防火墻規(guī)則。方案三路由器真實(shí)局域網(wǎng)這是最理想的測(cè)試環(huán)境適合辦公室或家庭內(nèi)部測(cè)試。所有測(cè)試電腦連接到同一個(gè)路由器有線或無(wú)線。操作流程確保所有電腦在同一網(wǎng)段如192.168.1.x。在其中一臺(tái)電腦上運(yùn)行專用服務(wù)器。在其他電腦上運(yùn)行客戶端使用運(yùn)行服務(wù)器的電腦的局域網(wǎng)IP地址進(jìn)行連接可在服務(wù)器電腦的命令行輸入ipconfig查看。關(guān)鍵點(diǎn)需要確保Windows防火墻允許你的游戲服務(wù)器和客戶端程序通過(guò)。通常第一次運(yùn)行時(shí)防火墻會(huì)彈出詢問(wèn)框務(wù)必選擇“允許”。如果沒(méi)彈出或連接失敗需要手動(dòng)在防火墻設(shè)置中添加入站規(guī)則。2.3 打包配置核心要點(diǎn)與常見(jiàn)失敗排查打包失敗是新手最常見(jiàn)的攔路虎。以下要點(diǎn)能極大提高打包成功率項(xiàng)目設(shè)置檢查地圖與模式在“項(xiàng)目設(shè)置 - 項(xiàng)目 - 地圖與模式”中確?!澳J(rèn)地圖”、“游戲默認(rèn)地圖”、“服務(wù)器默認(rèn)地圖”設(shè)置正確。對(duì)于多人游戲通常需要一個(gè)不會(huì)自動(dòng)連接服務(wù)器的“主菜單地圖”和一個(gè)正式的“游戲地圖”。打包目標(biāo)在“項(xiàng)目設(shè)置 - 平臺(tái) - Windows”中檢查目標(biāo)設(shè)置。如果項(xiàng)目包含C代碼確保已安裝對(duì)應(yīng)版本的Windows SDK和Visual Studio構(gòu)建工具。網(wǎng)絡(luò)配置在“項(xiàng)目設(shè)置 - 引擎 - 網(wǎng)絡(luò)”中可以設(shè)置默認(rèn)端口、網(wǎng)絡(luò)頻率等。常見(jiàn)打包錯(cuò)誤與解決錯(cuò)誤 MSB3428: 未能加載 Visual C 組件 “VCBuild.exe”這是一個(gè)經(jīng)典的環(huán)境配置問(wèn)題。它意味著你的 Visual Studio 安裝不完整或損壞。解決方案不要嘗試手動(dòng)找文件。最徹底的方法是運(yùn)行Visual Studio Installer找到你已安裝的VS版本如 Visual Studio 2022點(diǎn)擊“修改”在“工作負(fù)載”選項(xiàng)卡中確保勾選了“使用C的桌面開(kāi)發(fā)”。在右側(cè)的“安裝詳細(xì)信息”中務(wù)必勾選MSVC v143 - VS 2022 C x64/x86 生成工具和Windows 11 SDK或?qū)?yīng)你Windows版本的SDK。安裝完成后重啟電腦。缺少 .NET Framework 或 其他運(yùn)行時(shí)庫(kù)打包過(guò)程或打包后的程序可能需要。確保開(kāi)發(fā)機(jī)和測(cè)試機(jī)都安裝了較新版本的 .NET Framework 和 Visual C Redistributable。烹飪Cooking資源失敗某個(gè)資源文件如特定格式的模型、紋理可能損壞或不受支持。查看輸出日志Output Log中具體的錯(cuò)誤信息定位到出問(wèn)題的資源嘗試重新導(dǎo)入或檢查其設(shè)置。專用服務(wù)器Server構(gòu)建在打包對(duì)話框的“高級(jí)設(shè)置”中有一個(gè)“構(gòu)建”選項(xiàng)包含“游戲”、“客戶端”、“服務(wù)器”等。為了生成YourProjectServer.exe你需要至少選擇“服務(wù)器”進(jìn)行構(gòu)建。一個(gè)穩(wěn)妥的做法是直接選擇“全部構(gòu)建”。實(shí)操心得建議專門(mén)創(chuàng)建一個(gè)簡(jiǎn)單的“測(cè)試關(guān)卡”里面只包含最基礎(chǔ)的角色、出生點(diǎn)和必要的游戲邏輯。在開(kāi)發(fā)聯(lián)機(jī)功能時(shí)始終針對(duì)這個(gè)輕量級(jí)關(guān)卡進(jìn)行打包和測(cè)試可以極大縮短打包等待時(shí)間快速迭代。3. 藍(lán)圖網(wǎng)絡(luò)事件機(jī)制深度剖析理解了如何測(cè)試接下來(lái)就要理解測(cè)試什么。藍(lán)圖中的網(wǎng)絡(luò)事件是驅(qū)動(dòng)多人游戲邏輯的血管每一類事件都有其明確的職責(zé)和觸發(fā)條件。3.1 事件執(zhí)行順序與權(quán)威性模型在UE5的多人游戲架構(gòu)中存在一個(gè)核心概念服務(wù)器是權(quán)威的Authoritative。這意味著游戲世界的“唯一真相”只存在于服務(wù)器上??蛻舳丝吹降闹皇欠?wù)器狀態(tài)的一個(gè)近似副本。所有關(guān)鍵邏輯如傷害計(jì)算、物品生成、勝負(fù)判定都必須在服務(wù)器上執(zhí)行。在這個(gè)模型下藍(lán)圖事件的執(zhí)行遵循一個(gè)嚴(yán)格的順序和規(guī)則服務(wù)器端Server所有 Actor 的Event BeginPlay都會(huì)執(zhí)行。服務(wù)器擁有所有 Actor 的“最終決定權(quán)”??蛻舳硕薈lient客戶端只會(huì)接收到服務(wù)器認(rèn)為它“需要看到”的 Actor通過(guò)網(wǎng)絡(luò)復(fù)制。對(duì)于這些復(fù)制過(guò)來(lái)的 Actor客戶端也會(huì)執(zhí)行它們的Event BeginPlay。關(guān)鍵區(qū)別一個(gè) Actor 的Event BeginPlay會(huì)在兩個(gè)地方被調(diào)用一次在服務(wù)器如果它在服務(wù)器上生成一次在每個(gè)看到它的客戶端。因此你不能在Event BeginPlay里寫(xiě)只應(yīng)在單一權(quán)威端執(zhí)行的邏輯比如隨機(jī)生成一個(gè)寶藏位置除非你用Has Authority或Is Server節(jié)點(diǎn)進(jìn)行分支判斷。3.2 核心網(wǎng)絡(luò)事件詳解與應(yīng)用場(chǎng)景3.2.1 Event BeginPlay初始化的陷阱如上所述Event BeginPlay是網(wǎng)絡(luò)敏感的。一個(gè)常見(jiàn)的錯(cuò)誤是在這里初始化玩家狀態(tài)或生成道具。錯(cuò)誤示例在角色藍(lán)圖的Event BeginPlay中直接設(shè)置玩家生命值為100。后果服務(wù)器設(shè)置了生命值為100并復(fù)制給客戶端。但客戶端在自己的Event BeginPlay中也執(zhí)行了設(shè)置生命值為100。如果網(wǎng)絡(luò)復(fù)制稍有延遲客戶端可能會(huì)先用本地值100顯示然后立刻被服務(wù)器的復(fù)制值100覆蓋。雖然結(jié)果相同但這個(gè)過(guò)程隱藏了時(shí)序問(wèn)題。如果初始化邏輯更復(fù)雜比如從數(shù)據(jù)表讀取就可能出問(wèn)題。正確做法在Event BeginPlay中首先用Switch Has Authority節(jié)點(diǎn)進(jìn)行判斷。將只應(yīng)在服務(wù)器執(zhí)行的初始化邏輯如生命值設(shè)置、裝備默認(rèn)武器放在“Authority”分支將只應(yīng)在客戶端執(zhí)行的邏輯如播放本地音效、初始化本地UI放在“Remote”分支。3.2.2 Event Tick性能與網(wǎng)絡(luò)的權(quán)衡Event Tick每幀執(zhí)行是性能消耗大戶在網(wǎng)絡(luò)游戲中更需要謹(jǐn)慎使用。服務(wù)器端Tick可以用于執(zhí)行需要持續(xù)判斷的邏輯如檢測(cè)玩家是否進(jìn)入某個(gè)區(qū)域、持續(xù)性的環(huán)境傷害。但應(yīng)盡量避免每幀進(jìn)行復(fù)雜的計(jì)算或遍歷大量Actor??蛻舳硕薚ick常用于處理本地視覺(jué)特效、平滑插值如角色移動(dòng)的客戶端預(yù)測(cè)修正、本地輸入響應(yīng)。切記不能在客戶端Tick里直接修改需要同步的變量如角色位置、生命值這些修改必須通過(guò)RPC發(fā)送到服務(wù)器由服務(wù)器權(quán)威修改后再?gòu)?fù)制回來(lái)。優(yōu)化建議對(duì)于不需要每幀判斷的邏輯使用定時(shí)器Timer或事件延遲Delay來(lái)代替Tick。例如檢查周?chē)鷶橙说倪壿嬁梢悦?.2秒執(zhí)行一次而不是每幀。3.2.3 復(fù)制Replication與復(fù)制事件On Rep復(fù)制是服務(wù)器向客戶端同步數(shù)據(jù)的基礎(chǔ)機(jī)制。當(dāng)一個(gè)變量被設(shè)置為“復(fù)制Replicated”后服務(wù)器上該變量的值發(fā)生變化時(shí)會(huì)自動(dòng)將其新值發(fā)送給相關(guān)的客戶端。復(fù)制條件變量變化且持有該變量的Actor被設(shè)置為“網(wǎng)絡(luò)復(fù)制Replicates”且該變量屬性中勾選了“Replication”。On RepRepNotify這是一個(gè)為復(fù)制變量特別設(shè)計(jì)的事件。當(dāng)某個(gè)復(fù)制變量在客戶端接收到來(lái)自服務(wù)器的新值時(shí)就會(huì)觸發(fā)其對(duì)應(yīng)的On Rep事件。注意在服務(wù)器上修改變量不會(huì)觸發(fā)On Rep。核心應(yīng)用On Rep是客戶端響應(yīng)狀態(tài)變化的生命線。例如玩家生命值Health變量被復(fù)制并綁定了OnRep_Health事件。當(dāng)服務(wù)器扣除玩家生命值并復(fù)制到客戶端時(shí)客戶端的OnRep_Health被觸發(fā)你可以在這里播放受傷音效、屏幕閃紅、更新血條UI。這就是將數(shù)據(jù)變化轉(zhuǎn)化為視覺(jué)/聽(tīng)覺(jué)反饋的標(biāo)準(zhǔn)模式。3.2.4 遠(yuǎn)程過(guò)程調(diào)用RPC跨越網(wǎng)絡(luò)的指令RPC用于在機(jī)器間直接調(diào)用函數(shù)。它是客戶端與服務(wù)器、服務(wù)器與客戶端之間進(jìn)行主動(dòng)通信的主要手段。服務(wù)器RPCServer RPC由客戶端調(diào)用在服務(wù)器上執(zhí)行。這是客戶端請(qǐng)求服務(wù)器改變游戲世界的唯一方式。例如玩家按下射擊鍵客戶端調(diào)用一個(gè)Server_Fire的RPC請(qǐng)求服務(wù)器執(zhí)行射擊邏輯計(jì)算彈道、判斷命中、扣除生命值。關(guān)鍵限制只有該Actor的擁有者客戶端Owning Client才能向服務(wù)器調(diào)用該Actor上的Server RPC。例如玩家控制的角色藍(lán)圖其擁有者就是該玩家的客戶端??蛻舳薘PCClient RPC由服務(wù)器調(diào)用在指定的一個(gè)或所有客戶端上執(zhí)行。用于通知客戶端執(zhí)行一些本地表現(xiàn)。例如服務(wù)器確認(rèn)一次爆炸發(fā)生后調(diào)用一個(gè)Client_PlayExplosionEffects的RPC在所有客戶端上播放爆炸的音效和粒子。多播RPCMulticast RPC由服務(wù)器調(diào)用在服務(wù)器和所有客戶端上執(zhí)行。常用于需要高度同步的視覺(jué)效果或瞬時(shí)事件。例如服務(wù)器觸發(fā)一個(gè)開(kāi)門(mén)動(dòng)畫(huà)通過(guò)多播RPC讓所有客戶端包括服務(wù)器自己同時(shí)播放這個(gè)動(dòng)畫(huà)確保大家看到的動(dòng)畫(huà)時(shí)機(jī)是一致的。與復(fù)制的區(qū)別多播RPC是“事件驅(qū)動(dòng)”的同步而變量復(fù)制是“狀態(tài)驅(qū)動(dòng)”的同步。對(duì)于一次性、瞬時(shí)的事件如播放動(dòng)畫(huà)、音效使用多播RPC更直接。對(duì)于持續(xù)的狀態(tài)如生命值、坐標(biāo)使用變量復(fù)制更合適。3.3 網(wǎng)絡(luò)事件選擇決策流程圖面對(duì)一個(gè)功能如何選擇正確的網(wǎng)絡(luò)事件可以遵循以下決策路徑這個(gè)邏輯在哪里執(zhí)行必須在服務(wù)器執(zhí)行如傷害計(jì)算、生成物品使用Server RPC由客戶端觸發(fā)或直接在服務(wù)器的Event BeginPlay/Tick由服務(wù)器自主觸發(fā)中編寫(xiě)并用Has Authority保護(hù)。必須在特定客戶端執(zhí)行如更新本地玩家UI、播放第一人稱武器動(dòng)畫(huà)使用Client RPC由服務(wù)器調(diào)用或在該客戶端的本地事件中編寫(xiě)。需要在所有機(jī)器上同步執(zhí)行如同時(shí)播放的動(dòng)畫(huà)、全局游戲狀態(tài)切換使用Multicast RPC。這個(gè)數(shù)據(jù)是什么性質(zhì)持續(xù)的狀態(tài)會(huì)隨時(shí)間變化如坐標(biāo)、血量、彈藥數(shù)定義為Replicated Variable并用On Rep 事件來(lái)處理客戶端反饋。一次性的觸發(fā)事件如按下按鍵、拾取物品的瞬間使用RPC。這個(gè)邏輯何時(shí)執(zhí)行對(duì)象創(chuàng)建時(shí)使用Event BeginPlay并用Switch Has Authority區(qū)分服務(wù)器和客戶端邏輯。持續(xù)每幀使用Event Tick并特別注意性能優(yōu)化和權(quán)限判斷。響應(yīng)某個(gè)狀態(tài)變化時(shí)使用On Rep 事件或RPC。4. 實(shí)戰(zhàn)構(gòu)建一個(gè)簡(jiǎn)單的局域網(wǎng)測(cè)試Demo讓我們將理論付諸實(shí)踐創(chuàng)建一個(gè)最簡(jiǎn)單的“移動(dòng)與同步”測(cè)試Demo涵蓋從藍(lán)圖設(shè)置到打包測(cè)試的全流程。4.1 藍(lán)圖網(wǎng)絡(luò)基礎(chǔ)設(shè)置創(chuàng)建角色藍(lán)圖新建一個(gè)繼承自Character的藍(lán)圖命名為BP_NetworkTestCharacter。啟用網(wǎng)絡(luò)復(fù)制在藍(lán)圖的“類默認(rèn)值”中找到“復(fù)制Replication”部分勾選“Replicates”。這表示這個(gè)Actor可以被服務(wù)器復(fù)制到客戶端。添加一個(gè)復(fù)制變量在“我的藍(lán)圖”面板添加一個(gè)浮點(diǎn)型變量命名為CurrentHealth。在變量詳情中勾選“Replication”下拉框中的“RepNotify”。這會(huì)自動(dòng)生成一個(gè)OnRep_CurrentHealth事件。設(shè)置移動(dòng)輸入在事件圖表中找到“移動(dòng)”相關(guān)的事件如InputAxis MoveForward這些默認(rèn)已由Character類處理負(fù)責(zé)將輸入轉(zhuǎn)換為移動(dòng)并且CharacterMovement組件默認(rèn)是網(wǎng)絡(luò)復(fù)制的所以角色的基本移動(dòng)無(wú)需額外網(wǎng)絡(luò)代碼就能同步。4.2 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的傷害與同步邏輯我們的目標(biāo)是按下鍵盤(pán)某個(gè)鍵如H鍵服務(wù)器上的角色生命值減少10點(diǎn)并同步到所有客戶端客戶端在生命值變化時(shí)播放一個(gè)反饋效果。創(chuàng)建Server RPC在BP_NetworkTestCharacter的事件圖表中右鍵搜索“Custom Event”創(chuàng)建一個(gè)新事件命名為Server_TakeDamage。在該事件的詳情面板中將“Replicates”設(shè)置為“Run on Server”。這就將其標(biāo)記為一個(gè)服務(wù)器RPC。拖出該事件的節(jié)點(diǎn)。實(shí)現(xiàn)服務(wù)器傷害邏輯從Server_TakeDamage事件節(jié)點(diǎn)拉出引線添加一個(gè)Branch節(jié)點(diǎn)。這是為了安全起見(jiàn)雖然Server RPC只在服務(wù)器運(yùn)行但雙重檢查是好習(xí)慣。在Branch的Condition引腳連接Has Authority節(jié)點(diǎn)。在Branch的True分支執(zhí)行傷害邏輯使用Set CurrentHealth節(jié)點(diǎn)將其值設(shè)置為Get CurrentHealth減去10。確保勾選上“復(fù)制Replicate”選項(xiàng)這樣值的改變會(huì)自動(dòng)同步。綁定輸入并調(diào)用RPC在藍(lán)圖的事件圖表中添加一個(gè)InputAction H事件需要在項(xiàng)目設(shè)置中先定義名為“H”的輸入操作。從該事件拉出引線連接到Server_TakeDamage事件節(jié)點(diǎn)的Call引腳。這樣當(dāng)玩家按下H鍵時(shí)客戶端就會(huì)調(diào)用這個(gè)Server RPC請(qǐng)求服務(wù)器執(zhí)行扣血。實(shí)現(xiàn)客戶端反饋On Rep在“我的藍(lán)圖”的“事件”頁(yè)簽找到自動(dòng)生成的Event OnRep_CurrentHealth雙擊打開(kāi)。在此事件中我們可以添加客戶端的反饋。例如添加一個(gè)Print String節(jié)點(diǎn)打印“Health Changed: ” CurrentHealth的字符串。更實(shí)際的做法是這里可以驅(qū)動(dòng)UI血條更新、播放受傷音效或屏幕特效。設(shè)置游戲模式創(chuàng)建一個(gè)游戲模式藍(lán)圖BP_NetworkTestGameMode在其“類默認(rèn)值”中將“默認(rèn)Pawn類”設(shè)置為我們的BP_NetworkTestCharacter。在“項(xiàng)目設(shè)置 - 地圖與模式”中將“默認(rèn)游戲模式”設(shè)置為BP_NetworkTestGameMode。4.3 打包與局域網(wǎng)測(cè)試流程打包項(xiàng)目按照前文所述進(jìn)行Windows平臺(tái)打包。啟動(dòng)服務(wù)器在打包目錄運(yùn)行YourProjectServer.exe。觀察命令行窗口看到類似“LogNet: GameNetDriver: listening on port 7777”的日志表示服務(wù)器啟動(dòng)成功。啟動(dòng)客戶端A運(yùn)行YourProject.exe。進(jìn)入游戲后打開(kāi)控制臺(tái)~輸入open 127.0.0.1連接。啟動(dòng)客戶端B再運(yùn)行一個(gè)YourProject.exe進(jìn)程同樣連接127.0.0.1。測(cè)試控制客戶端A的角色移動(dòng)觀察客戶端B的窗口角色是否同步移動(dòng)。在客戶端A按下H鍵觀察客戶端A的屏幕上是否打印了扣血信息這是OnRep事件觸發(fā)的客戶端B的角色血條或打印信息是否也更新了這是變量復(fù)制的結(jié)果服務(wù)器命令行窗口是否有相關(guān)日志可以在Server RPC里加打印來(lái)驗(yàn)證關(guān)鍵觀察嘗試只在客戶端B按下H鍵會(huì)發(fā)現(xiàn)沒(méi)有任何反應(yīng)。因?yàn)榭蛻舳薆不是客戶端A角色的“擁有者Owner”它無(wú)權(quán)調(diào)用客戶端A角色上的Server RPC。這正符合網(wǎng)絡(luò)權(quán)限模型。5. 聯(lián)機(jī)調(diào)試與問(wèn)題排查實(shí)戰(zhàn)手冊(cè)即使按照步驟操作網(wǎng)絡(luò)問(wèn)題依然層出不窮。以下是經(jīng)過(guò)大量實(shí)戰(zhàn)總結(jié)的排查清單。5.1 連接失敗問(wèn)題排查問(wèn)題現(xiàn)象可能原因排查步驟客戶端無(wú)法連接到服務(wù)器Connection Failed1. 服務(wù)器未正確啟動(dòng)。2. 防火墻阻止連接。3. IP地址或端口錯(cuò)誤。4. 項(xiàng)目網(wǎng)絡(luò)設(shè)置錯(cuò)誤。1. 檢查服務(wù)器進(jìn)程是否運(yùn)行命令行有無(wú)報(bào)錯(cuò)。2. 暫時(shí)關(guān)閉防火墻測(cè)試或添加防火墻入站規(guī)則。3. 確認(rèn)服務(wù)器IP。單機(jī)測(cè)試用127.0.0.1局域網(wǎng)用服務(wù)器本機(jī)IP。4. 檢查“項(xiàng)目設(shè)置-引擎-網(wǎng)絡(luò)”中的默認(rèn)端口是否被占用。連接后立即斷開(kāi)Connection Lost1. 服務(wù)器和客戶端的游戲版本或內(nèi)容不匹配。2. 網(wǎng)絡(luò)同步出現(xiàn)致命錯(cuò)誤。1. 確保服務(wù)器和客戶端是同一打包版本。2. 查看服務(wù)器和客戶端的輸出日志Output Log尋找錯(cuò)誤或警告信息。5.2 網(wǎng)絡(luò)同步問(wèn)題排查問(wèn)題現(xiàn)象可能原因排查步驟客戶端看不到其他玩家移動(dòng)1. 角色藍(lán)圖的“Replicates”未勾選。2. 角色的MovementComponent未同步。3. 服務(wù)器未成功生成該角色。1. 確認(rèn)角色藍(lán)圖類默認(rèn)值中“Replicates”已勾選。2. Character默認(rèn)的移動(dòng)組件是同步的如果是自定義移動(dòng)需檢查。3. 在服務(wù)器端檢查角色是否成功生成打印日志。變量值不同步1. 變量未設(shè)置為“Replicated”。2. 變量所屬的Actor未設(shè)置“Replicates”。3. 變量在客戶端被本地修改覆蓋。1. 檢查變量詳情中的復(fù)制設(shè)置。2. 檢查Actor的“Replicates”屬性。3. 確保只在服務(wù)器修改該變量客戶端僅通過(guò)On Rep響應(yīng)。RPC調(diào)用無(wú)效1. RPC的復(fù)制條件不滿足如非擁有者調(diào)用Server RPC。2. RPC函數(shù)本身有錯(cuò)誤導(dǎo)致執(zhí)行失敗。3. 網(wǎng)絡(luò)連接不穩(wěn)定RPC丟失。1. 檢查調(diào)用者是否擁有正確的網(wǎng)絡(luò)角色Role。2. 在RPC函數(shù)內(nèi)添加打印語(yǔ)句查看是否被執(zhí)行。3. 使用UE內(nèi)置的網(wǎng)絡(luò)模擬Network Emulation工具測(cè)試丟包環(huán)境。5.3 高級(jí)調(diào)試工具與技巧netstat命令在命令行中輸入netstat -ano | findstr :77777777是你的端口可以查看該端口是否處于監(jiān)聽(tīng)LISTENING狀態(tài)以及有哪些進(jìn)程在連接。虛幻引擎內(nèi)置網(wǎng)絡(luò)統(tǒng)計(jì)在游戲運(yùn)行時(shí)按 **~** 打開(kāi)控制臺(tái)輸入stat net可以顯示詳細(xì)的網(wǎng)絡(luò)流量、丟包率、延遲等信息。stat fps 查看幀率。網(wǎng)絡(luò)模擬Network Emulation在編輯器播放模式下的“運(yùn)行Running”下拉菜單中可以啟用網(wǎng)絡(luò)模擬人為添加延遲Lag、丟包Packet Loss和抖動(dòng)Jitter用于測(cè)試游戲在網(wǎng)絡(luò)不佳環(huán)境下的表現(xiàn)??梢暬罩綱isual Logger對(duì)于復(fù)雜的狀態(tài)同步問(wèn)題可以使用Visual Logger記錄特定變量的變化和RPC的調(diào)用然后在編輯器中回放分析。確保確定性Determinism這是高級(jí)話題但至關(guān)重要。確保服務(wù)器和客戶端的邏輯計(jì)算結(jié)果是確定的。避免在游戲邏輯中使用本地時(shí)間、隨機(jī)數(shù)除非使用同步的隨機(jī)種子等非確定性因素否則會(huì)導(dǎo)致不同客戶端狀態(tài)逐漸偏離即“不同步”。最后的個(gè)人體會(huì)多人游戲開(kāi)發(fā)就像在指揮一個(gè)分布式的交響樂(lè)團(tuán)服務(wù)器是指揮每個(gè)客戶端是一個(gè)樂(lè)手。藍(lán)圖網(wǎng)絡(luò)事件就是樂(lè)譜上的各種記號(hào)。Event BeginPlay是樂(lè)手就位RPC是指揮發(fā)出的具體指令“小提琴組進(jìn)”Replicated Variable和On Rep是確保所有樂(lè)手看到同一頁(yè)樂(lè)譜并同步翻頁(yè)的機(jī)制。搭建局域網(wǎng)測(cè)試環(huán)境就是第一次帶妝彩排所有問(wèn)題都會(huì)暴露無(wú)遺。不要害怕在測(cè)試中遇到連接失敗、動(dòng)作不同步、變量對(duì)不上這些問(wèn)題每一個(gè)被解決的網(wǎng)絡(luò)Bug都會(huì)讓你對(duì)這套分布式系統(tǒng)的理解加深一分。從這個(gè)小Demo開(kāi)始嚴(yán)格區(qū)分服務(wù)器和客戶端的職責(zé)謹(jǐn)慎選擇每一個(gè)網(wǎng)絡(luò)事件你就能逐步搭建起穩(wěn)定、可預(yù)測(cè)的多人游戲體驗(yàn)。