Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
自訂資源格式載入器
前言
ResourceFormatLoader 是用來載入檔案資產的工廠介面。資源是主要的容器,當再次於相同檔案路徑呼叫載入時,會參照到先前已載入的 Resource。理論上,載入的資源必須是無狀態的。
本指南假設讀者已經了解如何建立 C++ 模組與 Godot 資料型別。若不熟悉,請參考 以 C++ 自訂模組 此指南
參考資料
用途說明?
新增多種檔案格式的支援
音訊格式
影片格式
機器學習模型
不適用於哪些?
點陣圖
應使用 ImageFormatLoader 來載入圖片。
參考資料
建立 ResourceFormatLoader
每個檔案格式都包含一個資料容器以及一個 ResourceFormatLoader。
ResourceFormatLoader 是回傳所有必要後設資料以支援 Godot 新副檔名的類別。該類別必須回傳格式名稱與副檔名字串。
此外,ResourceFormatLoader 必須實作 load 函式,將檔案路徑轉換為資源。載入資源時,load 必須負責讀取並處理資料序列化。
#pragma once
#include "core/io/resource_loader.h"
class ResourceFormatLoaderJson : public ResourceFormatLoader {
GDCLASS(ResourceFormatLoaderJson, ResourceFormatLoader);
public:
virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL);
virtual void get_recognized_extensions(List<String> *r_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
};
#include "resource_loader_json.h"
#include "resource_json.h"
RES ResourceFormatLoaderJson::load(const String &p_path, const String &p_original_path, Error *r_error) {
Ref<JsonResource> json = memnew(JsonResource);
if (r_error) {
*r_error = OK;
}
Error err = json->load_file(p_path);
return json;
}
void ResourceFormatLoaderJson::get_recognized_extensions(List<String> *r_extensions) const {
if (!r_extensions->find("json")) {
r_extensions->push_back("json");
}
}
String ResourceFormatLoaderJson::get_resource_type(const String &p_path) const {
return "Resource";
}
bool ResourceFormatLoaderJson::handles_type(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "Resource");
}
建立 ResourceFormatSaver
若希望能夠編輯並儲存資源,可實作一個 ResourceFormatSaver:
#pragma once
#include "core/io/resource_saver.h"
class ResourceFormatSaverJson : public ResourceFormatSaver {
GDCLASS(ResourceFormatSaverJson, ResourceFormatSaver);
public:
virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
virtual bool recognize(const RES &p_resource) const;
virtual void get_recognized_extensions(const RES &p_resource, List<String> *r_extensions) const;
};
#include "resource_saver_json.h"
#include "resource_json.h"
#include "scene/resources/resource_format_text.h"
Error ResourceFormatSaverJson::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
Ref<JsonResource> json = memnew(JsonResource);
Error error = json->save_file(p_path, p_resource);
return error;
}
bool ResourceFormatSaverJson::recognize(const RES &p_resource) const {
return Object::cast_to<JsonResource>(*p_resource) != NULL;
}
void ResourceFormatSaverJson::get_recognized_extensions(const RES &p_resource, List<String> *r_extensions) const {
if (Object::cast_to<JsonResource>(*p_resource)) {
r_extensions->push_back("json");
}
}
建立自訂資料型別
Godot 的 核心型別 或管理的資源中可能沒有適當的替代品。這時需註冊新的資料型別,讓 Godot 能夠辨識如機器學習模型等額外的二進位格式。
以下為建立自訂資料型別的範例:
#pragma once
#include "core/io/json.h"
#include "core/variant_parser.h"
class JsonResource : public Resource {
GDCLASS(JsonResource, Resource);
protected:
static void _bind_methods() {
ClassDB::bind_method(D_METHOD("set_dict", "dict"), &JsonResource::set_dict);
ClassDB::bind_method(D_METHOD("get_dict"), &JsonResource::get_dict);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "content"), "set_dict", "get_dict");
}
private:
Dictionary content;
public:
Error load_file(const String &p_path);
Error save_file(const String &p_path, const RES &p_resource);
void set_dict(const Dictionary &p_dict);
Dictionary get_dict();
};
#include "resource_json.h"
Error JsonResource::load_file(const String &p_path) {
Error error;
FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &error);
if (error != OK) {
if (file) {
file->close();
}
return error;
}
String json_string = String("");
while (!file->eof_reached()) {
json_string += file->get_line();
}
file->close();
String error_string;
int error_line;
JSON json;
Variant result;
error = json.parse(json_string, result, error_string, error_line);
if (error != OK) {
file->close();
return error;
}
content = Dictionary(result);
return OK;
}
Error JsonResource::save_file(const String &p_path, const RES &p_resource) {
Error error;
FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &error);
if (error != OK) {
if (file) {
file->close();
}
return error;
}
Ref<JsonResource> json_ref = p_resource.get_ref_ptr();
JSON json;
file->store_string(json.print(json_ref->get_dict(), " "));
file->close();
return OK;
}
void JsonResource::set_dict(const Dictionary &p_dict) {
content = p_dict;
}
Dictionary JsonResource::get_dict() {
return content;
}
注意事項
有些函式庫可能未定義像是 IO 處理等常用操作,因此必須將 Godot 的呼叫進行轉換。
例如,以下程式碼示範如何將 FileAccess 呼叫轉換為 std::istream。
#include "core/io/file_access.h"
#include <istream>
#include <streambuf>
class GodotFileInStreamBuf : public std::streambuf {
public:
GodotFileInStreamBuf(FileAccess *fa) {
_file = fa;
}
int underflow() {
if (_file->eof_reached()) {
return EOF;
} else {
size_t pos = _file->get_position();
uint8_t ret = _file->get_8();
_file->seek(pos); // Required since get_8() advances the read head.
return ret;
}
}
int uflow() {
return _file->eof_reached() ? EOF : _file->get_8();
}
private:
FileAccess *_file;
};
參考資料
註冊新檔案格式
Godot 會利用 ResourceLoader 處理器註冊 ResourceFormatLoader,當 load 被呼叫時,該處理器會自動選擇適合的載入器。
void register_json_types();
void unregister_json_types();
#include "register_types.h"
#include "core/class_db.h"
#include "resource_loader_json.h"
#include "resource_saver_json.h"
#include "resource_json.h"
static Ref<ResourceFormatLoaderJson> json_loader;
static Ref<ResourceFormatSaverJson> json_saver;
void register_json_types() {
ClassDB::register_class<JsonResource>();
json_loader.instantiate();
ResourceLoader::add_resource_format_loader(json_loader);
json_saver.instantiate();
ResourceSaver::add_resource_format_saver(json_saver);
}
void unregister_json_types() {
ResourceLoader::remove_resource_format_loader(json_loader);
json_loader.unref();
ResourceSaver::remove_resource_format_saver(json_saver);
json_saver.unref();
}
參考資料
在 GDScript 載入
建立一個名為 demo.json 的檔案,填入以下內容,並放在專案根目錄下:
{
"savefilename": "demo.json",
"demo": [
"welcome",
"to",
"godot",
"resource",
"loaders"
]
}
然後將下列腳本附加到任意節點:
extends Node
@onready var json_resource = load("res://demo.json")
func _ready():
print(json_resource.get_dict())