Skip to content
Closed
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
12 changes: 8 additions & 4 deletions docs/guide/assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ any Community/showcase page.
| **Empire toll gate** | `public/models/toll-gate.glb` | **1947** | 4.1 MiB | static | preview `019ee748-205e-763a-a883-bdda11e91c7e` · retexture `019ee749-ae59-7680-aa94-e6a8842c7bd5` |
| **Caravan wagon (Salt Road)** *(wired: caravan enemy visual + forest static prop, FLO-470)* | `public/models/caravan-wagon.glb` | **2827** | 394 KiB | static | `019ee749-d4cf-79b9-b813-d98be2201197` (preview) / `019ee74d-2300-772c-8a22-612c27dd99dc` (retexture) |
| **Cargo crate (Salt Road)** *(wired: forest cargo decor, FLO-470)* | `public/models/cargo-crate.glb` | **1022** | 296 KiB | static | `019ee743-a02c-7878-a22e-7b67cdfbafa6` (preview) |
| **Ruined watchtower (Salt Road)** | `public/models/watchtower.glb` | **2564** | 379 KiB | static | `019ee749-6051-7990-b286-98be4ecf82b4` (retexture) |
| **Ruined watchtower (Salt Road)** *(wired: forest landmark, FLO-476)* | `public/models/watchtower.glb` | **2564** | 379 KiB | static | `019ee749-6051-7990-b286-98be4ecf82b4` (retexture) |
| **Ranged enemy (archer)** | `public/models/ranged-archer.glb` | **2589** | 258 KiB | static (no skeleton) | preview `019ee91a-3128-705b-8acc-3d10e03e9930` · retexture `019ee91c-7315-78b1-8841-a90f77930d17` |
| **Empire palace-guard** | `public/models/empire-palace-guard.glb` | **2793** | 357 KiB | static (no skeleton) | retexture `019ee91c-7f15-78b4-9665-5f7c18268eec` (of soldier `019ee601-93f0-7988-86f8-e35ce1067881`) |

Expand Down Expand Up @@ -113,9 +113,11 @@ in `src/scenes/humanLandsScene.ts`.
- **Rig:** ships **static** (no skeleton) — it is scenery, not animated.
- **Verification:** loads headless via `node tools/meshy-3d/smoke_load_glb.mjs
public/models/watchtower.glb` → 2 meshes, 2564 tris, no errors.
- **Handoff:** wiring the GLB into the scene (replacing the procedural
watchtower box at `humanLandsScene.ts:60`) is engineering's job — for
Daedalus/CTO, not done here.
- **Wiring:** FLO-476 places the GLB in the first forest map as
`landmark.forest-watchtower`, streamed through `defaultLoadGlb()` with the
matte/faceted conform. The canonical Salt Road / human-lands landmark remains a
separate scene-wiring concern; this forest placement is the board-requested
first-map landmark.

### Empire soldier (enemy) — Phase 2

Expand Down Expand Up @@ -314,6 +316,8 @@ the same streaming manifest used by the tree/hut props:
prop; also the live `CaravanEnemy` visual.
- `korovany_hero_player-default.glb` → `npc.forest-static-elf`, two static
decorative forest elves.
- `watchtower.glb` → `landmark.forest-watchtower`, one large static ruined tower
placed near the first forest map as a visible silhouette landmark (FLO-476).

All streamed GLBs go through `defaultLoadGlb`, which normalizes them with
`loadModel()` and applies the shared `flatShade()` matte/faceted conform before
Expand Down
1 change: 1 addition & 0 deletions src/game/streaming/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export {
FOREST_CHEST_ASSET_ID,
FOREST_STATIC_ELF_ASSET_ID,
FOREST_TREE_ASSET_ID,
FOREST_WATCHTOWER_ASSET_ID,
WOODEN_HUT_ASSET_ID,
} from './zoneManifests'
export {
Expand Down
6 changes: 5 additions & 1 deletion src/game/streaming/zoneManifests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
FOREST_CHEST_ASSET_ID,
FOREST_STATIC_ELF_ASSET_ID,
WOODEN_HUT_ASSET_ID,
FOREST_WATCHTOWER_ASSET_ID,
ZONE_MANIFESTS,
getZoneManifest,
} from './zoneManifests'
Expand All @@ -19,12 +20,15 @@ describe('zone manifests', () => {
}
})

it('streams the forest props plus leftover decor (12 trees, 3 huts, 5 leftovers)', () => {
it('streams the forest props plus leftover decor (12 trees, 3 huts, 6 leftovers)', () => {
const forest = getZoneManifest('forest')
const trees = forest.placements.filter((p) => p.assetId === FOREST_TREE_ASSET_ID)
const huts = forest.placements.filter((p) => p.assetId === WOODEN_HUT_ASSET_ID)
expect(trees).toHaveLength(12)
expect(huts).toHaveLength(3)
const watchtower = forest.placements.find((p) => p.assetId === FOREST_WATCHTOWER_ASSET_ID)
expect(watchtower?.position).toEqual({ x: 12.5, y: 0, z: -13.5 })
expect(watchtower?.rotationY).toBeCloseTo(-0.55)
expect(forest.placements.filter((p) => p.assetId === FOREST_CHEST_ASSET_ID)).toHaveLength(1)
expect(forest.placements.filter((p) => p.assetId === FOREST_CARGO_CRATE_ASSET_ID)).toHaveLength(1)
expect(forest.placements.filter((p) => p.assetId === FOREST_CARAVAN_WAGON_ASSET_ID)).toHaveLength(1)
Expand Down
7 changes: 7 additions & 0 deletions src/game/streaming/zoneManifests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export const FOREST_CARGO_CRATE_ASSET_ID = 'prop.forest-cargo-crate'
export const FOREST_CARAVAN_WAGON_ASSET_ID = 'prop.forest-caravan-wagon'
/** Retired hero GLB reused as static forest elf NPC decor (FLO-470). */
export const FOREST_STATIC_ELF_ASSET_ID = 'npc.forest-static-elf'
/** Ruined watchtower placed in the first forest map as a landmark (FLO-476). */
export const FOREST_WATCHTOWER_ASSET_ID = 'landmark.forest-watchtower'

/** Tree positions: (x, z) pairs in scene units. Keeps a 4-unit clearing. */
const FOREST_TREE_POSITIONS: readonly [number, number][] = [
Expand All @@ -54,6 +56,11 @@ const FOREST_HUT_POSITIONS: readonly [number, number][] = [
]

const FOREST_LEFTOVER_PLACEMENTS: readonly ZoneAssetPlacement[] = [
{
assetId: FOREST_WATCHTOWER_ASSET_ID,
position: { x: 12.5, y: 0, z: -13.5 },
rotationY: -0.55,
},
{
assetId: FOREST_CARAVAN_WAGON_ASSET_ID,
position: { x: -5.5, y: 0, z: -9 },
Expand Down
9 changes: 7 additions & 2 deletions src/scenes/forestScene.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
FOREST_CHEST_ASSET_ID,
FOREST_STATIC_ELF_ASSET_ID,
FOREST_TREE_ASSET_ID,
FOREST_WATCHTOWER_ASSET_ID,
FOREST_SPAWN_PROP_SPECS,
FOREST_ZONE_ID,
SAFE_SPAWN_BUFFER,
Expand Down Expand Up @@ -57,14 +58,18 @@ describe('seedForestAssets', () => {
expect(registry.resolve(FOREST_STATIC_ELF_ASSET_ID).url).toBe(
'/models/korovany_hero_player-default.glb',
)
expect(registry.resolve(FOREST_WATCHTOWER_ASSET_ID).url).toBe('/models/watchtower.glb')
})

it('gives the tree a larger targetSize than the hut', () => {
it('gives landmark-scale assets a larger targetSize than ordinary props', () => {
const registry = new AssetRegistry()
seedForestAssets(registry)
expect(registry.resolve(FOREST_TREE_ASSET_ID).metadata.targetSize).toBeGreaterThan(
registry.resolve(WOODEN_HUT_ASSET_ID).metadata.targetSize ?? 0,
)
expect(registry.resolve(FOREST_WATCHTOWER_ASSET_ID).metadata.targetSize).toBeGreaterThan(
registry.resolve(FOREST_TREE_ASSET_ID).metadata.targetSize ?? 0,
)
})

// The forest manifest (E3.2 wiring) and the registry seeding live in separate
Expand Down Expand Up @@ -417,7 +422,7 @@ describe('forest safe spawn & difficulty curve (FLO-412)', () => {
expect(onPlayerDamaged).not.toHaveBeenCalled()

game.dispose()
})
}, 15_000)

// Acceptance (FLO-412): the player can walk to a caravan without dying. The
// nearest caravan (`caravan-1`, (-8,-6), 10 m) sits inside the soldier-free
Expand Down
6 changes: 6 additions & 0 deletions src/scenes/forestScene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
FOREST_CHEST_ASSET_ID,
FOREST_STATIC_ELF_ASSET_ID,
FOREST_TREE_ASSET_ID,
FOREST_WATCHTOWER_ASSET_ID,
WOODEN_HUT_ASSET_ID,
ZoneStreamingManager,
defaultLoadGlb,
Expand Down Expand Up @@ -104,6 +105,7 @@ export {
FOREST_CHEST_ASSET_ID,
FOREST_STATIC_ELF_ASSET_ID,
FOREST_TREE_ASSET_ID,
FOREST_WATCHTOWER_ASSET_ID,
WOODEN_HUT_ASSET_ID,
}

Expand Down Expand Up @@ -154,6 +156,10 @@ export function seedForestAssets(registry: AssetRegistry): void {
url: '/models/korovany_hero_player-default.glb',
metadata: { label: 'Static forest elf', targetSize: 1.8 },
})
registry.register(FOREST_WATCHTOWER_ASSET_ID, {
url: '/models/watchtower.glb',
metadata: { label: 'Forest watchtower', targetSize: 9 },
})
}

function propMaterial(scene: Scene, name: string, color: Color3): StandardMaterial {
Expand Down
Loading