自定义资源格式加载程序

介绍

ResourceFormatLoader是用于加载文件资源的工厂接口。资源是主要容器。当再次在同一文件路径上调用LOAD时,将引用先前加载的资源。当然,加载的资源必须是无状态的。

本指南假定读者知道如何创建C++模块和Godot数据类型。如果没有,请参阅本指南。 C++中的自定义模块 .

为何?

  • 添加对多种文件格式的新支持

  • 音频格式

  • 视频格式

  • 机器学习模型

为什么不呢?

  • 栅格图像

应使用ImageFormatLoader加载图像。

创建ResourceFormatLoader

每个文件格式由一个数据容器和一个 ResourceFormatLoader .

resourceformatloader通常是简单的类,它返回在godot中支持新扩展所需的所有元数据。类必须返回格式名和扩展字符串。

此外,ResourceFormatLoader必须使用 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");
}

创建自定义数据类型

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

考虑事项

有些库可能没有定义某些公共例程,如IO处理。因此,需要进行godot调用翻译。

例如,下面是用于翻译的代码 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;
};

注册新文件格式

Godot寄存器 ResourcesFormatLoader 用一个 ResourceLoader 处理程序。当 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())