Gerenciamento de Dados na Godot Engine

Dados Automatizados com @tool

Conforme um projeto de jogo cresce, o maior inimigo do desenvolvedor deixa de ser a complexidade do código e passa a ser a gerência de dados. No desenvolvimento de um City Builder, por exemplo, cada nova estrutura — seja uma casa, uma fábrica ou uma estrada — precisa de um modelo, de uma cena e de um arquivo de dados correspondente (.tres).

O grande perigo mora na hora de cadastrar essas estruturas em uma biblioteca: cada registro precisa de um ID único.

Fazer isso manualmente, digitando IDs um por um no Inspector, é uma receita infalível para o desastre. Basta dois arquivos receberem o mesmo ID por acidente para que o sistema de salvamento colapse, trocando prédios residenciais por estradas na hora de carregar o mapa.

Neste artigo, vamos aprender a transformar a biblioteca de estruturas do seu jogo em um Banco de Dados Automatizado. Utilizaremos o poder da diretiva @tool e a novíssima anotação de botões da Godot 4.4+ para fazer a engine trabalhar para nós, gerenciando e blindando nossos arquivos diretamente pelo editor.

1. O Salvador do Fluxo: O Modo @tool

Para evitar que você precise dar “Play” no jogo apenas para rodar um script de organização, recorremos à diretiva @tool.

Como vimos anteriormente, as anotações (ou diretivas) precedidas por @ são metadados que controlam como a engine lê, renderiza e permite a edição de elementos no editor. Ao colocar @tool na primeira linha do seu script, a Godot entende que aquele código tem permissão para rodar diretamente dentro do editor, em tempo de design.

No nosso sistema, o script structure_library.gd herdará de Resource. Isso significa que ele próprio será um arquivo de dados no projeto, mas com superpoderes ativos dentro do ecossistema do editor da Godot.

2. Anatomia do Script StructureLibrary

Antes de criarmos a automação, precisamos estruturar nossa biblioteca para receber e catalogar os dados com segurança.

⚠️ Regra de Ouro: A declaração da diretiva @tool precisa obrigatoriamente estar na primeira linha do script (ou logo após comentários de cabeçalho). Se você tentar declarar a classe antes do @tool, a Godot gerará um erro de compilação e o comportamento de ferramenta não será ativado.

Abaixo, veja como estruturar as variáveis fundamentais da sua biblioteca de dados:

GDScript

GDScript
@tool
class_name StructureLibrary extends Resource

@export_group("Library Config")

# Dicionários de indexação para busca rápida no jogo
@export var structures_by_id: Dictionary = {}
@export var structures_by_category: Dictionary = {}<br>
  • last_assigned_id: O coração do controle de duplicidade. Ele rastreia o maior ID já distribuído. Mesmo se você deletar uma estrutura antiga do projeto, o sistema nunca reciclará IDs passados, garantindo que o histórico de salvamento permaneça intacto.
  • Dicionários: Servem para mapear as construções por ID e categoria, facilitando a criação de abas de construção (como “Residencial”, “Industrial”, “Estradas”) na interface do seu jogo.

3. Adeus, Gambiarras! Os Novos Botões da Godot 4.4+

Até a versão 4.3 da Godot, criar um botão personalizado no Inspector exigia uma gambiarra clássica: criava-se uma variável booleana exportada e, dentro do método set(value), disparava-se a função desejada antes de redefinir a variável para false.

A partir da Godot 4.4, esse processo foi completamente revolucionado com a chegada da diretiva @export_tool_button. Agora, criar botões funcionais no Inspector exige apenas uma linha de código limpa e legível.

GDScript

GDScript
@export_group("Library Actions")

# Cria os botões reais no Inspector mapeando para suas respectivas funções
@export_tool_button("Update Structures") var update_btn: Callable = _refresh_library
@export_tool_button("Reset IDs") var reset_btn: Callable = reset_ids

⚙️ O que é um Callable? Em GDScript, um Callable é um tipo de dado que guarda a referência para uma função (neste caso, update_structures e reset_ids) em vez de guardar um valor estático (como um número ou texto). Quando o botão é clicado no Inspector, a Godot simplesmente executa o Callable correspondente.

4. Lógica de Atualização Automática

Quando clicamos no botão “Update Structures”, o script realiza uma varredura completa por trás das cortinas:

GDScript

GDScript
func _refresh_library() -> void:
	if not Engine.is_editor_hint():# or not value:
		return
		
	print("\n[StructureLibrary] Iniciando varredura e categorização...")
	
	# 1. Limpa os dicionários antigos
	info.clear()
	categorized_info.clear()
	
	# Inicializa as listas do dicionário de categorias baseado nos valores do Enum
	for enum_val in StructureData.type.values():
		categorized_info[enum_val] = []
	
	var dir = DirAccess.open(structures_folder)
	if not dir:
		printerr("[StructureLibrary] ERRO: Pasta não encontrada -> ", structures_folder)
		return
		
	var highest_id: int = -1
	var loaded_structures: Array[StructureData] = []
	
	# PASSO 1: Carrega todos os resources e acha o maior ID
	dir.list_dir_begin()
	var file_name = dir.get_next()
	while file_name != "":
		if not dir.current_is_dir() and file_name.ends_with(".tres"):
			var res_path = structures_folder + "/" + file_name
			var res = ResourceLoader.load(res_path)
			
			if res is StructureData:
				loaded_structures.append(res)
				if res.structure_id > highest_id:
					highest_id = res.structure_id
		
		file_name = dir.get_next()
		
	# PASSO 2: Atribui IDs inéditos e organiza as estruturas nas categorias
	for struct in loaded_structures:
		# Verifica se é uma estrutura nova
		if struct.structure_id == -1:
			highest_id += 1
			struct.structure_id = highest_id
			ResourceSaver.save(struct, struct.resource_path)
			print(" -> Nova estrutura: '", struct.name, "' | ID: ", struct.structure_id)
			
		# Adiciona ao dicionário geral
		info[struct.structure_id] = struct
		
		# Adiciona ao dicionário de categorias
		if categorized_info.has(struct.structure_type):
			categorized_info[struct.structure_type].append(struct)
		
	print("[StructureLibrary] Concluído! Total: ", info.size(), " estruturas registradas.")
	
	# Mostra o resumo das categorias no console
	for cat_key in categorized_info.keys():
		var amount = categorized_info[cat_key].size()
		# Pega o nome do Enum em texto para ficar legível no console
		var cat_name = StructureData.type.keys()[cat_key] 
		print("  - Categoria [", cat_name, "]: ", amount, " itens.")
	
	# Salva a própria biblioteca atualizada de volta no arquivo .tres físico
	if not resource_path.is_empty():
		var save_result = ResourceSaver.save(self, resource_path)
		if save_result == OK:
			print("[StructureLibrary] Sucesso! Arquivo da biblioteca salvo permanentemente no disco.")
		else:
			printerr("[StructureLibrary] ERRO ao salvar o arquivo da biblioteca. Código: ", save_result)
	else:
		printerr("[StructureLibrary] AVISO: Não foi possível salvar automaticamente porque este Resource ainda não foi salvo no disco nenhuma vez (resource_path está vazio).")
	
	# Atualiza a interface gráfica do Inspetor da Godot
	notify_property_list_changed()

Com esse fluxo, o seu designer de fases só precisa criar o arquivo .tres correspondente à nova estrutura, salvá-lo na pasta designada e apertar “Update Structures”. A biblioteca se encarrega de ler o arquivo, validar o ID, gravar as informações no disco e atualizar as listas de busca.

5. A Zona de Perigo: Entendendo o “Reset IDs”

O segundo botão criado em nossa interface é o “Reset IDs”. Embora pareça tentador ter uma função para limpar tudo e começar do zero, este botão deve ser tratado como uma ferramenta de manutenção de uso extremamente restrito.

AçãoConsequência no Projeto
Reset de IDsTodos os arquivos .tres voltam a ter o ID -1 e a variável last_assigned_id é zerada.
Próximo “Update”Novos IDs sequenciais são gerados do zero e gravados nas estruturas.
Impacto em SavesDesastre. Se houver um mapa salvo com a distribuição de IDs antiga, ao carregar o jogo, os prédios apontarão para os novos IDs gerados, fazendo ruas virarem indústrias ou casas desaparecerem.

Portanto, utilize o botão de reset apenas em fases de prototipação inicial ou se você decidir mudar radicalmente a biblioteca de assets do jogo e descartar qualquer compatibilidade de salvamento com versões anteriores.

Assista ao Vídeo

Ao unir a diretiva @tool com as facilidades do @export_tool_button da Godot 4.4+, você blinda o desenvolvimento do seu jogo contra falhas humanas que poderiam passar despercebidas até a fase de testes. Automatizar a gerência de banco de dados do seu projeto permite que você mantenha o foco no que realmente importa: projetar dinâmicas de jogo divertidas e expandir o seu universo.


Revisado em

em

,

por

Comments

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *