Minecraft的地圖更新邏輯是這樣的[1]

通常,只有圍繞玩家的大部分區塊才會被遊戲更新。這些區塊被稱為玩家的區塊更新範圍。當玩家在世界中移動時,進入範圍的新區塊會被添加到更新區塊的列表中,並且在範圍之外的舊區塊將被移除。只有在列表中的區塊才會被更新以反映時間的流逝。這意味著例如當玩家在其他維度中花上太多時間去探索時,他種下的農作物不會生長,並且烹飪、燒煉或自動化農場在他回來之前都不會完成。


雖然我不了解Minecraft的遊戲設計機制,不過題主所說的』還是說一下子就把整個地圖下載下來,然後只同步地圖更新的事件『 的說法應該是不對的。

原因很簡單,以下是Glavocraft上一個周目的離線地圖存檔+遊戲本體:

然後Galvocraft本周目用到的客戶端大小:

參考

  1. ^https://minecraft-zh.gamepedia.com/%E5%B8%B8%E5%8A%A0%E8%BD%BD%E5%8C%BA%E5%9F%9F


多人不是特別清楚,單機的操作是,當一個區域附近首次有玩家存在時,生成區塊信息,並將其存入region(主世界)或DIM_1(地獄)或DIM1(末地)的.mca文件里;然後若此區域附近有玩家,將信息存入內存進行載入,否則將之從內存卸載(spawn chunk和受/forceload影響的區塊例外,這些區塊永不卸載,甚至即使你不在對應維度)

多人的話,懷疑可能是在單機的區塊生成和載入機制的基礎上,僅將玩家附近的那些區域下載了下來。推測的理由是,當你網路狀態很差的時候,你所在的區域不會卸載消失,但是當你試圖往遠走的時候,會看到明顯的已載入/未載入區塊邊界。如果整個地圖都下載的話,應該是能夠進一步載入遠處的區域的(因為這將不再需要網路;雖然裡面的生物什麼的應該都不會動,因為這部分內容沒同步)。另一個理由是,有些地圖實際上非常大,但是流量監控顯示玩一次mc並沒有如此巨大的流量消耗,這隻能表明地圖並沒有被全部下載。


首先多人遊戲的地圖是走到哪裡下載哪裡的,但是不是圓,而是正方形。

正方形的大小可以在server.properties中設置,即view-distance

這個值默認為10,代表玩家為中心,上下左右各數10個區塊,也就是21*21的範圍,441個區塊,當玩家走動時會影響區塊傳遞和載入。

當地圖發生更新時,有兩種情況

  1. 如果更新的是實體(或方塊實體),那就不用重傳區塊,直接傳輸實體信息
  2. 如果更新的是方塊,就會重傳整個區塊(16*16*255個block)。特別的,如果更新的是區塊邊上的方塊,則有可能會造成隔壁區塊更新,這時候就會重傳多個區塊

所以你在玩mc的過程中,如果遇到區塊載入或者渲染出錯,在隔壁區塊放置或破壞一個方塊就有可能恢復正常


作為一個mod開發初學者來說說我的理解。

一般的處理機制是,玩家把動作上傳到伺服器,由伺服器進行合法性驗證並處理,更改存檔文件。

而客戶端會不斷的嘗試與伺服器同步附近的區塊,同步的數量與伺服器的視野範圍設置有關。

因此,在網路或伺服器卡頓時會發現一種現象,剛挖的方塊重新出現,就是因為伺服器還沒對你的操作進行處理,所以客戶端仍然使用你挖掉方塊之前的地圖,直到同步為止。

客戶端只會等待伺服器的處理結果,不會自己處理,在mcp反編譯的源代碼中,很多操作都會使用「world.isRemote」來判斷當前遊戲環境是客戶端還是服務端,比如經驗變更、方塊變更等,如果把這些操作用於客戶端,會引起數據不同步。在編寫mod的過程中,也要在這些操作前確保world.isRemote為false.

先說這些,想到其他了再更


只會載入玩家附近的區塊,根據伺服器視距大小發送對應範圍的區塊數據


也沒關心是怎樣的,反正看到人就想打,看到動物就想砍,看到花兒就想采,當然,還有其他的,多多益善嘛哈哈哈哈哈哈哈


全文瞎猜,想要正確答案自己去找會翻代碼的人。

首先排除「整張地圖全都下載」,桃子吃不完拿出來分了。這樣既佔用帶寬還沒啥屁用,畢竟下載下來玩家還得渲染呢。

至於破壞方塊後的同步,應該是「將破壞方塊的動作上傳至伺服器,在進行處理,處理後下發到客戶端,單位為一個區塊(16*16*16)」。


// Tank for invte

你好,大家。我是王弟的室友、DRE。我今天很光榮能有這個機會可以在這為大家講解 么C (又名 micro福特) 的本地區塊管理系統。也請大家多多指教。。。

這裡以 Minecraft/17w16a 的版本為參照,將大致的說到 [1]世界的載入(何時),[2]世界的運行(何樣),[3]區塊的載入(何時,何法),[4]區塊的卸載(何時,何發,會怎樣),[5]C/S大致的方塊數據的同步概念。

1/Load of the WorLds

本人認為世界的單純載入並不意味著極大的能源開銷問題,你們知道,高密度的方塊各種更新 不小量的實體較高密度更新 是較為耗費資源的 不僅是運算的時間資源,運行時存儲的空間資源在早期時候也讓人有些在意。然而即使這樣,我認為很多時候也可以在伺服器開啟時載入所有世界。但這並不意味著非法開銷問題,亦或功能設定的問題。

3dLord of Chunks

區塊的載入很大程度上取決於一個 於server.management中的一個程序 ChunkMap。ChunkMap 持有著一列 ChunkMapEntry, 每個Entry對應一位區塊 記錄其被「看」到的玩家(這是一點。下文計做listeningPlayers計數器。) 及各種相關該區塊的一些相關管理數據。

// 轉自一張圖片。。

圖中的每個瓦塊,對應著一個區塊/ChunkMapEntry。其中有3個大的"塊",代表三個玩家各自所能看到的區塊(雖然圖中沒有標明界限)。可見圖中他們各自有不同的viewDistance(通常由伺服器端決定)。假設實際情況如圖中所示,最上面一行瓦塊對應的區塊,只有被一名玩家所看到(最上面那位),因為size(listeningPlayers)不為0,所以那些區塊被載入 並收到更新後會傳遞給區塊的listeningPlayers。而第五行第五列(從1開始數的話。。)的瓦塊所對應的區塊Entry的listeningPlayers則有2為,分別是最上面那位,和中間(垂直方向)那位。所以該區塊的更新會傳遞給這兩位人士。

其實圖中已經詮釋了情況,從一個層度來看,區塊列表活動管理可視為 1. load/unload 載入/卸載,和 2. 發生改變。載入/卸載將在lisneningPlayers計數器發生變化時發生 僅當計數器從0變為1時區塊被載入,當從正數變為0時區塊被卸載。而發生的改變則將通過listeningPlayers傳遞給對應正在"收聽/可見"該區塊的人士 。

區塊載入於提供區塊時。這將首先會檢查已被載入/運行的區塊列表,假設沒有,那麼檢查從存檔載入,若存檔也沒有該區塊,那麼則生成一位區塊。

4. unloadChunk(si

上文其實有提到,在listeningPlayers從正數(實際上是1,因為即使是1以上 也是遞減至1。。)變為0時,區塊卸載發生。與之而來的 還有一個呼叫客戶端區塊卸載。若一個區塊Entry的listeningPlayers被減少一位人士後(通常因為該人類跑的太遠了 其的viewDistans 看不到該區塊了),會發送一個數據包給該客戶端,告訴他需要卸載一個區塊 並包含該區塊的地址 隨後客戶端將會卸載該區塊以讓客戶端玩家不必持有過多非法不被管理的區塊。然而與之對應的 還有一個當玩家被添加到一個區塊Entry的listeningPlayers時的操作,那就是發送整個區塊的數據 並讓該客戶端讀/顯示該區塊。值得一提的是,通常玩家對方塊的操作 或小量方塊更新,只會涉及到對應被更新的方塊的數據傳輸,整體的區塊數據傳輸通常在玩家剛載入該區塊時發送。

5. trans of blocks in net sync

在第4段中,有提到一些關於方塊傳輸的內容。是的,小量方塊更新 通常僅傳輸對應被更新的方塊。然而,每個被載入的區塊對應的瓦塊,區塊Entry的listeningPlayers計數器又是怎樣被更新 增加/減少的。。。這其實則是 ChunkMap 的行為。在world.onTick() 時, ChunkMap被更新,通過遍歷每個在該天地玩家,遍歷其視野距離 判斷能被其看到的區塊,再遍歷這些能被其看到的區塊 若該區塊所對應的區塊Entry的listeningPlayers包含他的話,那麼不做什麼,若不包含他,則添加他進去,並將該區塊的數據發送給他。遍歷完所有玩家後,開始遍歷所有已被載入的區塊,判斷每個區塊是否能被每個玩家所見,從對應該區塊的區塊Entry的listeningPlayers中去掉不可見該區塊的玩家,並發送數據包讓其客戶端卸下該區塊。


推薦閱讀:
相关文章