docs+tool: locate & extract world factory production-line recipes
The fixed single-recipe world structures (conveyors, e.g. 1 Raw Aurogen Crystal -> 10 Energy Rods) are a separate mechanic from workbench recipes. Document where they live and how to read them, with a reproducible extractor. - docs/PRODUCTION_LINES.md: the 'where to find it' record — ECS classes (ProductionLineRecipeComponent -> CraftingRecipe), the epb_assets_all game_conveyor_*_epb prefabs, EntityBlueprint/Odin serialization, the extraction path, and the open energy_grid_*/island-placement lead. - bundle/extract_production_lines.py: UnityPy + odin_read extractor -> extracted/production_lines.json (14 conveyor recipes). - BUNDLES.md: add production_lines.json to the data-source map.
This commit is contained in:
70
docs/PRODUCTION_LINES.md
Normal file
70
docs/PRODUCTION_LINES.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# World factory "production lines" (conveyors) — where to find them
|
||||
|
||||
The game has **fixed single-recipe world structures** — item conveyors that run *one*
|
||||
recipe (e.g. **1 Raw Aurogen Crystal → 10 Energy Rods**). These are a separate mechanic
|
||||
from the player **workbench** recipes (which live in `extracted/crafting_recipes.json`,
|
||||
sourced from `CraftingRecipeBundle` assets). This note records **where they live** so the
|
||||
data can be re-derived after a game update.
|
||||
|
||||
## The mechanic
|
||||
|
||||
In code it's a *"Factory Production Line"*. It's an Entitas ECS feature, namespace
|
||||
`Hologryph.Sand.Shared.Game.Features.Crafting` (see `il2cpp/dump.cs`):
|
||||
|
||||
| Class | Holds |
|
||||
|---|---|
|
||||
| `ProductionLineComponent` | `int inputEntityIndex`, `int outputEntityIndex` |
|
||||
| `ProductionLineRecipeComponent` | `CraftingRecipe recipe` ← the recipe |
|
||||
| `ProductionLineInputDataComponent` / `…OutputDataComponent` | `bool isLargeItem{Input,Output}` |
|
||||
| `CraftingRecipe` | `CraftingIngredient[] inputIngredients`, `CraftingIngredient[] outputIngredients`, `float craftingTimeSeconds` |
|
||||
| `CraftingIngredient` | `string itemId`, `int amount` |
|
||||
|
||||
Note `CraftingRecipe` / `CraftingIngredient` are the **same types** the workbench uses —
|
||||
only the container differs (a workbench holds `List<CraftingRecipeBundle> recipeBundles`;
|
||||
a production line holds a single `CraftingRecipe` on the entity).
|
||||
|
||||
## Where the data lives
|
||||
|
||||
- **Bundle:** `epb_assets_all.bundle` (reachable via the `bundles/` symlink).
|
||||
- **Prefabs:** `game_conveyor_*_epb.prefab`, under
|
||||
`Assets/Content/Game/game_conveyor/...`. 14 carry a real recipe; the
|
||||
`game_conveyor_base*` ones are template/test conversions (cf. `TestRecipesBundle`).
|
||||
- **Serialization:** each prefab GameObject (`m_Name = game_conveyor_<x>_epb`) has two
|
||||
components — a `Transform` and a `MonoBehaviour` whose script is **`EntityBlueprint`**.
|
||||
`EntityBlueprint : SerializedMonoBehaviour` (Sirenix Odin), so the component data —
|
||||
including the `CraftingRecipe` — is in its **Odin-serialized
|
||||
`serializationData.SerializedBytes`**, not in plain typetree fields. (Same situation as
|
||||
the loot tables — see [TASK.md](TASK.md) / `extract_loot.py`.)
|
||||
|
||||
### Extraction path (how to read it)
|
||||
|
||||
`UnityPy` (with an IL2CPP `TypeTreeGenerator` over `GameAssembly.dll` +
|
||||
`global-metadata.dat`) reads the `EntityBlueprint` MonoBehaviour → pull
|
||||
`serializationData.SerializedBytes` → `bundle/odin_read.py` parses the Odin binary →
|
||||
walk the tree for the node with `inputIngredients` / `outputIngredients`.
|
||||
|
||||
```bash
|
||||
venv/bin/python bundle/extract_production_lines.py # -> extracted/production_lines.json
|
||||
```
|
||||
|
||||
Key item ids seen here: `item_crystalHandles` = *Raw Aurogen Crystal*,
|
||||
`item_energyBar` = *NZ Mk2 Energy Rod*, `item_blackBox` = *Black Box*,
|
||||
`item_resourceCoralPiece` = *Coral Chunk*. Resolve any id → display name via
|
||||
`extracted/items_registry.json` / `extracted/item_names.json` (built from
|
||||
`CheatItemDefinitionsData`).
|
||||
|
||||
## Island placement — open lead
|
||||
|
||||
Which factory/island runs which conveyor is grouped by the
|
||||
`energy_grid_*_epb.prefab` blueprints in the same bundle:
|
||||
`Wunderinsel`, `Kaiserplatz`, `DeusExMachine`, `Factorio`, `LittleFactory1-3`,
|
||||
`LittleFactoryArmory1-3`, `TestFactory`. The **`…Armory`** groups are the likely
|
||||
**Sprengstofffabrik** (explosives factory) host for the explosive / grenade / rocket /
|
||||
cannon conveyors.
|
||||
|
||||
**Not yet resolved:** an `energy_grid_*` blueprint's Odin data references its conveyors by
|
||||
**entity reference, not item-id string** (a string scan of its serialized bytes finds no
|
||||
`game_conveyor_*` / `item_*` ids). So mapping recipe → specific island needs the **island
|
||||
prefab placements** in `islands_assets_all.bundle` (the `island_*` / fort / `loc_event_*`
|
||||
prefabs, where `Sprengstofffabrik` is an i2 `Toponyms/` name), not the conveyor or
|
||||
energy_grid EPBs alone. That linkage is the next step if island attribution is wanted.
|
||||
Reference in New Issue
Block a user