CaptainZ

CaptainZ

Prompt Engineer. Focusing on AI, ZKP and Onchain Game. 每周一篇严肃/深度长文。专注于AI,零知识证明,全链游戏,还有心理学。
twitter

Curio是如何把ECS遊戲引擎內置到OPStack中的?

bcd

5 月 31 日,Curio(@0xcurio)開源了 Keystone,一個內置了遊戲 Tick 和 ECS 全鏈遊戲引擎的 L2 鏈,該鏈基於 OP Stack 製作。相比通過智能合約編寫 ECS 狀態,這種設計允許所有 ECS 操作(如查詢和狀態設置)具有更快的性能。通過自定義預編譯,智能合約可以訪問底層的 ECS 鏈狀態。遊戲邏輯可以用 Go 語言編寫,而不是 Solidity,這可以大規模並行化。本文將對 Curio 項目本身,以及它的原理做深度剖析,並探討它是如何實現上述目的的。

Curio 由工程師和遊戲玩家 Kevin Zhang (@kzdagoof)和 Yijia Chen (@0x1plus)於 2022 年創立,致力於製作完全由智能合約驅動的全鏈遊戲。這使得一種新的多人計算方式成為可能,允許所有參與者為「共享宇宙」做出貢獻,創始人表示這讓遊戲可以幾乎完全由玩家創造。該公司的第一款遊戲 Treaty 是一款鏈上策略遊戲,用戶可以在其中編寫和部署智能合約。2023 年 2 月 21 日,Curio 宣布完成 290 萬美元種子輪融資,本輪融資由 Bain Capital Crypto 领投,TCG Crypto、Formless Capital、Smrti Lab、Robot Ventures、Zonff Partners 和多家天使投資人參投。

全鏈遊戲目前有多種敘事方式,常見的有去中心化遊戲(DeGame),自治世界(Autonomous Worlds),Curio 提出了自己的想法:用戶生成邏輯(User Generated Logic),簡稱 UGL。我估摸著,Curio 在製作自己的第一款全鏈遊戲 Treaty 的過程中,遇到了不少的困難,就萌生了製作自己的第一個鏈並且把遊戲引擎內置進去,這個想法和 Argus 不謀而合,區別在於 Argus 採用了分片機制,而 Curio 走了捷徑,直接採用 OP Stack。

MUD 的 ECS 遊戲框架#

我們先來看 MUD 的 ECS 框架是如何工作的?如果您看過我寫的科普文章《深度解析全鏈遊戲引擎 MUD》(https://captainz.xlog.app/shen-du-jie-xi-quan-lian-you-xi-yin-qing-MUD ),那應該了解到 ECS 透過將邏輯、數據和實體分離,提高了遊戲開發的靈活性和可維護性。編程語言採用 Solidity,遊戲對象的屬性狀態儲存在智能合約中。以 ERC-20 合約為例:ERC-20 合約將每個地址的代幣餘額存儲在一個映射中(從 address 到 uint256 餘額)。我們可以將每個 ERC-20 合約視為一個具有兩列的表:"地址" 和 "餘額"。這對應於具有單個模式值("餘額")的組件。表中的每行都將一個實體("地址")與一個組件值("餘額")關聯起來。一個地址可以在許多獨立的 ERC-20 合約中持有餘額,這對應於一個實體與許多獨立的組件值關聯。在當前的 ERC-20 參考實現中,狀態和邏輯是耦合在同一個合約中的。在 ECS 中,將有一個通用的 "轉帳系統" 來處理從一個地址向另一個地址轉帳代幣的邏輯,通過修改代幣組件中存儲的狀態。

因為 MUD 裡面的遊戲對象屬性狀態儲存在智能合約,所以 ECS 的狀態更改(客戶端的狀態同步到區塊鏈節點)每次都會通過智能合約來同步,而這個同步的過程無法並行進行且需要頻繁調用合約。所以 Curio 希望通過引入預編譯合約來解決。

預編譯合約#

以太坊虛擬機(EVM)中的預編譯合約是一種特殊類型的智能合約,其代碼直接硬編碼在以太坊節點的代碼中,而不是在 Solidity 或其他 EVM 兼容語言中編寫的。這種合約通常用於執行複雜的計算任務,因為硬編碼的實現通常比在 EVM 中解釋執行的代碼更高效。預編譯合約通常用於優化性能和降低 gas 成本。

實現預編譯函數涉及以下步驟:

  1. 選擇地址:預編譯函數需要一個地址。以太坊選擇了 1ff(包括 ff)這些地址來存儲預編譯合約。

  2. 實現功能:預編譯函數需要實現某種功能。這通常涉及到一些複雜的計算,例如椭圆曲线操作或大整數運算。這個函數通常使用 Golang 或 C++ 編寫,然後直接集成到以太坊節點的代碼中。

  3. 計算 gas 成本:預編譯函數需要一個函數來計算其運行所需的 gas。這個函數應該根據輸入數據的大小和操作的複雜性來確定 gas 成本。

  4. 集成到以太坊節點:預編譯函數需要集成到以太坊節點的代碼中。這通常涉及修改以太坊節點的代碼以添加新的預編譯合約,並重新編譯和部署節點。

然後,智能合約可以通過調用預編譯合約的地址來使用這個預編譜函數。EVM 將檢查該地址是否存在預編譜合約,如果存在,EVM 將直接調用節點代碼中的硬編碼函數,而不是在 EVM 中解釋執行合約代碼。

需要注意的是,添加新的預編譜函數需要對以太坊的協議進行修改,這通常需要通過社區的共識。此外,由於預編譜函數是硬編碼在以太坊節點的代碼中的,因此每個運行這個新版本的以太坊節點都需要包含這個新的預編譜函數的代碼。這意味著在實踐中,添加新的預編譜函數是一個複雜且需要深思熟慮的過程。

Curio 的解決方案#

我們在上面預編譜合約的討論中,可以發現,雖然使用預編譜合約可以極大的提高性能,但是需要修改鏈的節點代碼以及重新編譯和部署節點。以太坊主鏈根本做不到這點。於是 Curio 選擇了 OP Stack,在這個定制化的 Layer2 裡面,他們修改了節點代碼以添加 ECS 的預編譜合約。正是通過這個自定義的預編譜合約,智能合約可以直接訪問底層的 ECS 鏈狀態。因此,這種設計允許所有 ECS 操作(如查詢和狀態設置)具有更快的性能。又因為 OP Stack 節點使用的是 “Go-Ethereum” 客戶端,這就允許 Keystone 遊戲邏輯可以用 Go 語言編寫,而不是 Solidity,這可以大規模並行化。

Keystone 中的 ECS 主要是通過 'engine' 和 'game' 這兩個目錄的代碼實現的。

在 'engine' 目錄中,我們看到了定義了 ECS 的主要數據結構,例如 World 和 Component。World 是一個 ECS 基礎世界結構,它包括實體(Entities)和組件(Components)兩個主要部分。每個 Component 包含一個數據類型(DataType),以及用於存儲實體到值(EntitiesToValue)和值到實體(ValueToEntities)的映射。

在 'game' 目錄中,我們看到了一些特定的遊戲組件,如位置組件(PositionComp)、目標位置組件(TargetPositionComp)、標籤組件(TagComp)等。這些組件都有各自的數據類型和是否需要存儲值到實體的標誌(ShouldStoreValueToEntities)。

集成了遊戲引擎的鏈的優點#

通過上面的討論,我們可以看到,將 ECS(Entity-Component-System)狀態直接構建到定制化的區塊鏈中,可以比通過智能合約編寫 ECS 狀態實現更快的性能。這種性能提升來自以下幾個方面:

1. 數據結構優化:在智能合約中編寫 ECS 狀態通常需要使用一些非優化的數據結構,而在 Keystone 中,它們可以使用高效的數據結構(如稀疏集合)來存儲和操作 ECS 數據,從而提高查詢和設置狀態的速度。

2. 避免智能合約執行開銷:EVM(以太坊虛擬機)需要解釋執行智能合約的代碼,這會帶來一定的開銷。然而,將 ECS 狀態直接構建到區塊鏈中可以避免這種開銷,因為 ECS 操作是在區塊鏈的核心代碼中直接執行的,而不是通過解釋執行智能合約。

3. 並行化:Keystone 允許在 Go 中編寫遊戲邏輯,這意味著可以利用 Go 的並行和並發特性來提高 ECS 操作的速度。這在智能合約中是無法實現的,因為 EVM 是單線程的。

4. 預編譜合約:通過使用預編譜合約來訪問 ECS 狀態,可以提高 ECS 操作的速度。預編譜合約是在區塊鏈節點代碼中直接硬編碼的函數,執行速度比在 EVM 中解釋執行代碼要快。

5. 狀態更新優化:Keystone 採用了一種方法,允許在子世界中進行狀態更新,然後將這些更新應用到父世界。這種方法可以減少不必要的狀態更新,從而提高狀態設置的速度。

遊戲節拍器在哪裡#

GameTick 的概念通常在遊戲開發中用於管理遊戲內的時間進程。每一個 tick 代表了遊戲主循環的一個周期,各種遊戲事件可以根據這些 ticks 進行調度。這也是我們說傳統遊戲是 “loop-based” 的原因。

而區塊鏈的狀態本身並不包含我們通常理解的 "當前時間" 的概念。區塊鏈是基於區塊的概念運作的,這些區塊按照線性順序被添加到鏈中。雖然這些區塊通常包含一個時間戳,但這並不像在傳統計算環境中那樣被用作 "當前時間" 的度量。

Curio 宣稱集成了 GameTick 在區塊鏈中(GameTick built into the chain),但是我查遍了整個代碼庫,也沒找到關於 GameTick 的代碼片段,所以對 Keystone 如何實現在區塊鏈中的遊戲節拍感到十分好奇,希望 Curio 有機會可以對這個功能做更多的細節說明。不過我對此的猜測是,在 Keystone 的 GameTick 環境中,next_tick 字段可能用於確定遊戲循環的下一個周期應該在何時發生,這基於區塊鏈節點伺服器的內部時鐘,它被用來管理遊戲時間在遊戲自身的內部邏輯內的進程,與區塊鏈內區塊的進程是分開的。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。