Custom resource format loaders

はじめに

ResourceFormatLoaderは、ファイルアセットを読み込むファクトリインターフェイスです。リソースはプライマリコンテナです。同じファイル パスで再度読み込みが呼び出されると、以前に読み込まれたリソースが参照されます。当然のことながら、読み込まれたリソースはステートレスである必要があります。

This guide assumes the reader knows how to create C++ modules and Godot data types. If not, refer to this guide C++のカスタムモジュール.

参照

何のために?

  • 多くのファイル形式に対する新しいサポートの追加
  • オーディオフォーマット
  • ビデオフォーマット
  • 機械学習モデル

だめなんですか?

  • ラスター画像

ImageFormatLoaderを使用してイメージを読み込む必要があります。

ResourceFormatLoaderの作成

各ファイル形式は、データコンテナと ResourceFormatLoader で構成されています。

ResourceFormatLoadersは通常、Godotで新しい拡張機能をサポートするために必要なすべてのメタデータを返す単純なクラスです。クラスは、書式名と拡張文字列を返す必要があります。

さらに、ResourceFormatLoadersは load 機能を持つファイルパスをリソースに変換する必要があります。リソースを読み込むには、 load はデータのシリアル化を読み取り、処理する必要があります。

#ifndef MY_JSON_LOADER_H
#define MY_JSON_LOADER_H

#include "core/io/resource_loader.h"

class ResourceFormatLoaderMyJson : public 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> *p_extensions) const;
        virtual bool handles_type(const String &p_type) const;
        virtual String get_resource_type(const String &p_path) const;

        ResourceFormatLoaderMyJson();
        virtual ~ResourceFormatLoaderMyJson() {}
};
#endif // MY_JSON_LOADER_H
#include "my_json_loader.h"
#include "my_json.h"

ResourceFormatLoaderMyJson::ResourceFormatLoaderMyJson() {
}

RES ResourceFormatLoaderMyJson::load(const String &p_path, const String &p_original_path, Error *r_error) {
        MyJson *my = memnew(MyJson);
        if (r_error)
                *r_error = OK;
        Error err = my->set_file(p_path);
        return Ref<MyJson>(my);
}

void ResourceFormatLoaderMyJson::get_recognized_extensions(List<String> *p_extensions) const {
        p_extensions->push_back("mjson");
}

String ResourceFormatLoaderMyJson::get_resource_type(const String &p_path) const {

        if (p_path.get_extension().to_lower() == "mjson")
                return "MyJson";
        return "";
}

bool ResourceFormatLoaderMyJson::handles_type(const String &p_type) const {
        return (p_type == "MyJson");
}

Creating custom data types

Godotのコアタイプまたは管理対象リソース内に適切な代替物がない場合があります。 Godotには、機械学習モデルなどの追加のバイナリ形式を理解するために、新しい登録データ型が必要です。

カスタムデータ型を作成する方法の例を次に示します

#ifndef MY_JSON_H
#define MY_JSON_H

#include "core/dictionary.h"
#include "core/io/json.h"
#include "core/reference.h"
#include "core/variant.h"
#include "core/variant_parser.h"

class MyJson : public Resource {
        GDCLASS(MyJson, Resource);

protected:
        static void _bind_methods() {
                ClassDB::bind_method(D_METHOD("to_string"), &MyJson::to_string);
        }

private:
        Dictionary dict;

public:
        Error set_file(const String &p_path) {
                Error error_file;
                FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &error_file);

                String buf = String("");
                while (!file->eof_reached()) {
                        buf += file->get_line();
                }
                String err_string;
                int err_line;
                JSON cmd;
                Variant ret;
                Error err = cmd.parse(buf, ret, err_string, err_line);
                dict = Dictionary(ret);
                file->close();
                return OK;
        }

        String to_string() const {
                return String(*this);
        }

        operator String() const {
                JSON a;
                return a.print(dict);
        }

        MyJson() {};
        ~MyJson() {};
};
#endif // MY_JSON_H

考慮事項

Some libraries may not define certain common routines such as IO handling. Therefore, Godot call translations are required.

たとえば、 FileAccess 呼び出しを std::istream に変換するためのコードを次に示します。

#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;
};

Registering the new file format

Godotは ResourceFormatLoaderResourceLoader ハンドラで登録します。ハンドラは load が呼び出されると、適切なローダーを自動的に選択します。

/* register_types.cpp */
#include "register_types.h"
#include "core/class_db.h"

#include "my_json_loader.h"
#include "my_json.h"

static ResourceFormatLoaderMyJson *my_json_loader = NULL;
void register_my_json_types() {
        my_json_loader = memnew(ResourceFormatLoaderMyJson);
        ResourceLoader::add_resource_format_loader(my_json_loader);
        ClassDB::register_class<MyJson>();
}

void unregister_my_json_types() {
        memdelete(my_json_loader);
}

GDScriptに読み込む

{
  "savefilename" : "demo.mjson",
  "demo": [
    "welcome",
    "to",
    "godot",
    "resource",
    "loaders"
  ]
}
extends Node

func _ready():
    var myjson = load("res://demo.mjson")
    print(myjson.to_string())