475 lines
20 KiB
Markdown
475 lines
20 KiB
Markdown
# RuneWaker instance import guide
|
|
|
|
This guide records how Forsaken Abbey was recovered and packages that work as
|
|
a repeatable, offline-capable process for the remaining RuneWaker instances.
|
|
The preserved client/server files are evidence and build inputs. They are not
|
|
runtime dependencies of HealerMan.
|
|
|
|
## Non-negotiable runtime rule
|
|
|
|
The shipped game may read only ordinary HealerMan source files and packaged
|
|
assets. It must never connect to Microsoft SQL Server, read a RuneWaker backup,
|
|
or depend on `D:\Projects\runewaker`/`rom-pvt-server-backups`.
|
|
|
|
SQL Server is used only by the explicit `refresh` command. That command:
|
|
|
|
1. restores `ROM_Global.bak` and `ObjectEdit.bak` under unique temporary names;
|
|
2. marks both restored databases read-only;
|
|
3. exports one zone to JSON;
|
|
4. drops both temporary databases in `finally` cleanup;
|
|
5. hashes the source backups/catalogs so the snapshot is auditable.
|
|
|
|
Normal environment, actor, population, mechanics-audit, validation, offline,
|
|
build, test, and game commands do not connect to SQL.
|
|
|
|
## What Forsaken Abbey established
|
|
|
|
Forsaken Abbey is the reference import. Its environment recipe is
|
|
`recipes/forsaken-abbey.json`; its population recipe is
|
|
`recipes/forsaken-abbey-population.json`.
|
|
|
|
The completed pass recovered:
|
|
|
|
- the primary monastery ROS selected from 184 WDB descriptors;
|
|
- textured visual, collision chunks, and a Recast navigation GLB;
|
|
- an authoritative entrance from `Resource/luascript/03242.lua`;
|
|
- 251 active Zone 102 spawn rows;
|
|
- 142 ordinary combat rows and eight boss rows (150 runtime spawns);
|
|
- 101 audited deferred object/trigger/quest rows;
|
|
- nine unique combat actor ROS models converted to GLB;
|
|
- eight spawn-specific objectives, including four Necromage Keeper spawns;
|
|
- source hashes, coordinate/projection records, and validation reports.
|
|
|
|
The current actor pass recovers the original GR2 skeletons and sampled ACT/RAS
|
|
clips for the mesh-convertible combat models. Ghoul Drake, keeper doors,
|
|
scripted summons, patrols, treasure loot, and other encounter state still need
|
|
reviewed mechanics passes.
|
|
|
|
## Coordinate conversion
|
|
|
|
RuneWaker server positions are world coordinates. The environment ROS is
|
|
placed by one WDB descriptor. Spawns must be moved into that ROS's local frame
|
|
before the RuneWaker-to-Three coordinate conversion:
|
|
|
|
```text
|
|
sourceLocal = inverse(primaryWdbPlacement) * serverPosition
|
|
threeLocal = (sourceLocal.x, sourceLocal.y, -sourceLocal.z) * metersPerSourceUnit
|
|
```
|
|
|
|
The current calibrated scale is `0.1` meter per RuneWaker source unit. The
|
|
authoritative test-dungeon table uses 360 degrees per turn:
|
|
|
|
```text
|
|
yawRadians = normalizedDirection / 360 * 2*pi
|
|
```
|
|
|
|
Every entrance and spawn is projected to the generated navigation mesh. Combat
|
|
rows must remain within the recipe's maximum projection distance (currently 4
|
|
meters). Deferred objects may be farther away, but the report records them.
|
|
|
|
## Toolchain
|
|
|
|
The pipeline uses:
|
|
|
|
- the preserved/native RuneWaker object factory and ROS bridge;
|
|
- Microsoft DirectXTex `texconv` for DDS to PNG;
|
|
- Blender for OBJ/MTL cleanup and GLB export;
|
|
- glTF Transform with Meshopt for browser delivery;
|
|
- HealerMan's Recast navigation stage;
|
|
- Khronos glTF validation.
|
|
|
|
Set these only when their defaults do not match the machine:
|
|
|
|
```powershell
|
|
$env:RUNEWAKER_ROOT = 'D:\Projects\rom-pvt-server-backups\Runewaker'
|
|
$env:BLENDER_BIN = 'C:\\path\\to\\blender.exe'
|
|
$env:TEXCONV_BIN = 'C:\\path\\to\\texconv.exe'
|
|
$env:RUNEWAKER_SQL_SERVER = '.\\HEALERMAN_RW'
|
|
```
|
|
|
|
## Command overview
|
|
|
|
The generic entry point is:
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs help
|
|
```
|
|
|
|
Commands:
|
|
|
|
| Command | SQL | Purpose |
|
|
| --- | --- | --- |
|
|
| `discover` | No | Index configured dungeons, WDBs, Lua files, and recipe readiness. |
|
|
| `inspect-wdb` | No | Read one WDB and rank likely primary environment ROS models. |
|
|
| `scaffold` | No | Create environment/population recipes plus a review checklist. |
|
|
| `environment` | No | Convert, optimize, navmesh, package, and validate the environment. |
|
|
| `refresh` | Yes | Explicit temporary restore and portable population snapshot refresh. |
|
|
| `actors` | No | Convert reviewed unique creature ROS models to packaged GLBs. |
|
|
| `population` | No | Generate static entities, spawns, bosses, provenance, and report. |
|
|
| `mechanics` | No | Extract Lua/AutoPlot/template mechanic evidence and a review queue. |
|
|
| `offline` | No | Regenerate population and mechanics evidence from packaged inputs. |
|
|
| `build` | No | Environment + actors + population + mechanics + validation. |
|
|
| `validate` | No | Verify accounting, hashes, nav projection, portability, and GLBs. |
|
|
| `prepare-all` | No | Generate all recipes/snapshots from the portable all-zone export. |
|
|
| `build-all` | No | Resumable environment/actors/population/mechanics/validation batch. |
|
|
| `register-all` | No | Generate runtime definitions for every green packaged instance. |
|
|
| `refresh-all` | Yes | Explicit read-only forensic refresh for every configured zone. |
|
|
| `spells:refresh` | No | Rebuild the portable NPC spell catalog from preserved client DB files. |
|
|
| `paperdolls:refresh` | Yes | Export exact ImageObjectDB paperdoll component/color rows to a portable snapshot. |
|
|
| `audit:animation-readiness` | No | Account for source graphs, native clips, proxies, manifests, and shipping GLBs. |
|
|
| `audit:gameplay` | No | Audit source-backed attacks, evidence-only spells, objectives, navigation, and deferred mechanics. |
|
|
|
|
`refresh`, `refresh-all`, and `paperdolls:refresh` are deliberately not part of
|
|
any normal build. They restore temporary read-only databases only long enough
|
|
to create portable JSON, then drop those databases in `finally` cleanup.
|
|
|
|
## Reproducing the completed 30-instance batch
|
|
|
|
The repository contains a portable export for all 30 configured zones: 8,199
|
|
active `NPCData` rows, authoritative `ZoneObjectDB.mapfile` mappings, and hashed
|
|
source evidence. With SQL stopped, regenerate and verify everything with:
|
|
|
|
```powershell
|
|
npm run runewaker:prepare:all
|
|
npm run runewaker:spells:refresh
|
|
npm run runewaker:build:all
|
|
npm run runewaker:register:all
|
|
npm run runewaker:audit:animations
|
|
npm run runewaker:audit:gameplay
|
|
npm test
|
|
npm run build
|
|
```
|
|
|
|
The batch driver supports focused and resumable work:
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs build-all --resume
|
|
node scripts/runewaker-pipeline/cli.mjs build-all --only kalins-shrine,sand-vortex
|
|
node scripts/runewaker-pipeline/cli.mjs build-all --only mystic-altar --phase environment,population,validate --force
|
|
```
|
|
|
|
It writes `runewaker-export-work/all-instances-build-report.json` after each
|
|
dungeon, so a single bad asset does not lose prior work.
|
|
|
|
The batch handles these source cases explicitly and records them in recipes and
|
|
package metadata:
|
|
|
|
- Direct mesh actors select the largest GR2 body hierarchy, sample original
|
|
ACT/RAS controls at 30 Hz, remap skin weights across Blender vertex
|
|
reorder/seams, and ship Khronos-validated native GLBs.
|
|
- Runtime paperdoll containers are assembled from the exact `ImageObjectDB`
|
|
head, hair, upper/lower body, hands, feet, and equipment rows requested by
|
|
combat templates. Each distinct image ID receives a namespaced GLB and
|
|
provenance entry. Unsupported or genuinely triangle-free displays remain
|
|
explicit proxy/pose-only exceptions instead of being labelled native.
|
|
- Ystra Zone 109 packages all three authoritative placements of its repeated
|
|
boss-room ROS and clones the exact room navmesh for each placement.
|
|
- Sand Vortex has props but no terrain ROS, so its arena is derived from WDB
|
|
bounds. Six modular/primary-collision maps add source-anchor support pads to
|
|
preserve entrance and combat coordinates; full secondary WDB placement
|
|
assembly remains a visible review item.
|
|
|
|
Only an explicit refresh requires SQL. Start the extraction-only instance, then:
|
|
|
|
```powershell
|
|
npm run runewaker:refresh:all
|
|
npm run runewaker:paperdolls:refresh
|
|
```
|
|
|
|
The first command restores both backups once, sets them read-only, exports all
|
|
zones, drops the temporary databases, and runs `prepare-all`. The paperdoll
|
|
refresh independently restores `ObjectEdit.bak` read-only, exports only the
|
|
requested appearance rows, and drops its temporary database. Stop
|
|
`MSSQL$HEALERMAN_RW` afterward. The game and all normal build commands consume
|
|
packaged files only.
|
|
|
|
## Importing another instance
|
|
|
|
### 1. Discover the source catalog
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs discover
|
|
```
|
|
|
|
The command writes `runewaker-export-work/instance-catalog.json`. The catalog
|
|
currently sees 30 server-configured dungeons and more than 60 dungeon WDBs. A
|
|
name match is only a candidate. Internal client names often differ from the
|
|
display/server name (Forsaken Abbey is `dgn_forlorn_monastary.wdb`). Add verified
|
|
exceptions to `discovery-overrides.json`.
|
|
|
|
### 2. Scaffold recipes
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs scaffold --id <dungeon_config_id>
|
|
```
|
|
|
|
If the WDB match is ambiguous:
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs scaffold --id <id> --wdb <file.wdb>
|
|
```
|
|
|
|
The scaffolder runs the preserved WDB reader and ranks ROS resources. It chooses
|
|
the primary environment automatically only when a `model/dungeon` ROS clearly
|
|
dominates the next candidate. Otherwise it stops and asks for an explicit:
|
|
|
|
```powershell
|
|
--model model/dungeon/.../environment.ros
|
|
```
|
|
|
|
It also searches configured Lua files for authoritative X/Y/Z/DIR constants.
|
|
If none are found, `entryCoordinates.reviewRequired` remains true.
|
|
|
|
The scaffold is not a playable dungeon. All templates begin as `unclassified`
|
|
until their SQL/template evidence is recovered and reviewed.
|
|
|
|
### 3. Inspect the WDB separately when needed
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs inspect-wdb --wdb <file.wdb> --slug <slug>
|
|
```
|
|
|
|
Review `runewaker-export-work/<slug>/inspection/wdb-environment-candidates.json`.
|
|
Check model path, bounds, placement count, scale, and a visual export. Largest
|
|
bounds are a useful signal, not proof.
|
|
|
|
### 4. Perform the one-time forensic population refresh
|
|
|
|
Start the isolated `HEALERMAN_RW` development instance, then run:
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs refresh `
|
|
--recipe scripts/runewaker-pipeline/recipes/<slug>-population.json `
|
|
--update-recipe
|
|
```
|
|
|
|
`--update-recipe` pins the observed row/boss counts and fills initial template
|
|
and actor candidates from authoritative fields:
|
|
|
|
- `NPCData`: spawn DBID, template ID, room, position, direction, AutoPlot data;
|
|
- `NPCObjectDB`: level, boss crown (`sex=3`), image ID, spells, Lua events;
|
|
- `ImageObjectDB`: actor model (`actworld`);
|
|
- `StringDB`: localized name.
|
|
|
|
The automatic classification is conservative:
|
|
|
|
- `sex=3` plus a positive-level `model/character` display -> boss;
|
|
- `sex=3` on an FX, door, or other non-character model -> deferred mechanics
|
|
object (the source uses the same crown flag on scripted controllers);
|
|
- positive level plus `model/character/...` -> combat candidate;
|
|
- level-zero or object-model rows -> deferred object candidate;
|
|
- missing/ambiguous evidence -> unclassified and blocked.
|
|
|
|
Review every changed template. A configured `boss_guid` is not authoritative by
|
|
itself: Forsaken Abbey's old configuration included a normal zombie and a chest,
|
|
while the original data identified different keeper/boss rows. Likewise,
|
|
`NPCObjectDB.sex=3` alone is insufficient: the all-dungeon audit found six
|
|
invisible soul-ball controllers and two dungeon doors that had been incorrectly
|
|
promoted to boss objectives before the model-family gate was added.
|
|
|
|
After refresh, stop SQL Server. All remaining steps must succeed while stopped.
|
|
|
|
### 5. Build and review the environment
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs environment `
|
|
--recipe scripts/runewaker-pipeline/recipes/<slug>.json
|
|
```
|
|
|
|
Review:
|
|
|
|
- `<slug>-preview.png` for orientation, missing materials, scale, and obvious gaps;
|
|
- visual GLB material/blending behavior;
|
|
- collision chunks for decorative blockers;
|
|
- Recast report and entrance projection;
|
|
- WDB anchor in `import-metadata.json`;
|
|
- Khronos validation output.
|
|
|
|
Secondary WDB doodads/effects remain audited. Repeated primary room placements
|
|
and documented source-coordinate support/fallback geometry are automated; a
|
|
complete arbitrary multi-ROS WDB scene still requires explicit placement,
|
|
material, collision, and performance review.
|
|
|
|
### 6. Review and build creature actors
|
|
|
|
In the population recipe, confirm every combat/boss template maps to the correct
|
|
unique actor model. Deduplicate actors by source ROS; templates can share one GLB.
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs actors `
|
|
--recipe scripts/runewaker-pipeline/recipes/<slug>-population.json
|
|
```
|
|
|
|
The shipping contract is GLB under `public/assets/creatures/<slug>`. Actor pivots,
|
|
ground offsets, scale, label height, material reuse, and orientation must be
|
|
reviewed. A direct actor is labelled native only when its source graph, sampled
|
|
clips, skin, manifest, runtime binding, and validated GLB all agree. Paperdoll
|
|
actors additionally require an exact image-specific row in
|
|
`snapshots/runewaker-paperdoll-appearances.json`; normal actor/population builds
|
|
never query SQL.
|
|
|
|
Structural validation is necessary but not a visual animation test. After any
|
|
native exporter, skeleton-selection, coordinate-basis, or rig-injection change,
|
|
render representative uncompressed `<actor>.animated.raw.glb` files with
|
|
`blender/render-animated-actor.py`. Review the bind pose and the first, middle,
|
|
and last frames of the exact idle, run, attack/cast, wound, and death clips used
|
|
by the runtime. This gate caught the Pasper goatman quaternion-basis bug even
|
|
though the affected files had valid skins, finite tracks, complete clip families,
|
|
and zero Khronos warnings. The derivation and an executable example are in
|
|
`ORIGINAL_ANIMATION_IMPORT.md`.
|
|
|
|
The source renderer can layer runtime colors through component masks. The
|
|
appearance snapshot records those layers and `requiresColorLayerBake` in
|
|
provenance. Until a corresponding color-mask bake is implemented and visually
|
|
checked, retaining the resolved base texture is an explicit color-fidelity
|
|
limit, not a reason to downgrade a valid skeleton or animation set.
|
|
|
|
### 7. Generate the offline population
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs population `
|
|
--recipe scripts/runewaker-pipeline/recipes/<slug>-population.json
|
|
```
|
|
|
|
This command reads only the portable snapshot, environment metadata/navmesh,
|
|
actor manifest, and recipe. It emits:
|
|
|
|
- `PopulationDefinitionMap` entities;
|
|
- namespaced static spawn IDs;
|
|
- spawn-specific boss objectives;
|
|
- source-to-local and navmesh-projection records;
|
|
- portable provenance and accounting reports.
|
|
|
|
RuneWaker numeric IDs are never assigned to AzerothCore `serverEntry`.
|
|
|
|
Use recipe `attacks` for reviewed data-driven abilities. The generator also
|
|
joins template spell assignments to the portable source catalog and emits only
|
|
positively classified direct-HP-damage families. Buffs, heals, summons, plot
|
|
hooks, crowd-control-only rows, and unknown effects remain evidence-only; they
|
|
must never become executable attacks by inference. When no reviewed/source-safe
|
|
attack exists, the generator uses HealerMan's basic combat fallback. Boss health/damage,
|
|
leash, speed, spawn masks, visual scale, and repeated-objective names can be
|
|
overridden per template. For example:
|
|
|
|
```json
|
|
{
|
|
"id": 100070,
|
|
"classification": "boss",
|
|
"objectiveNamePattern": "Necromage Keeper {index}",
|
|
"attacks": [
|
|
{
|
|
"id": "rw-fa-shadow-bolt",
|
|
"name": "Shadow Bolt",
|
|
"delivery": "projectile",
|
|
"target": "primary",
|
|
"school": "shadow",
|
|
"animation": "cast",
|
|
"range": 18,
|
|
"cooldownMs": 4200,
|
|
"damageMultiplier": 1.08
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 8. Extract and implement mechanics
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs mechanics `
|
|
--recipe scripts/runewaker-pipeline/recipes/<slug>-population.json
|
|
```
|
|
|
|
The mechanics stage hashes and scans configured Lua files, template event
|
|
scripts, spell IDs, AutoPlot/PlotClass values, boss positions, and spawn rows.
|
|
It groups evidence into summons, doors, timers, movement, spells, death hooks,
|
|
phases, interactions, and loot.
|
|
|
|
It intentionally generates evidence, not executable guesses. Review the audit
|
|
and map mechanics into HealerMan's existing data/runtime boundaries:
|
|
|
|
- spells and timed boss actions -> reviewed attack definitions;
|
|
- summons/waves -> encounter-owned spawned entities with reset cleanup;
|
|
- doors/gates -> explicit encounter state plus collision/navigation behavior;
|
|
- patrols/AutoPlot -> navmesh-projected paths;
|
|
- phases/death hooks -> a tested simulation state machine outside React render;
|
|
- chests/interactions/loot -> noncombat object state and packaged loot data.
|
|
|
|
Simulation state stays outside React scene components. R3F components render
|
|
the current world state; they are not the encounter-rule source of truth.
|
|
|
|
Each mechanic must specify trigger, targets, timing, reset behavior, persistence,
|
|
offline behavior, and multiplayer synchronization boundary before being marked
|
|
implemented.
|
|
|
|
### 9. Register the dungeon
|
|
|
|
Use the generated environment metadata and population constants to create the
|
|
reviewed `DungeonDefinition`. Keep environment, population, and encounter state
|
|
as separate concerns. Add the definition to the dungeon catalog only after:
|
|
|
|
- entry and bounds are correct;
|
|
- every runtime spawn has a unique ID;
|
|
- boss/objective order is reviewed;
|
|
- all asset URLs resolve offline;
|
|
- validation status is green (or warnings are explicit and acceptable).
|
|
|
|
### 10. Validate offline
|
|
|
|
```powershell
|
|
node scripts/runewaker-pipeline/cli.mjs offline `
|
|
--recipe scripts/runewaker-pipeline/recipes/<slug>-population.json
|
|
|
|
node scripts/runewaker-pipeline/cli.mjs validate `
|
|
--recipe scripts/runewaker-pipeline/recipes/<slug>-population.json
|
|
|
|
npm test
|
|
npm run build
|
|
```
|
|
|
|
Stop SQL Server and disconnect the network before the final browser test. Verify
|
|
environment, all actor models, clustering, aggro, combat, healing, deaths/reset,
|
|
objective progress, doors/summons/phases, party routing, asset 404s, console
|
|
errors, WebGL errors, and mobile/desktop performance.
|
|
|
|
## Outputs and provenance
|
|
|
|
| Output | Purpose |
|
|
| --- | --- |
|
|
| `runewaker-export-work/instance-catalog.json` | Discovery inventory. |
|
|
| `runewaker-export-work/<slug>/inspection/*` | WDB candidates and raw report. |
|
|
| `scripts/runewaker-pipeline/recipes/*.json` | Reviewed import contracts. |
|
|
| `scripts/runewaker-pipeline/snapshots/*.json` | Portable, hashed spawn/template evidence. |
|
|
| `src/assets/game/dungeons/<slug>/*` | Environment, collision, navigation, reports. |
|
|
| `public/assets/creatures/<slug>/*` | Browser-shipping actor GLBs/manifest. |
|
|
| `src/game/generated/*Population.generated.ts` | Runtime entities/spawns/objectives. |
|
|
| `src/game/generated/*Mechanics.generated.ts` | Non-executable mechanics evidence summary. |
|
|
|
|
Generated runtime data must be reproducible from recipes plus portable snapshots
|
|
without SQL or network access.
|
|
|
|
## Common failure modes
|
|
|
|
- Choosing a large prop instead of the primary environment ROS.
|
|
- Applying the axis/scale conversion before removing the WDB placement.
|
|
- Accepting a spawn far from navigation without understanding why.
|
|
- Treating all level-zero rows as disposable; many are doors or script triggers.
|
|
- Treating `dungeon_config.boss_guids` as authoritative classification.
|
|
- Passing RuneWaker IDs into AzerothCore `serverEntry`.
|
|
- Shipping raw OBJ/DDS/ROS or unvalidated DCC exports.
|
|
- Letting React components own encounter simulation state.
|
|
- Translating Lua by keyword alone and silently changing timing/reset semantics.
|
|
- Leaving SQL, backup paths, or source-root reads in runtime code.
|
|
|
|
## Current deliberate limits
|
|
|
|
The generic scripts automate source discovery, primary environment conversion,
|
|
portable population recovery, direct GR2 actor conversion, exact paperdoll
|
|
assembly, source-safe direct-damage attacks, spawn generation, repeated-room
|
|
assembly, source-anchor navigation, mechanics evidence extraction, runtime
|
|
registration, and validation. They do not pretend that arbitrary Lua/AutoPlot
|
|
code can be safely translated without review. Disconnected navmesh islands,
|
|
doors, phases, summons, patrols, timers, interactions, loot semantics, arbitrary
|
|
multi-ROS placement assembly, source-exact damage formulas, and multiplayer
|
|
encounter synchronization remain explicit per-instance engineering work until
|
|
implemented and playtested.
|