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
@toolprecisa 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
@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
@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, umCallableé um tipo de dado que guarda a referência para uma função (neste caso,update_structuresereset_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 oCallablecorrespondente.
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
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ção | Consequência no Projeto |
| Reset de IDs | Todos 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 Saves | Desastre. 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.


Deixe um comentário