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...
Caricatori di formato di risorse personalizzati
Introduzione
ResourceFormatLoader è un'interfaccia per il caricamento di file. Le risorse sono contenitori primari. Quando il caricamento è richiamato sullo stesso percorso di file, la risorsa caricata in precedenza verrà referenziata. Naturalmente, le risorse caricate devono essere senza stato (stateless).
Questa guida presuppone che il lettore sappia come creare moduli C++ e tipi di dati di Godot. Se no, consultare questa guida: Moduli personalizzati in C++
Riferimenti
What for?
Aggiungere nuovo supporto per numerosi formati di file
Formati audio
Formati video
Modelli di machine learning
Per che cosa no?
Immagini raster
Si dovrebbe utilizzare ImageFormatLoader per caricare immagini.
Riferimenti
Creare un ResourceFormatLoader
Ogni formato di file consiste in un contenitore di dati e da un ResourceFormatLoader.
I ResourceFormatLoader sono classi che restituiscono tutti i metadati necessari per supportare nuove estensioni in Godot. La classe deve restituire il nome del formato e l'estensione.
Inoltre, i ResourceFormatLoader devono convertire i percorsi dei file in risorse con la funzione load. Per caricare una risorsa, load deve leggere e gestire la serializzazione dei dati.
#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");
}
Creare un ResourceFormatSaver
Se si desidera modificare e salvare una risorsa, è possibile implementare un 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");
}
}
Creare tipi di dati personalizzati
Godot potrebbe non avere un sostituto adeguato dentro i suoi Tipi principali o nelle risorse gestite. Godot necessita di un nuovo tipo di dati registrato per comprendere ulteriori formati binari, come i modelli di machine learning.
Ecco un esempio di creazione di un tipo di dati personalizzato:
#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;
}
Considerazioni
Alcune librerie potrebbero non definire certe routine comuni, come la gestione degli I/O. Pertanto, sono necessarie traduzioni delle chiamate Godot.
Ad esempio, ecco il codice per tradurre le chiamate di FileAccess in 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;
};
Riferimenti
Registrare il nuovo formato di file
Godot registra ResourcesFormatLoader con un gestore ResourceLoader. Il gestore seleziona automaticamente il caricatore appropriato quando load viene chiamato.
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();
}
Riferimenti
Caricarlo su GDScript
Salva un file denominato demo.json con il seguente contenuto e posizionalo nella cartella radice del progetto:
{
"savefilename": "demo.json",
"demo": [
"welcome",
"to",
"godot",
"resource",
"loaders"
]
}
Poi allega il seguente script a qualsiasi nodo:
extends Node
@onready var json_resource = load("res://demo.json")
func _ready():
print(json_resource.get_dict())