Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Benutzerdefinierte Ressourcenformat-Loader

Einführung

ResourceFormatLoader ist eine Factory-Schnittstelle zum Laden von Datei-Assets. Ressourcen sind Primärcontainer. Wird load erneut auf demselben Dateipfad aufgerufen, wird auf die zuvor geladene Ressource verwiesen. Geladene Ressourcen müssen natürlich zustandslos sein.

Diese Anleitung setzt voraus, dass der Leser weiß, wie man C++-Module und Godot-Datentypen erstellt. Falls nicht, lesen Sie diese Anleitung: Benutzerdefinierte Module in C++

Referenzen

Wofür?

  • Unterstützung für viele Dateiformate hinzufügen

  • Audioformate

  • Videoformate

  • Modelle für maschinelles Lernen

Was nicht?

  • Rasterbilder

ImageFormatLoader sollte zum Laden von Bildern verwendet werden.

Referenzen

Erstellen eines ResourceFormatLoaders

Jedes Dateiformat besteht aus einem Datencontainer und einem ResourceFormatLoader.

ResourceFormatLoaders sind Klassen, die alle notwendigen Metadaten für die Unterstützung neuer Erweiterungen in Godot zurückgeben. Die Klasse muss den Formatnamen und den Erweiterungs-String zurückgeben.

Außerdem müssen ResourceFormatLoaders Dateipfade mit der Funktion load in Ressourcen konvertieren. Um eine Ressource zu laden, muss load die Datenserialisierung lesen und verarbeiten.

/* resource_loader_json.h */

#ifndef RESOURCE_LOADER_JSON_H
#define RESOURCE_LOADER_JSON_H

#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;
};
#endif // RESOURCE_LOADER_JSON_H
/* resource_loader_json.cpp */

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

Erstellen eines ResourceFormatSaver

Wenn Sie eine Ressource bearbeiten und speichern möchten, können Sie einen ResourceFormatSaver implementieren:

/* resource_saver_json.h */

#ifndef RESOURCE_SAVER_JSON_H
#define RESOURCE_SAVER_JSON_H

#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;
};
#endif // RESOURCE_SAVER_JSON_H
/* resource_saver_json.cpp */

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

Benutzerdefinierte Datentypen erstellen

Godot hat möglicherweise keinen geeigneten Ersatz in seinen Kerntypen oder verwalteten Ressourcen. Godot benötigt einen neuen registrierten Datentyp, um zusätzliche Binärformate wie maschinelle Lernmodelle zu verstehen.

Hier ist ein Beispiel zum Erstellen eines benutzerdefinierten Datentyps:

/* resource_json.h */

#ifndef RESOURCE_JSON_H
#define RESOURCE_JSON_H

#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();
};
#endif // RESOURCE_JSON_H
/* resource_json.cpp */

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

Überlegungen

Einige Bibliotheken definieren möglicherweise bestimmte allgemeine Routinen wie die I/O-Behandlung nicht. Daher sind Godot-Call-Übersetzungen erforderlich.

Hier ist zum Beispiel der Code für die Übersetzung von FileAccess Aufrufen in std::istream.

#include "core/os/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;
};

Referenzen

Registrierung des neuen Dateiformats

Godot registriert ResourcesFormatLoader bei einem ResourceLoader-Handler. Der Handler wählt automatisch den richtigen Loader aus, wenn load aufgerufen wird.

/* register_types.h */

void register_json_types();
void unregister_json_types();
/* register_types.cpp */

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

Referenzen

Laden in GDScript

Speichern Sie eine Datei mit dem Namen demo.json mit dem folgenden Inhalt und legen Sie sie im Stammverzeichnis des Projekts ab:

{
  "savefilename": "demo.json",
  "demo": [
    "welcome",
    "to",
    "godot",
    "resource",
    "loaders"
  ]
}

Anschließend fügen Sie die folgenden beiden Funktionen hinzu:

extends Node

@onready var json_resource = load("res://demo.json")

func _ready():
    print(json_resource.get_dict())