8. Modelos

O MINECRAFT - FGA - 2025/1 utiliza uma arquitetura baseada em models para representar as entidades do jogo. Esta abordagem garante separação de responsabilidades, reutilização de código e facilita a manutenção.

8.1. Estrutura de Models

app/src/models/
├── __init__.py          # Exporta todas as models
├── player.py            # Models do personagem (Player e PlayerSession)
├── chunk.py             # Model do chunk
├── bioma.py             # Model do bioma
├── mapa.py              # Model do mapa
├── item.py              # Model do item
└── inventory.py         # Model do inventário

8.2. Player

A model Player representa um personagem principal do jogo com todos os seus atributos persistentes.

class models.player.Player(id_player, nome, vida_maxima, vida_atual, forca, localizacao, nivel, experiencia, current_chunk_id=None, inventario=<factory>)[source]

Bases: object

Model que representa um personagem no banco de dados

Variables:
  • id_player (int) – ID único do personagem no banco

  • nome (str) – Nome do personagem

  • vida_maxima (int) – Vida máxima do personagem

  • vida_atual (int) – Vida atual do personagem

  • forca (int) – Força do personagem

  • localizacao (str) – Localização atual do personagem

  • nivel (int) – Nível do personagem

  • experiencia (int) – Experiência acumulada

__eq__(other)[source]

Comparação de igualdade baseada no ID

__hash__()[source]

Hash baseado no ID

__post_init__()[source]

Validações após inicialização

__repr__()[source]

Representação detalhada do personagem

__str__()[source]

Representação string do personagem

current_chunk_id: int | None = None
experiencia: int
forca: int
gain_experience(amount)[source]

Adiciona experiência ao personagem

Parameters:

amount (int) – Quantidade de experiência a ser adicionada

get_health_bar(width=20)[source]

Retorna uma barra de vida visual

Parameters:

width (int) – Largura da barra em caracteres

Returns:

String representando a barra de vida

Return type:

str

get_health_percentage()[source]

Retorna a porcentagem de vida atual

Returns:

Porcentagem de vida (0.0 a 1.0)

Return type:

float

heal(amount)[source]

Cura o personagem

Parameters:

amount (int) – Quantidade de vida a ser restaurada

id_player: int
inventario: List[InventoryEntry]
is_alive()[source]

Verifica se o personagem está vivo

level_up()[source]

Tenta fazer o personagem subir de nível

Returns:

True se subiu de nível

Return type:

bool

localizacao: str
nivel: int
nome: str
take_damage(damage)[source]

Aplica dano ao personagem

Parameters:

damage (int) – Quantidade de dano a ser aplicado

Returns:

True se o personagem ainda está vivo após o dano

Return type:

bool

vida_atual: int
vida_maxima: int

Exemplo de uso:

from src.models.player import Player
from src.models.inventory import InventoryEntry

# Criar um personagem
player = Player(
    id_player=1,
    nome="Steve",
    vida_maxima=100,
    vida_atual=85,
    forca=12,
    localizacao="Mapa 1 - Chunk 1",
    nivel=1,
    experiencia=150,
    current_chunk_id=1
)

# Verificar se está vivo
if player.is_alive():
    print("Personagem está vivo!")

# Aplicar dano
sobreviveu = player.take_damage(20)

# Ganhar experiência
player.gain_experience(50)

# Tentar subir de nível
if player.level_up():
    print("Subiu de nível!")

# Exibir barra de vida
print(player.get_health_bar())

8.3. PlayerSession

A model PlayerSession representa um personagem ativo na sessão do jogo com informações otimizadas para performance.

class models.player.PlayerSession(id_player, nome, vida_max, vida_atual, xp, forca, id_chunk_atual=None, chunk_bioma=None, chunk_mapa_nome=None, chunk_mapa_turno=None)[source]

Bases: object

Model que representa um personagem ativo na sessão do jogo

Variables:
  • id_player (int) – ID único do personagem no banco

  • nome (str) – Nome do personagem

  • vida_max (int) – Vida máxima do personagem

  • vida_atual (int) – Vida atual do personagem

  • xp (int) – Experiência acumulada

  • forca (int) – Força do personagem

  • id_chunk_atual (int | None) – ID do chunk onde o personagem está

  • chunk_bioma (str | None) – Nome do bioma atual (cache para performance)

  • chunk_mapa_nome (str | None) – Nome do mapa atual (cache para performance)

  • chunk_mapa_turno (str | None) – Turno atual (Dia/Noite) (cache para performance)

__repr__()[source]

Representação detalhada do personagem

__str__()[source]

Representação string do personagem

can_move()[source]

Verifica se o personagem pode se mover

Returns:

True se pode se mover

Return type:

bool

chunk_bioma: str | None = None
chunk_mapa_nome: str | None = None
chunk_mapa_turno: str | None = None
forca: int
gain_xp(amount)[source]

Adiciona experiência ao personagem

Parameters:

amount (int) – Quantidade de XP a ser adicionada

get_health_bar(width=20)[source]

Retorna uma barra de vida visual

Parameters:

width (int) – Largura da barra em caracteres

Returns:

String representando a barra de vida

Return type:

str

get_health_percentage()[source]

Retorna a porcentagem de vida atual

Returns:

Porcentagem de vida (0.0 a 1.0)

Return type:

float

get_location_display()[source]

Retorna a localização formatada para exibição

Returns:

String formatada da localização

Return type:

str

heal(amount)[source]

Cura o personagem

Parameters:

amount (int) – Quantidade de vida a ser restaurada

id_chunk_atual: int | None = None
id_player: int
is_alive()[source]

Verifica se o personagem está vivo

nome: str
take_damage(damage)[source]

Aplica dano ao personagem

Parameters:

damage (int) – Quantidade de dano a ser aplicado

Returns:

True se o personagem ainda está vivo após o dano

Return type:

bool

to_dict()[source]

Converte o personagem para dicionário

vida_atual: int
vida_max: int
xp: int

Exemplo de uso:

from src.models.player import PlayerSession

# Criar uma sessão de personagem
session = PlayerSession(
    id_player=1,
    nome="Steve",
    vida_max=100,
    vida_atual=85,
    xp=150,
    forca=12,
    id_chunk_atual=5,
    chunk_bioma="Oceano",
    chunk_mapa_nome="Mapa_Principal",
    chunk_mapa_turno="Dia"
)

# Verificar se pode se mover
if session.can_move():
    print("Pode se mover!")

# Obter localização formatada
print(session.get_location_display())

# Converter para dicionário
data = session.to_dict()

8.4. Chunk

A model Chunk representa um chunk do mapa do jogo com suas coordenadas e relacionamentos.

class models.chunk.Chunk(id_chunk, id_bioma, id_mapa, x, y)[source]

Bases: object

Model que representa um chunk do mapa

Variables:
  • id_chunk (int) – Identificador único do chunk (chave primária)

  • id_bioma (int) – FK para Bioma.id_bioma

  • id_mapa (int) – FK para Mapa.id_mapa

  • x (int) – Coordenada X do chunk no grid

  • y (int) – Coordenada Y do chunk no grid

__eq__(other)[source]

Comparação de igualdade baseada na chave primária

__hash__()[source]

Hash baseado na chave primária

__repr__()[source]

Representação detalhada do chunk

__str__()[source]

Representação string do chunk

belongs_to_map(mapa_nome, mapa_turno)[source]

Verifica se o chunk pertence a um mapa específico

Parameters:
  • mapa_nome (str) – Nome do mapa

  • mapa_turno (str) – Turno do mapa

Returns:

True se o chunk pertence ao mapa

Return type:

bool

get_adjacent_chunk_ids(map_size=32)[source]

Retorna os IDs dos chunks adjacentes Baseado na lógica de grid do mapa

Parameters:

map_size (int) – Tamanho do mapa (assumindo mapa quadrado)

Returns:

Lista de IDs dos chunks adjacentes

Return type:

List[int]

get_bioma_type()[source]

Retorna o tipo de bioma como string

Returns:

Nome do bioma

Return type:

str

get_display_name()[source]

Retorna o nome formatado do chunk para exibição

Returns:

String formatada do chunk

Return type:

str

get_map_key()[source]

Retorna a chave do mapa como tupla

Returns:

Tupla (nome_mapa, turno_mapa)

Return type:

tuple

id_bioma: int
id_chunk: int
id_mapa: int
is_day()[source]

Verifica se é dia no chunk

is_desert()[source]

Verifica se o chunk é um deserto

is_forest()[source]

Verifica se o chunk é uma floresta

is_jungle()[source]

Verifica se o chunk é uma selva

is_night()[source]

Verifica se é noite no chunk

is_ocean()[source]

Verifica se o chunk é um oceano

x: int
y: int

Exemplo de uso:

from src.models.chunk import Chunk

# Criar um chunk
chunk = Chunk(
    id_chunk=1,
    id_bioma=2,  # ID do bioma Oceano
    id_mapa=1,   # ID do mapa principal
    x=10,
    y=15
)

# Verificar tipo de bioma por ID
if chunk.id_bioma == 2:
    print("É um oceano!")

# Obter nome formatado
print(chunk.get_display_name())

# Obter chunks adjacentes
adjacentes = chunk.get_adjacent_chunk_ids()

# Verificar se é dia ou noite baseado na coordenada
if chunk.is_day():
    print("É dia neste chunk!")

8.5. Bioma

A model Bioma representa um bioma do jogo com suas características.

class models.bioma.Bioma(id_bioma, nome, descricao)[source]

Bases: object

Model que representa um bioma do jogo

Variables:
  • id_bioma (int) – Identificador único do bioma (chave primária)

  • nome (str) – Nome do bioma

  • descricao (str) – Descrição do bioma

__eq__(other)[source]

Comparação de igualdade baseada na chave primária

__hash__()[source]

Hash baseado na chave primária

__repr__()[source]

Representação detalhada do bioma

__str__()[source]

Representação string do bioma

descricao: str
id_bioma: int
nome: str
class models.bioma.BiomaType(value)[source]

Bases: Enum

Tipos de bioma disponíveis no jogo

DESERTO = 'Deserto'
FLORESTA = 'Floresta'
OCEANO = 'Oceano'
SELVA = 'Selva'

Biomas Predefinidos:

from src.models.bioma import BIOMAS_PREDEFINIDOS, BiomaType, Bioma

# Usar bioma predefinido
deserto = BIOMAS_PREDEFINIDOS[BiomaType.DESERTO]

# Criar bioma personalizado
bioma_custom = Bioma(
    id_bioma=5,
    nome="Tundra",
    descricao="Um bioma frio e gelado."
)

# Comparar biomas
if deserto == bioma_custom:
    print("São o mesmo bioma!")

8.6. Mapa

A model Mapa representa um mapa do jogo com seus chunks e características temporais.

class models.mapa.Mapa(id_mapa, nome, turno, chunks=<factory>)[source]

Bases: object

Model que representa um mapa do jogo

Variables:
  • id_mapa (int) – Identificador único do mapa (chave primária)

  • nome (str) – Nome do mapa

  • turno (models.mapa.TurnoType) – Turno do mapa

  • chunks (List[models.chunk.Chunk]) – Lista de chunks relacionados a este mapa

  • _chunk_repository – Repository para acesso aos chunks (injeção de dependência)

__eq__(other)[source]

Comparação de igualdade baseada na chave primária composta

__hash__()[source]

Hash baseado na chave primária composta

__post_init__()[source]

Converte string para enum se necessário

__repr__()[source]

Representação detalhada do mapa

__str__()[source]

Representação string do mapa

chunks: List[Chunk]
get_bioma_distribution()[source]

Retorna a distribuição de biomas no mapa

Returns:

Dicionário com bioma e quantidade de chunks

Return type:

Dict[str, int]

get_chunk_by_id(chunk_id)[source]

Busca um chunk pelo ID neste mapa

Parameters:

chunk_id (int) – ID do chunk

Returns:

Chunk encontrado ou None

Return type:

Chunk | None

get_chunks()[source]

Retorna os chunks deste mapa usando o repository

get_chunks_by_bioma(bioma)[source]

Retorna todos os chunks de um bioma específico neste mapa

Parameters:

bioma (str) – Nome do bioma

Returns:

Lista de chunks do bioma

Return type:

List[Chunk]

get_display_info()[source]

Retorna informações formatadas do mapa para exibição

Returns:

Dicionário com informações do mapa

Return type:

Dict[str, Any]

id_mapa: int
is_day_map()[source]

Verifica se é um mapa de dia

is_night_map()[source]

Verifica se é um mapa de noite

nome: str
set_chunk_repository(repository)[source]

Define o repository de chunks (injeção de dependência)

turno: TurnoType
class models.mapa.TurnoType(value)[source]

Bases: Enum

Tipos de turno disponíveis

DIA = 'Dia'
NOITE = 'Noite'

Exemplo de uso:

from src.models.mapa import Mapa, TurnoType

# Criar mapa
mapa = Mapa(
    id_mapa=1,
    nome="Mapa_Principal",
    turno=TurnoType.DIA
)

# Verificar tipo de turno
if mapa.is_day_map():
    print("É um mapa de dia!")

# Obter informações de exibição
info = mapa.get_display_info()

# Buscar chunk específico (requer repository configurado)
# mapa.set_chunk_repository(chunk_repository)
# chunk = mapa.get_chunk_by_id(1)

8.7. Item

A model Item representa um item do jogo que pode ser coletado ou usado.

class models.item.Item(id_item, nome, tipo, poder=None, durabilidade=None)[source]

Bases: object

Representa um item no inventário ou no jogo

Variables:
  • id_item (int) – Identificador único do item (chave primária)

  • nome (str) – Nome do item

  • tipo (str) – Tipo do item (e.g., ‘Arma’, ‘Poção’, ‘Comida’)

  • poder (int | None) – Opcional, poder de ataque ou efeito do item

  • durabilidade (int | None) – Opcional, durabilidade restante

__hash__()[source]

Hash baseado no ID do item

durabilidade: int | None = None
id_item: int
nome: str
poder: int | None = None
tipo: str

Exemplo de uso:

from src.models.item import Item

# Criar diferentes tipos de itens
espada = Item(
    id_item=1,
    nome="Espada de Ferro",
    tipo="Arma",
    poder=8,
    durabilidade=200
)

pocao = Item(
    id_item=2,
    nome="Poção de Vida",
    tipo="Poção",
    poder=50,
    durabilidade=None  # Poções não têm durabilidade
)

madeira = Item(
    id_item=3,
    nome="Madeira",
    tipo="Material",
    poder=None,
    durabilidade=None
)

8.8. InventoryEntry

A model InventoryEntry representa uma entrada no inventário de um jogador.

class models.inventory.InventoryEntry(id, player_id, item_id, quantidade)[source]

Bases: object

Representa uma entrada de inventário (itens de um jogador)

Variables:
  • id (int) – Identificador único da entrada (chave primária)

  • player_id (int) – FK para Player.id_player

  • item_id (int) – FK para Item.id_item

  • quantidade (int) – Quantidade do item possuído

id: int
item_id: int
player_id: int
quantidade: int

Exemplo de uso:

from src.models.inventory import InventoryEntry

# Criar entrada de inventário
entrada = InventoryEntry(
    id=1,
    player_id=1,
    item_id=3,  # Madeira
    quantidade=64
)

# Modificar quantidade
entrada.quantidade += 32
print(f"Nova quantidade: {entrada.quantidade}")

8.9. Relacionamentos do Banco de Dados

As models refletem exatamente a estrutura do banco de dados:

Mapa (id_mapa, nome, turno) ← Chunk (id_mapa)
Bioma (id_bioma, nome) ← Chunk (id_bioma)
Chunk (id_chunk) ← Player (current_chunk_id)
Player (id_player) ← Inventario (player_id)
Item (id_item) ← Inventario (item_id)

Características dos Relacionamentos:

  • Mapa: Chave primária simples (id_mapa) com constraint única (nome, turno)

  • Bioma: Chave primária simples (id_bioma) com nome único

  • Chunk: Chave primária simples (id_chunk) com FKs para Bioma e Mapa

  • Player: Referencia Chunk através de current_chunk_id (pode ser NULL)

  • Item: Chave primária simples (id_item) com nome único

  • Inventario: Relacionamento N:M entre Player e Item com quantidades

8.10. Integração com o Sistema

As models são utilizadas em conjunto com o sistema de gerenciamento de personagens:

from src.models.player import Player
from src.utils.player_manager import get_current_player, set_current_player
from src.services.interface_service import InterfaceService

# Obter personagem ativo
current_player = get_current_player()

if current_player:
    print(f"Jogando com: {current_player.nome}")
    print(f"Localização: {current_player.localizacao}")
    print(f"Vida: {current_player.get_health_bar()}")

    # Usar interface service para operações
    interface_service = InterfaceService.get_instance()

    # Mover para outro chunk
    updated_player = interface_service.move_player_to_chunk(current_player, 2)

    # Salvar progresso
    interface_service.save_player(updated_player)

8.11. Vantagens da Arquitetura de Models

  1. Separação de Responsabilidades: Cada model tem responsabilidades bem definidas

  2. Reutilização: Models podem ser usadas em diferentes partes do sistema

  3. Manutenibilidade: Mudanças em uma model não afetam outras partes

  4. Testabilidade: Cada model pode ser testada independentemente

  5. Documentação: Models são auto-documentadas com docstrings

  6. Type Safety: Uso de type hints para melhor desenvolvimento

  7. Fidelidade ao Banco: Models refletem exatamente a estrutura do banco

  8. Performance: PlayerSession otimizada para uso em sessões de jogo

8.12. Padrões de Uso

Player vs PlayerSession: - Use Player para operações de persistência e dados completos - Use PlayerSession para otimização de performance em sessões ativas

Localização: - Player.localizacao armazena string formatada (“Mapa 1 - Chunk 1”) - Player.current_chunk_id armazena referência direta ao chunk - PlayerSession inclui cache de informações do chunk para performance

Inventário: - Relação N:M entre Player e Item através de InventoryEntry - Suporte a quantidades e controle de unicidade por constraint

8.13. Exemplos Avançados

Para ver exemplos completos de uso das models em cenários reais, consulte os testes unitários e os services do sistema.

Navegação entre Chunks:

# Obter chunk atual do jogador
current_chunk = interface_service.get_chunk_by_id(player.current_chunk_id)

# Obter chunks adjacentes
adjacent_chunks = interface_service.get_adjacent_chunks(current_chunk.id_chunk, 'Dia')

# Mover para chunk adjacente
if adjacent_chunks:
    next_chunk_id = adjacent_chunks[0][0]
    updated_player = interface_service.move_player_to_chunk(player, next_chunk_id)

Progressão de Personagem:

# Sistema de XP e level up
player.gain_experience(50)

while player.level_up():
    print(f"Subiu para nível {player.nivel}!")
    print(f"Nova vida máxima: {player.vida_maxima}")
    print(f"Nova força: {player.forca}")

# Salvar progresso
interface_service.save_player(player)