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())