1 Módulo 2
Documentação do Esquema e Dados do Projeto
1.1 Esquema do Banco de Dados (DDL)
Este é o DDL (Data Definition Language) para criar a estrutura do banco de dados do projeto. Ele define as tabelas, colunas, chaves primárias e estrangeiras necessárias.
-- Configurações para garantir que os comandos rodem sem parar em erros de "já existe"
-- Isso é útil se o script for executado em um ambiente onde partes já foram criadas.
SET client_min_messages TO WARNING; -- Suprime mensagens de NOTICE, mostrando WARNINGs e erros
CREATE TABLE IF NOT EXISTS Bioma (
NomeBioma VARCHAR(100) PRIMARY KEY NOT NULL
);
CREATE TABLE IF NOT EXISTS Mapa (
Nome VARCHAR(100) NOT NULL,
Turno VARCHAR(50) NOT NULL,
PRIMARY KEY (Nome, Turno)
);
CREATE TABLE IF NOT EXISTS Chunk (
Numero_chunk INTEGER PRIMARY KEY NOT NULL,
Id_bioma VARCHAR(100) NOT NULL,
Id_mapa_nome VARCHAR(100) NOT NULL,
Id_mapa_turno VARCHAR(50) NOT NULL,
FOREIGN KEY (Id_bioma) REFERENCES Bioma(NomeBioma) ON DELETE RESTRICT ON UPDATE CASCADE,
FOREIGN KEY (Id_mapa_nome, Id_mapa_turno) REFERENCES Mapa(Nome, Turno) ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS Jogador (
Id_Jogador SERIAL PRIMARY KEY,
Nome VARCHAR(100) NOT NULL,
Vida_max INT NOT NULL,
Vida_atual INT NOT NULL,
xp INT NOT NULL,
forca INT NOT NULL
);
CREATE TABLE IF NOT EXISTS Inventario (
id_jogador INT NOT NULL,
id_inventario INT NOT NULL,
Instancia_Item TEXT,
ArmaduraEquipada VARCHAR(100),
ArmaEquipada VARCHAR(100),
PRIMARY KEY (id_jogador, id_inventario),
FOREIGN KEY (id_jogador) REFERENCES Jogador(Id_Jogador) ON DELETE CASCADE ON UPDATE CASCADE
);
-- Garante que a coluna e a constraint só sejam adicionadas se não existirem.
DO $$
BEGIN
-- Adicionar a coluna Id_Chunk_Atual à tabela Jogador se ela não existir
-- Note que este bloco 'IF NOT EXISTS' não é padrão SQL, mas é uma extensão comum em PG.
-- Ou você pode usar um bloco EXCEPTION WHEN duplicate_column THEN null; como antes
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='jogador' AND column_name='id_chunk_atual') THEN
ALTER TABLE Jogador ADD COLUMN Id_Chunk_Atual INTEGER; -- <--- AGORA É INTEGER
END IF;
-- Adicionar a constraint de chave estrangeira se ela não existir
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_jogador_chunk') THEN
ALTER TABLE Jogador ADD CONSTRAINT fk_jogador_chunk
FOREIGN KEY (Id_Chunk_Atual) REFERENCES Chunk(Numero_chunk) ON DELETE SET NULL ON UPDATE CASCADE;
END IF;
END
$$ LANGUAGE plpgsql;
-- Índices para Chaves Estrangeiras (para otimização de performance em consultas)
CREATE INDEX IF NOT EXISTS idx_chunk_id_bioma ON Chunk (Id_bioma);
CREATE INDEX IF NOT EXISTS idx_chunk_id_mapa ON Chunk (Id_mapa_nome, Id_mapa_turno);
CREATE INDEX IF NOT EXISTS idx_inventario_id_jogador ON Inventario (id_jogador);
CREATE INDEX IF NOT EXISTS idx_jogador_id_chunk_atual ON Jogador (Id_Chunk_Atual);
1.2 Manipulação de Dados (DML)
Este script DML (Data Manipulation Language) insere alguns dados iniciais nas tabelas do banco de dados para testes e demonstrações.
INSERT INTO Mapa (Nome, Turno)
VALUES
('Mapa_Principal', 'Dia'),
('Mapa_Principal', 'Noite')
ON CONFLICT (Nome, Turno) DO NOTHING;
INSERT INTO Bioma (NomeBioma)
VALUES
('Deserto'),
('Oceano'),
('Selva'),
('Floresta')
ON CONFLICT (NomeBioma) DO NOTHING;
INSERT INTO Chunk (Numero_chunk, Id_bioma, Id_mapa_nome, Id_mapa_turno)
VALUES
(1, 'Deserto', 'Mapa_Principal', 'Dia'),
(2, 'Oceano', 'Mapa_Principal', 'Dia'),
(3, 'Selva', 'Mapa_Principal', 'Noite'),
(4, 'Floresta', 'Mapa_Principal', 'Noite')
ON CONFLICT (Numero_chunk) DO NOTHING;
INSERT INTO Jogador (Nome, Vida_max, Vida_atual, xp, forca, Id_Chunk_Atual)
VALUES
('Player1', 100, 100, 0, 10, 1),
('Player2', 120, 120, 50, 12, 2);
INSERT INTO Inventario (id_jogador, id_inventario, Instancia_Item, ArmaduraEquipada, ArmaEquipada)
VALUES
(1, 1, '{"item_id": 101, "quantidade": 5}', 'Capacete de Ferro', 'Espada de Diamante'),
(2, 1, '{"item_id": 201, "quantidade": 1}', 'Armadura de Couro', 'Arco Longo')
ON CONFLICT (id_jogador, id_inventario) DO NOTHING;
1.3 Linguagem de Consulta de Dados (DQL)
Aqui estão algumas consultas DQL (Data Query Language) para recuperar e analisar os dados armazenados no banco de dados.
-- =================================================================
-- Consultas Básicas
-- Seleciona todos os dados de cada tabela individualmente.
-- =================================================================
-- Seleciona todos os mapas
SELECT * FROM Mapa;
-- Seleciona todos os biomas
SELECT * FROM Bioma;
-- Seleciona todos os chunks
SELECT * FROM Chunk;
-- Seleciona todos os jogadores
SELECT * FROM Jogador;
-- Seleciona todos os inventários
SELECT * FROM Inventario;
-- Consulta 1: Jogadores e sua Localização Atual
-- Mostra em qual chunk, bioma, mapa e turno cada jogador está.
SELECT
j.Nome AS Nome_Jogador,
j.Vida_atual,
j.xp,
c.Numero_chunk,
c.Id_bioma AS Bioma,
c.Id_mapa_nome AS Mapa,
c.Id_mapa_turno AS Turno
FROM
Jogador j
JOIN
Chunk c ON j.Id_Chunk_Atual = c.Numero_chunk;
-- Consulta 2: Inventário de Cada Jogador
-- Lista os itens, armadura e arma equipada para cada jogador.
SELECT
j.Nome AS Nome_Jogador,
i.Instancia_Item,
i.ArmaduraEquipada,
i.ArmaEquipada
FROM
Inventario i
JOIN
Jogador j ON i.id_jogador = j.Id_jogador; -- Assumindo que 'Id_jogador' é a chave primária da tabela Jogador.
-- Consulta 3: Detalhes Completos dos Chunks
-- Visualiza os detalhes de cada chunk, incluindo o nome do bioma e as informações do mapa.
SELECT
c.Numero_chunk,
b.NomeBioma,
m.Nome AS Nome_Mapa,
m.Turno
FROM
Chunk c
JOIN
Bioma b ON c.Id_bioma = b.NomeBioma
JOIN
Mapa m ON c.Id_mapa_nome = m.Nome AND c.Id_mapa_turno = m.Turno;
1.4 DML: Geração de 1000 Chunks
Este script DML avançado preenche o banco de dados com 1000 “chunks” para simular um mapa maior. Ele inclui lógica para distribuir os biomas (Oceano, Deserto, Selva, Floresta) de forma programática.
-- Script DML para popular o banco de dados com 1000 chunks
-- Mapa: 32x32 chunks (1024 chunks total, mas vamos usar 1000)
-- Estrutura: Oceano ao redor, deserto no centro (20%), selva e floresta no resto
-- Inserir mapas (Dia e Noite)
INSERT INTO Mapa (Nome, Turno)
VALUES
('Mapa_Principal', 'Dia'),
('Mapa_Principal', 'Noite')
ON CONFLICT (Nome, Turno) DO NOTHING;
-- Inserir biomas
INSERT INTO Bioma (NomeBioma)
VALUES
('Deserto'),
('Oceano'),
('Selva'),
('Floresta')
ON CONFLICT (NomeBioma) DO NOTHING;
-- Função para gerar chunks com a distribuição especificada
-- Mapa 32x32 com oceano na borda, deserto no centro, selva e floresta no resto
DO $$
DECLARE
chunk_id INTEGER := 1;
x INTEGER;
y INTEGER;
biome_name VARCHAR(100);
map_size INTEGER := 32;
center_start INTEGER := 12; -- Início da área central (deserto)
center_end INTEGER := 20; -- Fim da área central (deserto)
desert_chunks INTEGER := 0;
ocean_chunks INTEGER := 0;
jungle_chunks INTEGER := 0;
forest_chunks INTEGER := 0;
BEGIN
-- Gerar chunks para o mapa de dia
FOR y IN 1..map_size LOOP
FOR x IN 1..map_size LOOP
-- Determinar bioma baseado na posição
IF x = 1 OR x = map_size OR y = 1 OR y = map_size THEN
-- Borda: Oceano
biome_name := 'Oceano';
ocean_chunks := ocean_chunks + 1;
ELSIF x >= center_start AND x <= center_end AND y >= center_start AND y <= center_end THEN
-- Centro: Deserto (área 9x9 = 81 chunks, aproximadamente 20% de 1000)
biome_name := 'Deserto';
desert_chunks := desert_chunks + 1;
ELSE
-- Resto: Alternar entre Selva e Floresta
IF (x + y) % 2 = 0 THEN
biome_name := 'Selva';
jungle_chunks := jungle_chunks + 1;
ELSE
biome_name := 'Floresta';
forest_chunks := forest_chunks + 1;
END IF;
END IF;
-- Inserir chunk
INSERT INTO Chunk (Numero_chunk, Id_bioma, Id_mapa_nome, Id_mapa_turno)
VALUES (chunk_id, biome_name, 'Mapa_Principal', 'Dia')
ON CONFLICT (Numero_chunk) DO NOTHING;
chunk_id := chunk_id + 1;
-- Parar após 1000 chunks
IF chunk_id > 1000 THEN
EXIT;
END IF;
END LOOP;
-- Parar após 1000 chunks
IF chunk_id > 1000 THEN
EXIT;
END IF;
END LOOP;
-- Gerar chunks para o mapa de noite (mesma distribuição)
chunk_id := 1001;
FOR y IN 1..map_size LOOP
FOR x IN 1..map_size LOOP
-- Determinar bioma baseado na posição
IF x = 1 OR x = map_size OR y = 1 OR y = map_size THEN
-- Borda: Oceano
biome_name := 'Oceano';
ELSIF x >= center_start AND x <= center_end AND y >= center_start AND y <= center_end THEN
-- Centro: Deserto
biome_name := 'Deserto';
ELSE
-- Resto: Alternar entre Selva e Floresta
IF (x + y) % 2 = 0 THEN
biome_name := 'Selva';
ELSE
biome_name := 'Floresta';
END IF;
END IF;
-- Inserir chunk
INSERT INTO Chunk (Numero_chunk, Id_bioma, Id_mapa_nome, Id_mapa_turno)
VALUES (chunk_id, biome_name, 'Mapa_Principal', 'Noite')
ON CONFLICT (Numero_chunk) DO NOTHING;
chunk_id := chunk_id + 1;
-- Parar após 2000 chunks total (1000 para cada turno)
IF chunk_id > 2000 THEN
EXIT;
END IF;
END LOOP;
-- Parar após 2000 chunks total
IF chunk_id > 2000 THEN
EXIT;
END IF;
END LOOP;
-- Mostrar estatísticas
RAISE NOTICE 'Chunks gerados para o mapa de dia:';
RAISE NOTICE 'Deserto: % chunks', desert_chunks;
RAISE NOTICE 'Oceano: % chunks', ocean_chunks;
RAISE NOTICE 'Selva: % chunks', jungle_chunks;
RAISE NOTICE 'Floresta: % chunks', forest_chunks;
RAISE NOTICE 'Total: % chunks', (desert_chunks + ocean_chunks + jungle_chunks + forest_chunks);
END
$$ LANGUAGE plpgsql;
-- Inserir alguns jogadores de exemplo (apenas se não existirem)
INSERT INTO Jogador (Nome, Vida_max, Vida_atual, xp, forca, Id_Chunk_Atual)
VALUES
('Player1', 100, 100, 0, 10, 1),
('Player2', 120, 120, 50, 12, 2),
('Player3', 110, 110, 25, 11, 3)
ON CONFLICT (Id_Jogador) DO NOTHING;
1.5 Vídeo de Demonstração
Assista ao nosso vídeo de demonstração aqui: Vídeo do módulo 2 no YouTube