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...
Carregadores de recurso em formato personalizado
Introdução
ResourceFormatLoader é uma interface de criação para carregamento de recursos. Os Recursos são contêineres primários. Quando o carregamento é chamado novamente no mesmo caminho de arquivo, o Recurso carregado anteriormente será referenciado. Naturalmente, os recursos carregados devem ser sem estado (stateless).
Este guia pressupõe que o leitor saiba como criar módulos C++ e tipos de dados do Godot. Se não souber, consulte este guia: Módulos personalizados em C++
Referências
Para que serve?
Adicionando novo suporte para muitos formatos de arquivo
Formatos de Áudio
Formatos de Vídeo
Modelos de aprendizado de máquina
Para que não serve?
Imagens Rasterizadas
ImageFormatLoader deve ser utilizado para carregar imagens.
Referências
Criando um ResourceFormatLoader
Cada formato de arquivo consiste de um contêiner de dados e um ResourceFormatLoader.
ResourceFormatLoaders são classes que retornam todos os metadados necessários para suportar novas extensões no Godot. A classe deve retornar o nome do formato e a string da extensão.
Além disso, ResourceFormatLoaders deve converter os caminhos de arquivo em recursos com a função load. Para carregar um recurso, a função load deve ler e manipular a serialização de dados.
#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");
}
Criando um ResourceFormatSaver
Se você quiser ser capaz de editar e salvar um recurso, você pode implementar um 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");
}
}
Criando tipos de dados personalizados
Godot pode não ter um substituto adequado de Tipos de núcleos ou recursos gerenciados. Godot precisa de um novo tipo de dados registrado para reconhecer formatos binários adicionais, como modelos de aprendizado de máquina.
Eis um exemplo de como criar um tipo de dados personalizado:
#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;
}
Considerações
Algumas bibliotecas podem não definir certas rotinas comuns, como manipulação de E/S. Portanto, são necessárias traduções de chamadas do Godot.
Por exemplo, aqui está o código para traduzir chamadas de FileAccess em 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;
};
Referências
Registrando o novo formato de arquivo
O Godot registra o ResourcesFormatLoader com um manipulador ResourceLoader. O manipulador seleciona automaticamente o carregador adequado quando load é chamado.
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();
}
Referências
Carregando no GDScript
Salve um arquivo chamado demo.json com o conteúdo a seguir e coloque-o na pasta raiz do projeto:
{
"savefilename": "demo.json",
"demo": [
"welcome",
"to",
"godot",
"resource",
"loaders"
]
}
Em seguida, anexe o seguinte script a qualquer nó:
extends Node
@onready var json_resource = load("res://demo.json")
func _ready():
print(json_resource.get_dict())