Home > 工具編程 | 遊戲編程 > 從頭開始思考遊戲的資料管理系統(二)

從頭開始思考遊戲的資料管理系統(二)

上回談及一些遊戲資料管理的初部分析,但有些思緒還沒有整理好,寫得頗亂。今次就直接談我在幾個月前設計的Mil Universe Database (MUD),從中再闡述當中的一些想法。

基本的資料流程

資料流程

首先,一個項目中的所有引擎會使用的資料,都放進一個完整的資料庫裡。現時我的設計一個資料庫會儲存成一個 .mud檔案。

外部檔案可以滙入資料庫,也可以滙出。但滙出的資料會失去一些資訊(如稍後說的依存關係)。

資料庫最後會轉換為平台特定的格式,如轉換Endianness、轉換模型和紋理格式、轉換XML到二進制格式、編譯腳本等等。這步驟的主要目的是加快遊戲讀資料的速度。此外,也可以把關卡或人物的資料(如三維模型、紋理、動畫等)包裝成一個資料塊(data chunk),優點是進一步加快了讀資料的速度(尤其是光碟,因為seeking慢),缺點是一筆資料可能出現在多個資料塊中,增加了遊戲的容量,而且可能會讀到已載入的資料。

如果多人參與同一項目,該資料庫會分為中央和本地的資料庫,透過版本控制同步及提交更新。這裡描述的是一個可離線編輯的版本控制系統,我也和伙伴討論過其他方式,可見使用Database Server+Source Control Server构建游戏开发用数据文件的可行性分析

功能需求

構想MUD 時考慮了以下的需求。

完整單一資料庫

上回說到一個遊戲項目會有數萬以上筆資料。如果每筆資料以獨立檔案儲存,會產生很多問題。我覺得缺乏完整性 (Integrity)是最大的問題。所以MUD是以單一的資料庫儲(.mud檔案)存整個項目的資料。

Key

使用整數作為每筆資料在永續時的Identifier,稱為 Key。Key只是系統才知道的,製作人員應該從來不需要知道這概念。

層階式檔案系統

每筆資料會有路徑和檔案名稱,但這只是給使用者「看」而已,遊戲引擎始終是使用Key作為Unique Identifier。資料庫轉換成平台格式時,這些路徑檔名會被忽略,不存在於遊戲的執行版本。

依存關係

資料和資料間的依存關係會記綠下來。如一個三維模使用數個材質;每個材質又使用數個紋理。當一筆資料被刪掉時,可提醒使用者該資料被那些資料使用,如果確定刪去,也會通知其他資料刪去那些使用參考。

腳本也是用Key去挷定資料。例如一個腳本會在執行期,在某些情況下改變它的遊戲物件的三維模型,那麼該腳本會定義它需要一個三維模型的(成員)變數。關卡設計師會把腳本挷定在一個遊戲物件上,並設定它需要的三維模型。這遊戲物件永續時儲存了三維模型的Key,而在執行期腳本則拿到了三維模型的物件(指針)。這可以解決把資料(如路徑)直接寫在腳本所產生的問題。

此外,依存關係也可以找出及清除一些孤立的資料(沒有其他資料會依存的資料)。當然,要做到這一點,還要定義一個(或一些)根節點。

版本控制

遊戲的資料通常由很多人參與製作,版本的控制是十分重要的。我未詳細考慮怎樣實現MUD的版本控制。簡單的方案是使用SVN之類的檔案版本控制軟件的API,把Key轉為檔案去存取。但仍要考慮資料以外的東西怎麼作版本處理(檔名、依存關係等等)。

其他擴展功能

  • 資產管理(Asset Management): 除了儲存遊戲編輯工具和遊戲引擎會直接使用的檔案,亦儲存來源檔 (.max、.psd ),並有workflow自動轉換這些檔案,例如紋理的大小和mip-map設定。
  • 壓縮: 加快檔案的讀寫、減少磁碟使用空間。
  • 加密: 加強安全性 (開發時期的泄漏、出版後被反組譯等等)

Schema設計

我之前設計的第一個Mud版本應該是以C++直接實作,但schema用一般database畫出來可能比較容易明白:

Mud Schema

最重要的是Key table,它記錄每個key所指向的資料的大小、類型、和儲存在資料庫中的offset。

File、Folder和Dependency都是制作期的資料庫才有的,這些 tables在最終運行版的資料庫會被刪去。

API 設計

以下是Mud API的第一個版本,當中示有 Retail的函數是遊戲正式版需要的函數:

class MudFile
{
public:
    MudFile(char *mudFileFilename);    // Retail

    // Mud file manipulation
    bool Create();
    bool Open();    // Retail
    bool Close();    // Retail
    bool Check();
    bool Compact();

    // Transaction
    bool BeginTransaction();
    bool Commit();
    bool Rollback();

    // Read/Write
    bool OpenReadFile(Key key);    // Retail
    bool OpenWriteFile(Key key);
    bool CloseFile();    // Retail
    uint32_t ReadFile(void *buffer, uint32_t maxSize);    // Retail
    uint32_t WriteFile(void *buffer, uint32_t size);

    // File manipulations
    Key CreateFile(FolderID folderID, char *filename, FileType type);
    bool DeleteFile(Key key);
    bool RenameFile(Key key, char *filename);
    bool MoveFile(Key key, FolderID folderID);

    // File information
    char *GetFilename(Key key);
    uint32_t GetFileSize(Key key);    // Retail
    FileType GetFileType();    // Retail
    FolderID GetFileFolder(Key key);

    // Folder manipulations
    FolderID CreateFolder(FolderID parentFolderID, char *folderName);
    bool DeleteFolder(FolderID folderID);
    bool RenameFolder(FolderID folderID, char *folderName);
    bool MoveFolder(FolderID folderID, FolderID parentFolderID);

    // Folder information
    char *GetFolderName(FolderID folderID);
    FolderID GetFolderParent(FolderID folderID);
    
    // Path
    string GetPath(Key key);
    Key GetKeyByPath(const string& path);

    // Folder/File Traversal
    FolderID GetFirstChildFolder(FolderID folderID);
    FolderID GetNextSiblingFolder(FolderID folderID);
    Key GetFirstFileInFolder(FolderID folderID);
    Key GetNextFileInFolder(Key key);

    // Dependency
    bool AddDependency(Key source, Key target);
    bool RemoveDependency(Key source, Key target);
    KeyList GetSources(Key target);
    KeyList GetTargets(Key source);
};

我把這組API盡量設計得簡單,減少所需要的類別(如File、Folder類別),使C# (或其他語言)的Binding容易實作。在Retail版中,只需要少量函數,實作多個平台的版本也變得容易。

我原來的設計裡還有 Transaction 的考慮,希望可以加強database的integrity。例如程式在運作中途異常結束,database的內容可以維持consistency (不會有只寫了一半的資料或資料組)。

後記

這一篇文章其實只談及一個解決方案,並沒有很仔細的分析每個決定,及討論其他方案。如果有寫得不太清楚,或有任何意見,歡迎留言討論。

Comments:1

Milo 09-03-19 (四) 21:13

之前又自動設定了不可回應,不知道更新了 WordPress 後為甚麼會這樣的…

Comment Form
Remember personal info

Trackbacks:0

Trackback URL for this entry
http://miloyip.seezone.net/wp-trackback.php?p=109
Listed below are links to weblogs that reference
從頭開始思考遊戲的資料管理系統(二) from Milo的遊戲開發

Home > 工具編程 | 遊戲編程 > 從頭開始思考遊戲的資料管理系統(二)

Search
Feeds
Meta

Return to page top