Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ O **Isometricon** foi planejado com interfaces limpas no módulo `src/integratio
| Módulo | Equipe A (Motor do Mundo) | Equipe B (Motor Interativo) |
| :--- | :--- | :--- |
| **Responsabilidade** | Chunks, VoxelGrid, Terreno, Shaders, Otimização | Raycasting, Grid, Miniaturas, UI |
| **Fornece** | `VoxelGridProvider`, `CameraStateProvider` | Comandos de seleção e movimento |
| **Consome** | Coordenadas de foco e seleção da Equipe B | `VoxelGrid`, `ViewMatrix`, `ProjectionMatrix` |
| **Fornece** | `VoxelGridProvider` e estado de frame no loop principal | Raycasting, grid, miniaturas e destaques |
| **Consome** | Dados de terreno por `VoxelGridProvider` | View, Projection, Model e viewport passados diretamente |

> Consulte [docs/INTEGRATION_SPEC.md](docs/INTEGRATION_SPEC.md) para a especificação completa do contrato.

Expand Down
14 changes: 6 additions & 8 deletions docs/EQUIPE_B_ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ O **Motor Interativo (Interactive Engine)** é o subprojeto da **Equipe B** resp
+-----------------------------+ +-------------------------------+
| |
+----------- src/integration/ ----------+
VoxelGridProvider / Bridge
VoxelGridProvider
```

---
Expand All @@ -40,11 +40,9 @@ src/
│ ├── grid_overlay.py # Renderização do grid quadriculado
│ ├── token_manager.py # Gerenciamento de miniaturas/tokens
│ └── ui_renderer.py # Overlay de UI (fichas de RPG)
├── integration/ # 🔌 Ponte Equipe A <-> Equipe B
├── integration/ # 🔌 Consulta compartilhada A <-> B
│ ├── __init__.py
│ ├── voxel_provider.py # VoxelGridProvider (implementação)
│ ├── highlight_bridge.py # HighlightBridge (ativa hover shader)
│ └── camera_provider.py # CameraStateProvider (matrizes)
│ └── voxel_grid.py # VoxelGridProvider (implementação)
assets/
├── shaders/
│ ├── highlight.vert # 🟦 Shader de destaque/hover (vertex)
Expand Down Expand Up @@ -315,9 +313,9 @@ Consulte o documento completo em [docs/INTEGRATION_SPEC.md](INTEGRATION_SPEC.md)

| Interface | Provedor | Consumidor | Finalidade |
|-----------|----------|------------|------------|
| `VoxelGridProvider` | Equipe A | Equipe B | Consulta blocos e colisão |
| `HighlightBridge` | Equipe A | Equipe B | Ativa hover shader |
| `CameraStateProvider` | Equipe A | Equipe B | Matrizes View/Proj para raycasting |
| `VoxelGridProvider` | Motor do Mundo | Motor Interativo | Consulta blocos carregados |
| Matrizes de frame | `src.main` | Raycast e renderizadores | View, Projection, Model e viewport passados diretamente |
| Renderizadores de overlay | Motor Interativo | Loop principal | Controlam hover e visibilidade da grade diretamente |

---

Expand Down
319 changes: 65 additions & 254 deletions docs/INTEGRATION_SPEC.md

Large diffs are not rendered by default.

21 changes: 19 additions & 2 deletions src/integration/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 🔌 Módulo de Integração (Team B Bridge)
# 🔌 Módulo de Integração

Ponto de contato entre o Motor do Mundo (Equipe A) e o Motor Interativo
(Equipe B).
Expand All @@ -15,7 +15,11 @@ usando coordenadas globais `(x, y, z)`.
Para mundos estáticos, ele recebe um mapeamento de chunks. Para o mundo com
streaming, `block_lookup=world_manager.neighbor_at` mantém as consultas ligadas
aos chunks atualmente carregados. Uma região ausente continua retornando
`AIR`; a consulta não carrega chunks nem aguarda o worker assíncrono.
`AIR`; nenhuma consulta carrega chunks nem aguarda o worker assíncrono.

`get_top_solid_block(x, z)` percorre somente a coluna vertical atualmente
usada pelo `WorldManager` (chunk `y=0`) e também retorna `-1` quando a coluna
não está carregada. O mundo streamado não possui bounds globais fixos.

### Consultas

Expand All @@ -39,6 +43,19 @@ As coordenadas fornecidas à interface são sempre coordenadas globais.
A conversão para chunk/local é feita internamente e suporta coordenadas
negativas.

### Semântica de ocupação e superfície

`is_solid()` significa "bloco ocupado": qualquer valor diferente de `AIR`,
inclusive `WATER` e `LEAVES`. A superfície tática válida para tokens e grade
é uma política separada de `src.interaction.surface`.

### Integração de frame

O estado de câmera/frame é passado diretamente pelo loop principal ao
raycasting e aos renderizadores. Hover/highlight e visibilidade da grade são
controlados diretamente por `BlockHighlightRenderer` e `GridOverlayRenderer`;
não há `CameraStateProvider` nem `HighlightBridge` no contrato atual.

### AABB

Cada voxel ocupa:
Expand Down
15 changes: 13 additions & 2 deletions src/integration/voxel_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,21 @@ def get_top_solid_block(
world_x: int,
world_z: int,
) -> int:
# Retorna o maior Y sólido existente na coluna X/Z
# A busca utiliza somente chunks carregados, caso não exista nenhum bloco sólido na coluna, retorna -1
"""Retorna o maior Y não-AIR da coluna carregada em ``(x, z)``.

O ``WorldManager`` atual transmite apenas colunas no chunk vertical
``y=0``. No modo dinâmico, a busca consulta essa coluna diretamente
pelo ``block_lookup``: regiões descarregadas continuam retornando AIR
e a consulta não interage com as filas de streaming.
"""
x = _coordinate(world_x)
z = _coordinate(world_z)
if self._block_lookup is not None:
for y in range(Chunk3D.SIZE - 1, -1, -1):
if self.get_block_at(x, y, z) != BlockType.AIR:
return y
return -1

best_y: int | None = None
for chunk in self._chunks.values():
chunk_x_min = chunk.chunk_x * Chunk3D.SIZE
Expand Down
2 changes: 1 addition & 1 deletion src/interaction/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Este pacote contém toda a lógica de interação do usuário com o tabuleiro:

## Dependências

- `src/integration/` — Pontos de contato com a Equipe A (VoxelGridProvider, HighlightBridge, CameraStateProvider)
- `src/integration/` — Consulta de terreno compartilhada (`VoxelGridProvider`)
- `src/rendering/` — TexturedMesh para renderização dos tokens
- `src/camera/` — IsometricCamera para cálculos de raycasting

Expand Down
15 changes: 8 additions & 7 deletions src/interactive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,18 @@ O diretório `src/interactive/` contém todos os módulos da **Equipe B (Motor I
## Arquitetura de Integração

```
src/integration/ ← Bridge A↔B (mantido pela Equipe A)
voxel_provider.py ← Consulta de blocos do mundo
camera_provider.py ← Estado da câmera (view/proj)
highlight_bridge.py ← Ativa shaders de destaque
src/integration/
voxel_grid.py ← VoxelGridProvider: consulta de blocos do mundo

src/interactive/ ← DOMÍNIO DA EQUIPE B
raycasting.py
highlight.py
grid_overlay.py
token_system.py
ui_overlay.py
```

Consulte [INTEGRATION_SPEC.md](../../docs/INTEGRATION_SPEC.md) para o contrato completo de interfaces.
O loop principal passa View, Projection, Model e viewport diretamente ao
raycasting e aos renderizadores. Highlight e grid mantêm seu próprio estado;
`CameraStateProvider` e `HighlightBridge` não fazem parte da arquitetura atual.
Seleção persistente, alcance de movimento e click-to-move continuam futuros.

Consulte [INTEGRATION_SPEC.md](../../docs/INTEGRATION_SPEC.md) para o contrato completo.
7 changes: 3 additions & 4 deletions src/world/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ Responsável pelo armazenamento, geração e otimização dos dados de blocos do
permanecem inteiras. O cubo de demonstração centrado em main.py precisará
ser posicionado no centro da célula pela futura renderização.

O contrato VoxelGridProvider permanece futuro: consultas globais, solidez,
topo de coluna e AABB por bloco serão compostas sobre esta fundação.
A representação AABB contém somente dados; raycasting permanece fora deste módulo.
`VoxelGridProvider` já compõe sobre esta fundação consultas globais, ocupação,
topo de coluna e AABB por bloco. A representação AABB contém somente dados;
raycasting permanece fora deste módulo.

## Meshing CPU (Issue #6)

Expand Down Expand Up @@ -279,4 +279,3 @@ validação da API e geometria/índices do mesher sem contexto gráfico.

Fora desta etapa: WorldManager/streaming, save/load, biomas, vegetação,
estruturas, greedy meshing, frustum culling, materiais avançados e Equipe B.

24 changes: 23 additions & 1 deletion tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from src.math.aabb import AABB
from src.integration import VoxelGridProvider
from src.world import BlockType, Chunk3D
from src.world import BlockType, Chunk3D, TerrainGenerator, WorldManager


def make_chunk(
Expand Down Expand Up @@ -98,6 +98,28 @@ def test_top_solid_block_across_y_chunks():
assert provider.get_top_solid_block(3, 4) == 16


def test_top_solid_block_uses_loaded_dynamic_world_chunks():
generator = TerrainGenerator(seed=27, enable_caves=False)
manager = WorldManager(
generator=generator,
render_distance=0,
create_gl_meshes=False,
async_loading=False,
)
try:
manager.load_initial_region(-1.0, -1.0)
provider = VoxelGridProvider(block_lookup=manager.neighbor_at)

expected_y = max(generator.get_height(-1, -1), generator.sea_level)
assert provider.get_top_solid_block(-1, -1) == expected_y

manager.update(32.0, -1.0)
assert provider.get_block_at(-1, expected_y, -1) is BlockType.AIR
assert provider.get_top_solid_block(-1, -1) == -1
finally:
manager.delete()


def test_block_bounding_box():
provider = VoxelGridProvider()

Expand Down