国产精品va,亚洲免费视频网,日本久久久久久久久久,91啪在线,呦女专区,日韩欧美在线播放,国产精品资源在线

服務熱線熱線:

13818745178

九游(ninegame)娛樂中國官方網(wǎng)頁-企業(yè)入口

企業(yè)動態(tài)

關于unreal-engine4:Exploring--UE4Unreal回放系統(tǒng)剖析上

發(fā)布時間:2025-05-10點擊次數(shù):

  回放,是電子游戲中一項常見的性能,用于記錄整個較量過程或者展現(xiàn)游戲中的精彩霎時。通過回放,咱們能夠觀摩高手之間的對決,享受游戲中的精彩霎時,甚至還能夠拿到敵方玩家的較量錄像進行剖析和學習。

  FIFA / 實況足球 / NBA2K / 守望先鋒 / 極限競速:地平線 / 跑跑卡丁車

  守望先鋒 / CSGO / Dota / LOL / 魔獸爭霸 / 星際爭霸 / 紅色警戒 / 坦克世界 / 絕地求生 / 王者光榮

  早在 20 世紀 90 年代,回放零碎就曾經(jīng)誕生并寬泛用于即時戰(zhàn)略、第一人稱射擊以及體育競技等類型的游戲當中,而那時存儲器的容量十分無限,遠遠無奈與當今動輒幾十 T 的硬盤等量齊觀,面對一場數(shù)十分鐘的較量,較量數(shù)據(jù)該如何存儲和播放?回放該如何實現(xiàn)?這篇文章會通過分析 UE 的回放零碎,來由淺入深地幫忙大家了解其中的原理和細節(jié)。

  盡管不同游戲里回放零碎具體的實現(xiàn)形式與利用場景不同,但實質(zhì)上都是對數(shù)據(jù)的記錄和重現(xiàn),這個過程與網(wǎng)絡游戲外面的同步技術十分類似。舉個例子,如果 AB 兩個客戶端進行 P2P 的連貫對戰(zhàn),A 客戶端上開始時并沒有對于 B 的任何信息。當建設連貫后,B 開始把本人的相干信息(坐標,模型,大小)發(fā)給 A,A 在本人的客戶端上利用這個信息從新構建了 B,實現(xiàn)了數(shù)據(jù)的同步。

  思考一下,如果 B 不把這個信息發(fā)給 A,而發(fā)給本人進行解決,是不是就相當于錄制了本人的機器上的較量信息再進行回放呢?

  沒錯,網(wǎng)絡游戲中的同步信息正是回放零碎中的錄制信息,因而網(wǎng)絡同步就是實現(xiàn)回放零碎的技術根底!

  在正式介紹回放零碎前,無妨先概括地介紹一下游戲開發(fā)中的網(wǎng)絡同步技術。咱們常說網(wǎng)絡同步能夠簡略分為幀同步、快照同步和狀態(tài)同步

  ,對應的英文概念是 LockStep/Deterministic Lockstep。其基本思路是每固定距離(如 0.02 秒)對玩家的行為進行一次采樣失去一個“Input 指令”并發(fā)送給其余所有玩家,每個玩家都緩存來自其余所有玩家的“Input 指令”,當某個玩家收到所有其余玩家的“Input 指令”后,他的本地游戲狀態(tài)才會推動到下一幀。

  ,能夠翻譯成 Snapshot Synchronization。其思維是服務器把以后這幀整個游戲世界的狀態(tài)進行一個備份,而后把這個備份發(fā)送給所有客戶端,客戶端依照這個備份對本人的世界狀態(tài)進行批改和糾正進而實現(xiàn)同步。(快照,對應的英文概念是 SnapShot,強調(diào)的是某一時刻的數(shù)據(jù)狀態(tài)或者備份。從游戲世界的角度了解,快照就是整個世界所有的狀態(tài)信息,包含對象的數(shù)量、對象的屬性、地位線信息等。從每個對象的角度了解,快照就是指整個對象的各種屬性,比方生命值、速度這些。所以,不同場景下快照所指的內(nèi)容可能是不同的。)

  ,能夠翻譯成 State(State Based)Synchronization。其思維與快照同步類似,也是服務器將世界的狀態(tài)同步給客戶端。但不同的是狀態(tài)同步的粒度變得十分?。ㄒ詫ο蠡蛘邔ο蟮膶傩詾閱挝唬?,服務器不須要把一幀外面所有的對象狀態(tài)進行保留和同步,只須要把客戶端須要的那些對象以及須要的屬性進行保留和發(fā)送即可。

  拓展:快照同步其實是狀態(tài)同步的前身,那時候整個游戲須要記錄的數(shù)據(jù)量還不是很大,人們也天然的應用快照來代表整個世界在某一時刻的狀態(tài),通過定時地同步整個世界的快照就能夠做到完滿的網(wǎng)絡同步。然而這種間接把整個世界的狀態(tài)進行同步的過程是很消耗流量和性能的,思考到對象的數(shù)據(jù)是逐漸產(chǎn)生變動的,咱們能夠只記錄發(fā)生變化的那些數(shù)據(jù),所以就有了基于 delta 的快照同步。更進一步的,咱們能夠把整個世界拆分一下,每一幀只針對須要的對象進行 delta 的同步,這樣就齊全將各個對象的同步拆分開來,再聯(lián)合一些過濾能夠進一步縮小沒必要的數(shù)據(jù)同步,最初造成了狀態(tài)同步的計劃。更多對于網(wǎng)絡同步技術的倒退和細節(jié)能夠參考我的文章——《細談網(wǎng)絡同步在游戲歷史中的倒退變動》。

  在空幻引擎外面,默認實現(xiàn)的是一套絕對欠缺的狀態(tài)同步計劃,場景外面的每個對象都稱為一個 Actor,每個 Actor 都能夠獨自設置是否進行同步(Actor 身上還能夠掛 N 個組件,也能夠進行同步),Actor 某一時刻的標記 Replicated 屬性就是所謂的狀態(tài)信息。服務器在每幀 Tick 的時候,會去判斷哪些 Actor 應該同步給哪些客戶端,哪些屬性須要進行同步,而后對立序列化成二進制(能夠了解為一個以后世界狀態(tài)的增量快照)發(fā)給對應的客戶端,客戶端在收到后還能夠調(diào)用回調(diào)函數(shù)進一步解決。這種通信形式咱們稱為屬性同步。

  此外,UE 外面還有另一種通信形式叫 RPC,能夠像調(diào)用本地函數(shù)那樣來調(diào)用遠端的函數(shù)。RPC 罕用于做一些跨端的事件告訴,盡管并不嚴格屬于傳統(tǒng)意義上狀態(tài)同步的領域,但也是 UE 網(wǎng)絡同步外面不可短少的一環(huán)。

  網(wǎng)絡驅(qū)動治理,封裝了同步 Actor 的基本操作,還包含初始化客戶端與服務器的連貫,建設屬性同步記錄表,解決 RPC 函數(shù),創(chuàng)立 Socket,構建并治理 Connection 信息,接管數(shù)據(jù)包等等基本操作。

  示意一個網(wǎng)絡連接。服務器上,一個客戶端到一個服務器的一個連貫叫一個 ClientConnection。在客戶端上,一個服務器到一個客戶端的連貫叫一個 ServerConnection。

  數(shù)據(jù)通道,每一個通道只負責替換某一個特定類型特定實例的數(shù)據(jù)信息。比方一個 ActorChannel 只負責解決對應 Actor 自身相干信息的同步,包含本身的同步以及子組件、屬性的同步、RPC 調(diào)用等。

  聯(lián)合咱們后面提到的網(wǎng)絡同步技術,如果咱們當初想在游戲外面錄制一場較量要怎么做呢?是不是像快照同步一樣把每幀的狀態(tài)數(shù)據(jù)記錄下來,而后播放的時候再去讀取這些數(shù)據(jù)呢?沒錯!利用網(wǎng)絡同步的思維,把游戲自身當成一個服務器,游戲內(nèi)容當成同步數(shù)據(jù)進行錄制存儲即可。

  當然對于幀同步來說,咱們并不會去記錄不同時刻世界的狀態(tài)信息,而是把關注點放在了玩家的行為指令上(Input 隊列)。幀同步會默認各個客戶端的初始狀態(tài)完全一致,只有保障同一時刻每個指令的雷同,那么客戶端上整個游戲世界的推動和體現(xiàn)也應該是齊全一樣的(須要解決浮點數(shù)精度、隨機數(shù)一致性問題等)。因為只須要記錄玩家的行為數(shù)據(jù),所以一旦幀同步的框架實現(xiàn),其回放零碎的實現(xiàn)是十分不便和輕量化的。

  錄制:就像服務器網(wǎng)絡同步一樣,每幀去記錄所有對象(Actor)的狀態(tài)信息,而后通過序列化的形式寫到一個緩存外面。

  在 EpicLancher 外面引擎(我應用的是 4.26 版本),創(chuàng)立一個第三人稱的模板工程命名為 MyTestRec;

  與數(shù)據(jù)的存儲流程相同,當咱們通過 PlayReplay 開始播放回放時,須要先從對應的 NetworkReplayStreamer 外面取出回放數(shù)據(jù),而后解析成 FQueuedDemoPacket 數(shù)組。隨后每幀在 TickDemoPlayback 依據(jù) Packet 外面的工夫戳繼續(xù)一直地進行反序列化來復原場景外面的對象。到這里,咱們曾經(jīng)整頓出了錄制和回放的大抵流程和入口地位。但為了能循序漸進地分析回放零碎,我還成心暗藏了很多細節(jié),比如說 NetworkReplayStreamer 外面是如何存儲回放數(shù)據(jù)的?回放零碎如何做到從指定工夫開始播放的?想弄清這些問題就不得不進一步剖析回放相干的數(shù)據(jù)結構與組織思維。

  無論通過哪種形式實現(xiàn)回放都肯定會波及到快進、暫停、跳轉(zhuǎn)等相似的性能。然而,咱們目前應用的形式并不能很好地反對跳轉(zhuǎn),次要問題在于空幻引擎默認應用增量式的狀態(tài)同步,任何一刻的狀態(tài)數(shù)據(jù)都是后面所有狀態(tài)同步數(shù)據(jù)的疊加,必須從最開始播放能力保障不失落掉兩頭的任何一個數(shù)據(jù)包。比方下圖的例子,如果我想從第 20 秒開始播放并且從第 5 個數(shù)據(jù)包開始加載,那么肯定會失落 Actor1 的創(chuàng)立與移動信息。

  數(shù)據(jù)流在錄制的時候兩頭是沒有明確宰割的,也就是所有的序列化數(shù)據(jù)都嚴密地連貫在一起的,無奈進行拆分,只能從頭開始一點點讀取并反序列化解析。兩頭哪怕丟了一個字節(jié)的數(shù)據(jù)都可能造成前面的數(shù)據(jù)解析亂掉。

  存檔點,即一個殘缺的世界快照(相似單機游戲中的存檔),通過這個快照能夠齊全回復過后的游戲狀態(tài)。每隔一段時間(比方 30s)存儲一個 Checkpoint。

  一段間斷工夫的數(shù)據(jù)流,存儲著從上一個 Checkpoint 到以后的所有序列化錄制數(shù)據(jù)。

  通過這種形式,咱們在任何時刻都能夠找到一個鄰近的全局快照(Checkpoint)并進行加載,而后再依據(jù)最終目標的工夫疾速地讀取后續(xù)的 Stream 信息來實現(xiàn)目標地位的跳轉(zhuǎn)。拿后面的案例來說,因為我當初在 20s 的時候能夠通過 Checkpoint 的加載而失去后面 Actor1 在以后的狀態(tài),所以能夠完滿地實現(xiàn)跳轉(zhuǎn)性能。在理論錄制的時候,ReplayHelper 的 FQueuedDemoPacket 其實有兩個,別離用于存儲 Stream 和 Checkpoint。

  每次回放開始前咱們都能夠傳入一個參數(shù)用來指定跳轉(zhuǎn)的工夫點,隨后就會開啟一個 FPendingTaskHelper 的工作,依據(jù)指標工夫找到后面最靠近的快照,并通過 UDemoNetDriver:: LoadCheckpoint 函數(shù)來反序列化復原場景對象數(shù)據(jù)(這一步實現(xiàn) Checkpoint 的加載)。

  如果指標工夫比快照的工夫要大,則須要在 ConditionallyReadDemoFrameInto PlaybackPackets 疾速地把這段時間差的數(shù)據(jù)包全副讀出來并進行解決,默認狀況下在一幀內(nèi)實現(xiàn),所以玩家并無感知(數(shù)據(jù)流太大的話會造成卡頓,能夠思考分幀)。

  Archive 能夠翻譯成檔案,在空幻外面是用來存儲序列化數(shù)據(jù)的類。其中 FArchive 是數(shù)據(jù)存儲的基類,封裝了一些序列化 / 反序列化等操作的接口。咱們能夠通過繼承 FArchive 來實現(xiàn)自定義的序列化操作。

  那這兩個 Archive 具體是如何存儲和保護的呢?為了能有一個直觀的展現(xiàn),倡議大家先去依照 2.3 小結的形式去操作一下,而后就能夠在你工程下 /Saved/Demo/ 門路下失去一個回放的文件。這個文件次要存儲的就是多個 Stream 和一個 Checkpoint,關上后大略如下圖(因為是序列化成了 2 進制,所以是不可讀的)

  而在讀取播放時,數(shù)據(jù)的解決流程會有一些差別。零碎會嘗試一次性從磁盤加載所有信息到一個用于組織回放的數(shù)據(jù)結構中——FLocalFileReplayInfo

  3.3.3 回放架構梳理小結到此,咱們曾經(jīng)對整個零碎有了更深刻的了解,再回頭看整個回放的流程就會清晰很多。

  上個小結咱們曾經(jīng)從架構的角度上梳理了回放錄制的原理和過程,然而還有很多細節(jié)問題還沒有深究,比方:

  這些問題看似簡略,但實現(xiàn)起來卻并不容易。比方咱們在播放時須要動靜切換特定的攝像機視角,那就須要曉得 UE 外面的攝像機零碎,包含 Camera 的治理、如何設置 ViewTarget、如何通過網(wǎng)絡 GUID 找到對應的指標等,這些內(nèi)容都與游戲玩法高度耦合,因而在剖析錄制加載細節(jié)前倡議先回顧一下 UE 的 Gameplay 框架。

  UE 的 Gameplay 根本是依照面向?qū)ο蟮男问絹碓O計的,波及到常見概念(類)如下:

  一個可控的游戲單位,Character 相比 Pawn 多了很多人型角色的性能,比方挪動、下蹲、跳躍等

  所有攝像機相干的性能都通過 CameraManager 治理,比方攝像機的地位、攝像機觸動成果等

  概括來講,一個游戲場景是一個 World,每個場景能夠拆分成很多子關卡(即 Level),咱們能夠通過配置 Gamemode 參數(shù)來設置游戲規(guī)則(只存在與于服務器),在 Gamestate 上記錄以后游戲的較量狀態(tài)和進度。對于每個玩家,咱們個別至多會給他一個能夠管制的角色(即 Pawn/Character),同時把這個角色相干的數(shù)據(jù)存儲在 Playerstate 上。最初,針對每個玩家應用惟一的一個控制器 Playercontroller 來響應玩家的輸出或者執(zhí)行一些本地玩家相干的邏輯(比方設置咱們的察看對象 VIewTarget,會調(diào)用到 Camermanager 相干接口)。此外,PC 是網(wǎng)絡同步的要害,咱們須要通過 PC 找到網(wǎng)絡同步的中心點進而剔除不須要同步的對象,服務器也須要依附 PC 能力判斷不同的 RPC 應該發(fā)給哪個客戶端。

  回放零碎 Gameplay 邏輯仍然遵循 UE 的根底框架,但因為只波及到數(shù)據(jù)的播放還是有不少須要留神的中央。

  在一個 Level 里,有一些對象是默認存在的,稱為 StartupActor。這些對象的錄制與回放可能須要非凡解決,比方回放一開始就默認創(chuàng)立,盡量避免動靜的結構開銷。

  UE 的網(wǎng)絡同步自身須要借助 Controller 定位到 ViewTarget(同步核心,便于做范疇剔除),所以回放錄制時會創(chuàng)立一個新的 DemoPlayerController(留神:因為在本地可能同時存在多個 PC,獲取 PC 時不要拿錯了)。這個 Controller 的主要用途就是輔助同步邏輯,而且會被錄制到回放數(shù)據(jù)外面。

  回放零碎并不限度你的察看視角,然而會默認提供一個自在挪動的觀戰(zhàn)對象(SpectatorPawn)。當咱們播放時會收到同步數(shù)據(jù)并創(chuàng)立 DemoPC,DemoPC 會從 GameState 上查找 SpectatorClass 配置并生成一個用于觀戰(zhàn)的 Pawn。咱們通常會 Possess 這個對象并挪動來管制攝像機的視角,當然也能夠把觀戰(zhàn)視角鎖定在游戲中的其余對象上。

  回放不倡議錄制 PlayerController(簡稱 PC),游戲中的與玩家角色相干的數(shù)據(jù)也不應該放在 PC 上,最好放在 PlayerState 或者 Character 下面。為什么回放不解決 PC?次要起因是每個客戶端只有一個 PC。如果我在客戶端下面錄制回放并且把很多重要數(shù)據(jù)放在 PC 上,那么當你回放的時候其余玩家 PC 上的數(shù)據(jù)你就無奈拿到。

  回放不會錄制 Gamemode,因為 Gamemode 只在服務器才有,并不做同步。

  RPC 的目標是跨端近程調(diào)用,九游娛樂平臺對于非多播的 RPC,他只會在某一個客戶端或者服務器下面執(zhí)行。也就是說,我在服務器上錄制就拿不到客戶端的 RPC,我在客戶端上錄制就拿不到服務器上的 RPC,總會失落掉一些 RPC。

  RPC 是冗余的,可能咱們在回放的時候不想調(diào)用。比方服務器觸發(fā)了一個 ClientRPC(讓客戶端播放攝像機觸動)并錄制,那么回放的時候我作為一個觀戰(zhàn)的視角不應該調(diào)用這個 RPC(當然也能夠自定義的過濾掉)。

  RPC 是一個無狀態(tài)的告訴,一旦錯過了就再也無奈獲取?;胤胖谐3泄し虻奶D(zhuǎn),跳轉(zhuǎn)之后咱們再就無奈拿到后面的 RPC 了。如果咱們適度依賴 RPC 做邏輯解決,就很容易呈現(xiàn)回放體現(xiàn)不對的狀況。

  綜上所述,我并不倡議在反對回放零碎的游戲外面頻繁應用 RPC,最好應用屬性同步來代替,這樣也能很好的反對斷線重連。

  4)導出所有同步屬性根本信息 FieldExport GroupMap,用于播放時精確且能兼容地接管這些屬性

  調(diào)用 ProcessReplayTasks 解決以后正在執(zhí)行的工作,如果工作沒有實現(xiàn)就返回(工作有很多種,比方 FGotoTime InSecondsTask 就是用來執(zhí)行工夫跳轉(zhuǎn)的工作)

  拿到 StreamArchive,設置以后回放的工夫(回放工夫決定了以后回放數(shù)據(jù)加載的進度)

  去 PlaybackPackets 查找是否還有待處理的數(shù)據(jù),如果沒有數(shù)據(jù)就暫?;胤?/p>

  ConditionallyReadDemo FrameIntoPlaybackPackets 依據(jù)以后的工夫,讀取 StreamArchive 外面的數(shù)據(jù),緩存到 PlaybackPackets 數(shù)組外面

  ConditionallyProcess PlaybackPackets 一一去解決 PlaybackPackets 外面的數(shù)據(jù),進行反序列化的操作(這一步是還原數(shù)據(jù)的要害,回放 Actor 的創(chuàng)立通常是這里觸發(fā)的)

  FinalizeFastForward 解決快進等操作,因為咱們可能在一幀的時候解決了回放 N 秒的數(shù)據(jù)(也就是快進),所以這里須要把被快進掉的回調(diào)函數(shù)(OnRep)都執(zhí)行到,同時記錄到底快進了多少工夫

  在 2.3.2 大節(jié),咱們提到了 UE 的網(wǎng)絡同步形式為增量式的狀態(tài)同步,任何一刻的狀態(tài)數(shù)據(jù)都是后面所有狀態(tài)同步數(shù)據(jù)的疊加,所以必須從最開始播放能力保障不失落掉兩頭的任何一個數(shù)據(jù)包。想要實現(xiàn)快進和工夫跳躍必須通過加載最近的 Checkpoint 能力實現(xiàn)。

  在每次開始回放前,咱們能夠給回放指定一個指標工夫,而后回放零碎就會創(chuàng)立一個

  。基本思路是先找到左近的一個 Checkpoint(快照點)加載,而后疾速讀取從 Checkpoint 工夫到指標工夫的數(shù)據(jù)包進行解析。這個過程中有很多細節(jié)須要了解,比方咱們從 20 秒跳躍到 10 秒的時候,20 秒時刻的 Actor 是不是都要刪除?刪除之后要如何再去創(chuàng)立一個新的和 10 秒時刻截然不同的 Actor?無妨帶著這些問題去了解上面的流程。

  3)刪除掉所有非 StartUp(StartUp:一開始擺在場景里的)的 Actor,StartUp 依據(jù)狀況選擇性刪除(在跳轉(zhuǎn)進度的時候,整個場景的 Actor 可能曾經(jīng)齊全不一樣了,所以最好全副刪除,對于擺在場景外面的可毀壞墻,如果沒有產(chǎn)生過變動能夠無需解決,如果被打壞了則須要刪除從新創(chuàng)立)。

  除此之外,咱們還提到了回放的暫停。其實暫停分為兩種,一種是暫?;胤艛?shù)據(jù)的錄制 / 讀取,通過 UDemoNetDriver:: PauseRecording 能夠?qū)崿F(xiàn)暫?;胤诺匿浿?,通過 PauseChannels 能夠暫?;胤潘?Actor 的體現(xiàn)邏輯(個別是在加載 Checkpoint、快進、沒有數(shù)據(jù)讀取時主動調(diào)用),然而不會進行 Tick 等邏輯執(zhí)行。另一種暫停是暫停 Tick 更新(也能夠用于非回放世界),通過 AWorldSetting:: SetPauserPlayerState 實現(xiàn),這種暫停不僅會進行回放數(shù)據(jù)包的讀取,還會進行 WorldTick 的更新,包含動畫、挪動、粒子等,是嚴格意義上的暫停。

  3.5.1 回放兼容性的意義回放的錄制和播放往往不是一個機會,玩家可能了回放后過了幾天才想起來觀看,甚至還會用曾經(jīng)降級到 5.0 的游戲版本去播放 1.0 時的回放數(shù)據(jù)。因而,咱們須要有一個機制來盡可能地兼容過來一段時間游戲版本的回放數(shù)據(jù)。

  因為代碼在迭代的時候,函數(shù)流程、數(shù)據(jù)格式、類的成員等都會發(fā)生變化(減少、刪除、批改),游戲邏輯是必須要依賴這些內(nèi)容能力正確執(zhí)行。舉個例子,如果 1.0 版本的代碼中類 ACharacter 上有一個成員變量 FString CurrentSkillName 記錄了游戲角色以后的技能名字,在 2.0 版本的代碼時咱們把這個成員刪掉了。因為在 1.0 版本錄制的數(shù)據(jù)外面存儲了 CurrentSkillName,咱們在應用 2.0 版本代碼執(zhí)行的時候必須得想方法繞過這個成員,因為這個值在以后版本外面沒有任何意義,強行應用的話可能造成回放失常的數(shù)據(jù)被籠罩掉。

  其實不只是回放,咱們?nèi)粘T趹镁庉嬈鞯裙ぞ邥r,只有同時波及到對象的序列化(通用點來講是固定格局的數(shù)據(jù)存儲)以及版本迭代就肯定會遇到相似的問題,輕則導致引擎資源有效重則產(chǎn)生解體。

  在 UE 的回放零碎外面,兼容性的問題還要更簡單一些,因為波及到了空幻網(wǎng)絡同步的實現(xiàn)原理。

  第一節(jié)咱們談到了空幻有屬性同步和 RPC 兩種同步形式,且二者都是基于 Actor 來實現(xiàn)的。在每個 Actor 同步的時候,咱們會給每個類創(chuàng)立一個 FClassNetCache 用于惟一標識并緩存他的同步屬性,每個同步屬性 /RPC 函數(shù)也會被惟一標識并緩存其相干數(shù)據(jù)在 FFieldNetCache 構造外面。因為同一份版本的客戶端代碼和服務器代碼雷同,咱們就能夠保障客戶端與服務器每個類的 FClassNetCache 以及每個屬性的 FFieldNetCache 都是雷同的。這樣在同步的時候咱們只須要在服務器上序列化屬性的 Index 就能夠在客戶端反序列化的時候通過 Index 找到對應的屬性。

  這種計劃的實現(xiàn)前提是客戶端與服務器的代碼必須是一個版本的。如果客戶端的類成員與服務器對應的類成員不同,那么這個 Index 在客戶端上所代表的成員就與服務器上的不統(tǒng)一,最終的執(zhí)行后果就是謬誤的。所以對于失常的游戲來說,咱們必須要放棄客戶端與服務器版本雷同。然而對于回放這種可能跨版本執(zhí)行的狀況就須要有一個新的兼容計劃。

  盡管這種形式減少了同步的開銷和老本,但對于回放零碎來說是能夠承受的,而且回放的整個錄制過程中是齊全牢靠的,不會因為丟包而產(chǎn)生播放時導出數(shù)據(jù)沒收到的狀況。這樣即便我新版本的對象屬性數(shù)量發(fā)生變化(比方程序發(fā)生變化),因為我在回放數(shù)據(jù)外面曾經(jīng)存儲了這個對象所有會被序列化的屬性信息,我肯定能找到對應的同步屬性,而對于曾經(jīng)被刪掉的屬性,我回放時本地代碼創(chuàng)立的 FClassNetCache 不蘊含它,因而也不會被利用進來。

  到這里,咱們基本上能夠了解空幻引擎對回放零碎的向后兼容性計劃。然而即便有了下面的計劃,咱們其實也只是兼容了類成員產(chǎn)生扭轉(zhuǎn)的狀況,保障了不會因為屬性失落而呈現(xiàn)邏輯的謬誤執(zhí)行。然而對于新增的屬性,因為原來存儲的回放文件外面基本不存在這個數(shù)據(jù),回放的時候是齊全不會有任何相干的邏輯的。因而,所謂回放零碎的兼容也只是有肯定限度的兼容,想很好地反對版本差別過大的回放文件還是絕對艱難許多的。

  這是侑虎科技第 1367 篇文章,感激作者 Jerish 供稿。歡送轉(zhuǎn)發(fā)分享,未經(jīng)作者受權請勿轉(zhuǎn)載。如果您有任何獨到的見解或者發(fā)現(xiàn)也歡送分割咱們,一起探討。(QQ 群:465082844)

上一篇:虛幻4引擎(Unreal Engine4)

返回列表

下一篇:Unreal Engine虛幻游戲引擎擴展資料 - 工業(yè)城市