Rendered from reconstruction/REIMPLEMENTATION-PLAN.md

OpenZT2 Reimplementation Plan

ORIGINAL-GAME-FUNCTIONAL-SPECIFICATION.md describes the original game domain: the source-owned files, native managers, object types, message contracts, state transitions, and behaviours the reconstruction must preserve. This document describes the engineering shape of the Rust runtime: how those contracts should be stored, loaded, indexed, simulated, and presented efficiently in a modern Bevy engine.

The specification answers "what did Zoo Tycoon 2 mean and require?" This file answers "how do we execute those same meanings without building a slow facade over a 2008 single-threaded C++ heap model?"

The reconstruction must remain backwards-compatible with the original source formats: Z2F archives, XML/MAXML/BFXML documents, localization files, materials, models, textures, audio, saves, and packages. It does not need to preserve the original C++ memory layout, allocator behaviour, STL container choices, pointer graph, vtable mechanics, or duplicate transient trees unless one of those mechanics is part of an observable or persisted contract.

Implementation Completion Tracker

This tracker is a work board for the Rust overhaul, with status assigned from the accepted functional specification, live Rust modules/loaders/systems, and the classified binary perimeter. It tracks current evidence state rather than percentage complete. A recorded row means Rust has records for a source/domain surface; source hydration and runtime execution are stated only when the capability cell names them. A row is ready for assignment when its Unlock cell names the first concrete source file family, handler group, binary contract, or runtime path to inspect or implement.

Badge meanings:

Badge Meaning
done Finite evidence/register surface is exhausted enough to depend on it.
runs The Rust/Bevy executable has a live path for this capability.
loaded Source data or file format parses/hydrates into Rust values.
recorded Rust records fields, types, messages, or state shapes for the original surface.
recover Source/binary/formula behavior must be recovered before implementation.
map Known product area lacks a focused Rust owner or source inventory.
adapter Original middleware mechanics are replaced behind the original contracts.

Source And Evidence

Work package State Capability now Missing product behavior Unlock
Native class/type roster done 2,068 registered native types and parent edges are documented. Runtime factories and type-specific handlers still need per-domain attachment. Use the roster as the closed list for type handles and factory dispatch.
Message token registry done 1,084 registered message/event tokens are grouped by family. Most token handler bodies remain open. Attach tokens to the feature row whose manager owns the side effect.
Binary perimeter classification done 18,853 of 19,145 entries carry a name, type role, middleware provenance, vtable role, or inferred domain. 8,156 ZT/BlueFang entries have inferred area without exact behavior names; 292 entries stay opaque. Pick frontier functions only from a product row below.
Z2F archive mount and asset paths runs content::z2f, content::path, and Bevy SourceArchivePlugin mount shipped archives and serve bytes. Archive-backed loading is incomplete for every asset class. Convert remaining extraction/temp reads into Bevy asset-source reads.
XML/BFXML/MAXML parsing runs content::data parses documents; startup hydration reads UI, config, and runtime documents. Schema validation, include resolution, and original DOM write order are open. Implement BFXMLSchemaMgr validation and source-location preserving storage.
BFTypedBinder source objects loaded Binder identity, type/version keys, component refs, shared/instance documents, and event nodes are represented. Precedence, versionReplace, repopulateMethod, and by-name/by-type/by-kind lookup are unrecovered. Recover binder readers and lookup callsites before adding gameplay consumers.
Shared entity-data maps recorded BFAIEntityDataShared maps b_*, s_*, f_*, and p_* property families. Descriptor-table fields per component family are incomplete. Enumerate descriptors from native readers and representative entity XML.
Model source formats loaded content::model parses BFB and substantial NetImmerse/NIF block families. Full animation, skin, texture, and render binding semantics are incomplete. Promote parsed blocks into Bevy mesh/material/animation assets.
Material, texture, sound, and package formats recover Asset loader entry points and some texture helpers exist. .bfmat/.fx, sound tags, package variants, and .z2s layout are open. Recover one file family at a time from shipped assets plus native load callsites.

App, UI, Menus, And Modes

Work package State Capability now Missing product behavior Unlock
Bevy shell boot runs openzt2_shell, launch, task pools, archive registration, plugins, window setup, and startup loading run. Original ZT2Client/BFApp manager order is represented with many startup todo!() points. Replace startup placeholders with recovered app/bootstrap order.
Startup document hydration runs Startup reads UI, template, catalog, runtime-support, shell-mode, and presentation source documents. Hydration still publishes several aggregate resources and lacks original listener order. Shrink startup resources into Bevy-owned runtime resources and recover load listeners.
Authored UI tree projection runs UiDocument, skins, nodes, widgets, localization, and Bevy UI projection render source layouts. Many widget subclasses lack native behavior parity. Work widget family by family: list box, slider, drag/drop, text edit, tooltip, graph, window.
UI messages and value handlers recorded BFMessageBus, typed UI payloads, value-handler registry, hotkeys, timed events, and named routes exist. Most UI_* and ZT_* handlers lack recovered side effects. Pick one panel, list its emitted tokens, then implement handlers owned by the target manager.
Widget hit-test, focus, edit, sound, animation recover Widget fields and runtime state exist. Native hit-test, focus routing, edit validation, sound binding, font metrics, text wrap, and show/hide timing are open. Recover UI_HIT_TEST, UI_MODIFY, UI_QUERY, UISoundMgr, and font/text callsites.
Main menu and title flow runs Source-driven menu layouts can reach Bevy projection and shell mode state. Title/splash/profile/campaign transitions still need original message-order semantics. Trace ZT_SPLASH_CLOSED, ZT_SETMODE, ZT_LOADGAME, and main-menu event blocks.
Profile selection and user options recorded BFUserProfileMgr, profile commands, options records, graphics/audio/Vince fields, and safe graphics state exist. Read/write order, profile directories, registry mapping, and safe-mode restore are open. Recover profile/options XML readers and write-back paths.
Campaign, scenario, map-selection panels recorded Campaign index, globe dots, map data, movie list, populated menu lists, and cached map data exist. UI population handlers and scenario launch effects are incomplete. Read the authored menu layouts and implement ZT_POPULATE_*, ZT_CACHE_MAPDATA, and selection messages.
File/load/save modes recorded File mode state, file rows, load/save requests, screenshots, and alerts exist. Directory enumeration, delete/preview, screenshot capture, and .z2s read/write are open. Recover ZTFileMode handlers and the save package format.
Download, web, MOTD, EULA, diagnostics adapter Commands and state exist for downloads, MOTD, EULA, CD check, DxDiag, logging consent, and Vince telemetry. Host integration and event completion semantics are open. Map user-visible effects onto modern OS/network APIs and keep original message contracts.
Options and graphics mode recorded Graphics/audio/Vince snapshot, sliders, selected settings, float messages, and acceptance records exist. Confirmation, safe restore, slider binding, and persistence are incomplete. Recover ZTGfxOptionsMode value handlers and profile writes.
General mode manager recorded ZTModeMgr, mode records, hotkeys, event blocks, shell mode catalogue, stack, and requests exist. Per-mode input/tick/message handlers are mostly pending. Choose one mode row below and recover its vtable/message body.
Selection, delete, overview, guest-view modes recorded State records cover selection cursors, delete groups, overview filters/icons, and guest-view camera binding. Entity queries, confirmations, map projection, highlighting, and commands are incomplete. Implement one mode against live ECS entity state.
First-person, training, fossil, cloning, tranquilize modes recorded Mode state covers camera, training result feedback, gesture traces, fossil sonar, cloning score, and tranquilize target/range. Reward buckets, pointer math, target selection, and completion effects are open. Recover the relevant ZT_ENTER_*, ZT_FP_*, gesture, and behavior handlers.

Entity, Animal, Guest, And World Systems

Work package State Capability now Missing product behavior Unlock
Entity/component catalog loaded Entity definitions, shared/instance data nodes, component refs, authored events, and binder subtree records exist. Full component schema, inheritance, component factory creation, and validation are incomplete. Recover component readers by binder family, starting with one animal and one scenery/building type.
Loaded-world ECS bootstrap runs Loaded-world records can queue Bevy projection/bootstrap resources and spawn source-derived entity components. Original spawn/despawn, component mutation order, and full ECS ownership are incomplete. Convert one BFGEntity instance path into Bevy components and systems.
Entity selection and info panels recorded Selection requests, info panels, action controls, needs/training/inventory/family/donation rows exist. Panels lack live data bindings and action side effects. Wire selected entity ECS components to panel value handlers.
Animal type definitions recorded Species, family, biome, endangerment, lifecycle, variant, habitat, adoption, release, crate, disease, conservation, and training records exist. Source hydration per species and live need/status updates are incomplete. Hydrate one species family from binder plus AI/entity data, then generalize.
Animal lifecycle and breeding recover Lifecycle and pregnancy records exist. Breeding, offspring selection, family tree effects, and status flag reads are open. Recover animal lifecycle callsites and component-to-status readers.
Species behavior slice recover AI task, behavior, locomotion, animation, sound, and animal state surfaces exist separately. No complete animal can think, choose tasks, move, animate, vocalize, and update needs end to end. Pick one family such as elephant; read its binder, AI .tsk/.beh, model/anim/sound refs, then implement a vertical behavior pack.
Guest needs, satisfaction, and movement map Guest surfaces are scattered through AI, donations, world queries, and status. A focused guest owner, need model, path goals, spending model, and group behavior are missing. Inventory guest registered classes, authored components, UI panels, and ZTAIGuestMgr handlers.
Guest viewing and donations recorded View memory, donation candidates, score factors, donation task state, and contribution history exist. Eligibility, scoring, pruning, and task dispatch are todo!() surfaces. Recover ZTBehViewAnimals, ZTBehViewEvent, and ZTAIGuestMgr donation callsites.
Terrain heightfield, biome, water recorded Terrain grid, biome definitions, mesh patches, water edits, brush state, and map config records exist. Grid units, file layouts, water/biome edit algorithms, and charges are open. Recover terrain document layout, BFTERRAIN_* messages, and edit command readers.
Terrain/world Bevy projection runs Bevy world/terrain plugins have runtime resources, dirty queues, bootstrap projection, camera source, and mesh task scaffolding. Projection is still a scaffold for authored world state. Feed recovered terrain/world data into Bevy mesh/material/entity projection.
Placement validation and transactions recover Placement commands, rule sets, cursor/preview, affordance, failure catalog, and result tokens exist. Footprint schema, slope/headroom/traversability/research/money order, commit side effects, and undo are open. Trace ZT_SETPLACEMENT*, ZT_PLACEOBJECT, BFG_PLACE_ENTITY, and validator result tokens.
Paths and elevated supports recorded Path/elevated path records, placement commands, validation, support state, and curb mode exist. Segment joins, height rules, support topology, traversability updates, and undo need recovery. Recover path placement mode and BFGElevatedSupportTracker behavior.
Fences, gates, and portals recorded Fence types, segments, gate undo, portal segments, topology events, and mode state exist. Placement geometry, rotation, health, sale/delete, and traversal effects are pending. Implement ZTFenceMode command decisions against placement grid.
Tanks and aquatic construction recorded Tank manager, topology, walls, gates, portals, supports, links, water volume, cleanliness, and commands exist. Height speeds, tank topology edits, animal containment, show-tank edges, and validation feedback are open. Recover ZTTankCommandReader, wall/floor/water messages, and tank-gate behavior.
Transport rides recorded Circuits, tracks, stations, vehicles, crossings, query set, tour recorder, and command records exist. Route generation, boarding, capacity, vehicle motion, circuit direction, and station limits are open. Recover ZTTransportationMgr and ZTBehVehicle*/transport route behaviors.
Ground-fit, collision, traversability, pathfinding recover Fitting surfaces, collision/traversability/pathfinder managers, changed-triangle queues, and configs exist. Contact math, open-area rules, path graph invalidation, and steering fan-out are open. Recover BFGTraversabilityMgr, BFGPathFinderMgr, and ground-fit component callsites.

AI, Staff, Shows, And Behavior

Work package State Capability now Missing product behavior Unlock
AI task template source loaded Startup reads .tsk/.beh documents into BFAITaskCatalog; template parsing and basic fixed-score selection exist. Full authored behavior scheduling, sibling component attachment, scoring, and side effects are incomplete. Hydrate one task document end to end and instantiate BFAITaskRoot.
AI scoring and thinker scheduler recover State/task thinker records, task runtime state, eval result, tokens, and manager records exist. Scoring, tie-break, ThinkerInterval, token lifetime, reserve conflicts, and completion/failure effects are open. Recover BFAITaskThinker, BFAIEvalData, and BFAICompletionData behavior.
Behavior verbs recorded BFBehavior base and many ZTBeh* records exist; many methods name exact todo!() contracts. Movement, docking, animation, events, scripts, use-gate, ride, tour, view, cure, dig, morph, and splash effects are pending. Pick one verb family and implement XML read plus runtime side effect.
Steering and locomotion recover Steering vectors, profiles, locomotion manager, traversal refs, and STEER_*/LOCO_* messages exist. Blend weights, arbitration order, obstacle/entity avoidance, and animation realization are open. Recover BFSteeringMgr, BFLocomotionMgr, and BFLocoAnimate callsites.
Staff jobs and assignment UI recorded Staff manager, request controller, job queue, role handles, candidates, assignments, time categories, trainer, and cleaning records exist. Request evaluation, job claiming/stealing, assignment targeting, water cleaning, and trainer behavior are pending. Implement ZT_STAFF_REQUEST, assignment selection, and one staff role lifecycle.
Shows and trick training recorded Show manager, scheduler, states, songs, score/size bands, effects, tricks, targets, mixer, timer, and UI commands exist. Timeslot choice, trick difficulty/popularity, animal eligibility, guest feedback, and show effects are open. Recover show scheduler and one trick execution path.
Tours and guest viewing recorded Tour taker data, recorder waypoints, viewable object managers, station view sets, and viewing behaviors exist. Tour star rating, route feedback, and view scoring are open. Recover ZTAITourTaskThinker, ZTBehTour, and tour star rating queries.
Gesture recognition and minigames recorded Gesture definitions, traces, recognizer, spline editor, projection frame, event textures, and score bands exist. Projection math, trace scoring, texture events, reward dispatch, and editor commands are open. Recover ZTGestureMgr and gesture trace component callsites.

Economy, Progression, Status, And Catalog UI

Work package State Capability now Missing product behavior Unlock
Cash and admission price loaded Startup hydrates economy/status configs; domain methods apply cash deltas, transaction polarity, and admission price/index values when called. Live UI/simulation transaction routing, commit history, and several status forwarding effects remain. Implement ZTTransaction aggregation and BFGTransactionTracker commit.
Economy components and cost factors recorded Economy components, context configs, transaction configs, cost factors, frequency/period/cost types, and user-count transactions exist. Authored component execution on live entities is pending. Hydrate economy config into ECS/domain components and execute one transaction category.
Donation boxes and guest spending recorded Donation totals, buckets, boxes, contribution history, guest donation state, and info-panel rows exist. Weighting, target choice, box routing, and spend timing are open. Recover edDonate, donation candidate scoring, and box contribution handlers.
Fame and zoo rating recover Fame status, fame history, message types, half-star value handlers, release/all-species values, and admission coupling exist. Half-star thresholds, fame sources, max fame, status update cadence, and award coupling are open. Recover ZTFameData update and value-handler callsites.
Research and unlocks recover Research manager, items and buttons, unlock refs, active/completed records, and ZT_RESEARCH_* tokens exist. Source schema, dependencies, timers, UI button state, and placement gating behavior are open. Read research config files and native ZTResearchMgr handlers.
Disease and cure mode recorded Disease manager, disease records, qualifiers, filters, cases, cure UI state, infection/cure requests, and clue records exist. Spread cadence, force application, sampling, cure scoring, rewards, and vet/staff interactions are open. Recover ZTDiseaseMgr::update, force_disease, and ZTCureDiseaseMode.
Adoption and release recover Adoption manager records, slots, animal adoption/release/crate states, and UI actions exist. Slot availability, rarity, decline/adopt/release side effects, and panel refresh are open. Recover ZTAdoptionMgr, ZTAdoptionSlotMgr, and adoption panel handlers.
Awards and status messages map Award records, status configs, feedback records, zoo messages, thoughts, emoticons, and survey records exist. Criteria, trigger timing, display routing, and persistence are thin. Inventory ZTAwardMgr, ZTStatus, ZTFeedbackMgr, and status UI tokens.
Zoopedia and catalog lists recorded Zoopedia TOC entries, pages, navigation, type lists, filters, buy info panel, and catalog entries exist. Page loading, list population, filters, loc/text rendering, and navigation handlers are incomplete. Implement one source-driven catalog panel from layout through value handlers.

Scenario, Scripts, Save, And Photos

Work package State Capability now Missing product behavior Unlock
Scenario rule tree recorded Rules, groups, tests, actions, objectives, challenge state, globals/user vars, and typed BFS commands exist. Evaluation order, trigger cadence, campaign graph, and objective progression are open. Recover BFScenarioMgr and ZTScenarioMgr rule evaluation.
Script context and BFS API recorded Script context manager, Lua context records, function bindings, script action records, effects, cache, args, and responses exist. Argument marshalling, return semantics, error handling, and every BFS_* side effect need implementation. Map BFS_* commands by family, then bind them to owning managers.
Lua runtime execution adapter Lua 5.0.2 is middleware evidence; Rust should provide a BFS-compatible script host. Runtime choice and compatibility layer are undecided. Embed a current Lua runtime and implement recovered call/return contracts.
Compiled scenario and VINCE payloads recover .bin, .lop, Vince, and telemetry command records exist. Binary object semantics and telemetry payloads are open. Decode compiled scenario assets and BFS_PROCESS_VINCE.
Save/load package format recover Save/load requests, loaded game/world/economy/entity contexts, alerts, screenshots, and package refs exist. .z2s container bytes, section order, versioning, and persisted member boundary are open. Recover .z2s container structure and per-component write_xml_node scope.
Profile/options persistence loaded Graphics/audio/profile/user-settings records and commands exist. Original profile directory resolution and write order are open. Implement BFUserProfileMgr file/registry path behavior.
Photo albums and camera recorded Photo manager, albums, capture requests/results, photo info, subject bounds, analysis context, and UI tokens exist. Capture, album file behavior, move/delete/enlarge/shrink, and HTML export are pending. Implement ZTPhotoManager against Bevy camera/render output.
Photo challenges recorded Challenge sets, score thresholds, parse trees, getters, abstractions, and results exist. Subject detection, scoring, challenge stars, and submission side effects are open. Recover ZTPA* getter bindings and photo analysis scoring.

Renderer, Audio, Camera, And Host Adapters

Work package State Capability now Missing product behavior Unlock
Gamebryo/NetImmerse and D3D backend adapter Middleware span and component inputs are known; Bevy owns modern render execution. Source-visible render semantics still need preservation. Replace backend internals while honoring BFSceneGraphComponent, BFAnim*, BFSpriteMgr, material, and texture contracts.
Bevy render bridge runs Renderer plugin, model projection cache, terrain mesh tasks, dirty queue, and mode visual effect asset exist. World/entity/material projection is thin. Feed source models/materials and ECS transforms into Bevy meshes/materials.
Scene graph and actor components recorded Scene graph, actor, camera, decal, LOD, resource cache, model manager, texture manager, and particle manager records exist. Live graph update, culling, bounds, attachment, and visibility rules are open. Implement one visible entity projection from BFSceneGraphComponent to Bevy.
Materials, effects, particles recover Material/effect/particle records, params, render states, selectors, emitters, and include managers exist. .bfmat/.fx syntax, animation tracks, shader constants, particle modifiers, and slot binding are open. Recover source parsers and bind them to Bevy material/effect assets.
Animation recover Animation graph, nodes, transitions, sequences, controllers, key data, and request records exist. Blend/transition rules, event timing, locomotion coupling, and Bevy mapping are open. Recover BFAnimController, BFAnimGraph, ANIM_*, and text-key callsites.
Camera recorded Camera command reader, active commands, command events, rail/follow cameras, frustum, output states, and Bevy window camera source exist. Curves, timing, first-person/overhead/guest-view coupling, and projection math are open. Implement ZT_CAMERA_* commands against Bevy camera state.
UI sprite/text rendering runs Source UI documents reach Bevy UI projection. Original sprite manager bitmap geometry, hitmasks, text buffer, font metrics, and rich text tags are incomplete. Recover BFSpriteMgr, BFUIRenderer, and BFUIText* behavior.
Audio playback and ambients recorded Sound manager, stages, categories, tags, ambient docs, water sound stages, requests, and commands exist. Real playback, 3D attachment, category mix, ducking, random/stage selection, and cross-fade timing are open. Implement BFSND_* through Bevy/audio backend and recover sound-tag selection.
Window, input, cursor, IME runs Bevy window/input plugins capture pointer, keyboard, focus, cursor projection, and window render config. Original IME, dialog, startup-window, and some cursor file semantics are open. Map BFWindowComponent, UIKeyboardEvent, UIMouseEvent, and IME records to host APIs.

Unknown Extent And Expansion Rule

Work package State Capability now Missing product behavior Unlock
Proven middleware/library surface adapter Binary perimeter marks 9,483 functions as proven middleware/library, including the large Gamebryo/NetImmerse renderer block and Lua 5.0.2. Adapter layers still need source-visible behavior parity. Implement replacement through Bevy, Lua host, archive readers, and audio/window/network adapters.
Classified ZT/BlueFang frontier recover 8,156 ZT/BlueFang functions have inferred functional area with no exact behavior name yet; 3,536 are high-confidence. Exact contracts remain absent for selected handlers/formulae. Pick a row above, inspect its functions/source assets, state the domain contract, then implement it.
Fully opaque tail recover 292 function entries remain opaque, mostly small leaf thunks plus tank/map geometry helpers and dispatchers. Their relevance is unknown until a product row points at them. Inspect only when a feature slice reaches one of these addresses.
Section-local other unknowns map Rows above cover the currently named work packages from the spec, Rust modules, and binary perimeter. Any registered class, function band, source file family, or manager outside these rows lacks a project owner. Add a row before implementing that evidence.
Tracker expansion rule done This board names current assignable rows. New source or binary recovery can reveal finer owners. Add a row when a distinct manager, source file family, state transition, formula, or adapter boundary appears.

Workspace Crate Boundaries

content owns source-file boundaries: shipped Z2F archive addressing, asset paths, XML/MAXML-like data documents, localization documents, parser support, and source references needed to recover where a value came from. Content code can parse, decode, normalize, and validate source documents; it does not own live game state or host projection state.

domain owns host-independent source-derived game concepts and original contracts: UI/document semantics, manager configuration, entity definitions, catalog values, rules, state transitions, command/event meaning, and invariants. Domain code receives loaded source documents and original-game messages, then returns values/results or mutates original-game state. It does not own Bevy resources, ECS entities, renderer buffers, mounted archives, asset caches, task pools, audio playback, or generic host registries.

Domain may define original-game semantic asset value types, tokens, validation rules, and pure transforms over loaded source data. It must not own the live loaded asset set: generic loaded-document collections, mounted archive mirrors, asset path indexes, Bevy handles, loader queues, or duplicate caches of Bevy asset values belong outside domain. Preserving an original ZT*, BF*, or BFG* symbol means naming the source/domain value type and its semantics. Runtime storage ownership still belongs at the boundary defined for that value.

bevy owns the executable runtime adapter: windowing, app lifecycle, task pools, mounted archive state, Bevy asset sources, asset extraction, resources, ECS entities/components, Bevy messages, input, rendering, audio playback, and projection of source/domain values into the live Bevy world.

Runtime Shape

The running game should use Bevy as the runtime world, scheduler, asset system, and presentation store. domain defines original semantic types, invariants, source-derived values, and mutation rules; bevy stores live state as Bevy resources/components and connects them to input, rendering, audio, assets, and schedules.

content
  Z2F/archive/path lookup
  source bytes
  BFXML/XML/MAXML parsed document assets

domain
  original semantic types and mutation rules:
    UI nodes/widgets/messages
    app lifecycle states
    managers
    modes
    entity/type records
    AI tasks
    terrain/world/camera concepts

bevy
  Bevy plugins, schedules, systems
  Bevy Assets for decoded source artifacts
  Resources/components containing domain types
  render/UI/audio/input adapters

StartupDomainResources publishes source-derived values during Bevy-adapter boot. Startup code may assemble values there, then immediately publish the result into Bevy resources/components without a second transfer bucket. The player-facing runtime should operate on the published resources directly.

Original singleton-like managers and runtime domains should live in coherent Bevy resources that match real runtime boundaries. Use one Bevy resource per old singleton only when that singleton is itself the recovered boundary:

ZTAppRuntime
ZTModeMgr
UiRuntimeContext
UiLayoutRegistry
BFGWorldRuntime
EconomyRuntime
BFLocaleMgr
EntityTypeRegistry
RendererRuntime
RuntimeSupport

Many-instance runtime objects should become Bevy entities/components carrying domain-defined state:

World entity:
  ZTEntityInstance
  EntityTypeRef
  BFPhysObj-derived transform/state
  AI runtime state
  mutable needs/disease/staff/etc. components as recovered
  render/audio/UI marker components where needed

The domain model remains intelligible outside Bevy because the types and handlers live in domain. The running storage is Bevy because Bevy is the engine's ECS, scheduler, change tracker, and asset-handle store.

Bevy Runtime Primitives

In the running executable, Bevy should provide the primary runtime substrate: storage, scheduling, change detection, asset handles, presentation, and host I/O. Original game contracts still live in domain types and handlers. Those types should be stored and executed through Bevy primitives where that improves locality, parallelism, and incremental updates.

App, Plugins, And World

App is the boot container. It wires plugins, resources, schedules, assets, states, diagnostics, windows, and render pipelines. OpenZT2 should use plugins as real subsystem boundaries:

SourceArchivePlugin
BfxmlPlugin
LocalizationPlugin
UiRuntimePlugin
ShellModePlugin
WorldRuntimePlugin
TerrainPlugin
RendererBridgePlugin
AudioPlugin
DiagnosticsPlugin

Each plugin should install the resources, components, systems, asset loaders, events/messages, and schedules for one original responsibility. Plugins register recovered domain meaning into the runtime.

World is Bevy's entity/resource storage. In the game executable, the Bevy world should hold the live runtime state directly. A separate domain graph that is copied into the world every frame is a performance smell. Headless tests may still create domain structures without Bevy. The player-facing runtime should treat World as the canonical mutable store for resources/components.

Entities, Components, Resources, And Bundles

Entities are ids for runtime instances. Animals, guests, staff, vehicles, placed objects, UI widgets, cameras, terrain chunks, effect emitters, and audio emitters can all be entities when they have independent lifetime or per-instance state.

Components are the runtime fields attached to those ids. Original concepts such as entity type references, component properties, AI task state, disease state, physics/object state, selection state, renderable model refs, and UI widget runtime state should be normal Bevy components when they are per-instance.

Resources are singleton or registry state. Original managers and global tables map naturally to resources: mode manager, world manager, status/economy manager, locale manager, archive repository, document store, UI layout registry, material registry, input focus state, and render configuration.

Use bundles as spawn/update ergonomics for coherent Bevy entities:

UiWidgetBundle
WorldEntityBundle
TerrainChunkBundle
CameraRigBundle
AudioEmitterBundle

The bundle should contain domain components and Bevy presentation components; it should not hide a second copy of the source record.

Systems, Queries, Commands, And Params

Systems are the runtime functions. Domain handlers should be called from systems that gather input from Bevy resources/components and write results back into Bevy storage.

Queries are how systems access entity sets. They are the right way to avoid linear scans of a giant session object:

Query<(&EntityTypeRef, &mut AiRuntimeState, &Transform), With<Animal>>
Query<(&UiSourceNode, &mut Visibility), Changed<UiWidgetRuntimeState>>
Query<(&TerrainChunkId, &mut MeshHandle), With<DirtyTerrainChunk>>

Commands are deferred structural mutations: spawning/despawning entities, adding/removing components, and inserting/removing resources. Use them for lifetime changes. Ordinary field updates should go through mutable queries/resources.

System params, including Res, ResMut, Query, EventReader, EventWriter, MessageReader, MessageWriter, Local, Commands, and ParamSet, are the way to make dependencies explicit. ParamSet is useful where an original handler needs mutually exclusive query shapes that Rust's borrow checker cannot otherwise express in one system.

Schedules, System Sets, Run Conditions, And States

Schedules should model execution phases. Product meaning belongs in domain state. Useful schedules/sets are:

StartupSourceMount
StartupDocumentHydration
InputCollection
DomainMessageDispatch
Simulation
PresentationSync
RenderPreparation
Diagnostics

System sets give stable ordering and parallelism boundaries inside those phases. Use them to separate source loading, message dispatch, simulation mutation, dirty projection, and diagnostics. Systems within a set should run in parallel when their data access permits it.

Run conditions are cheap gates. They should prevent inactive systems from touching irrelevant data:

run_if(in_shell_ui)
run_if(in_loaded_world)
run_if(resource_changed::<UiRuntimeContext>)
run_if(any_dirty_terrain_chunks)

Bevy states can control schedule activation such as Loading, ShellUi, and InGame3d. They must remain host scheduling state. Original app/mode state should remain explicit domain resources such as ZTAppRuntime, ZTModeMgr, or the recovered manager type.

Events, Messages, Observers, And Change Detection

Use Bevy events/messages for short-lived runtime facts:

OriginalUiProjectionCommandQueued
OriginalUiMessageQueued
TerrainRegionEdited
BFAudioCommandQueued

Original UI commands and game messages should be represented in domain terms, then transported through Bevy messages/events when the runtime needs decoupled delivery. Do not convert an original domain message into a Bevy-only callback that loses the original sender, target, payload, or ordering.

Observers are appropriate for local reactions to component or entity changes when they express host mechanics: attach a render child when a renderable component appears, start an animation when a UI visual state changes, or emit a diagnostic marker when a terrain chunk becomes dirty. They should not replace the original native message handlers.

Bevy change detection is central to performance. UI, terrain, world entities, materials, animation, audio, and cameras should update presentation only from Changed<T>, dirty sets, generation counters, or explicit messages. Avoid full-tree and full-world rebuilds.

Assets, Handles, Reflection, Scenes, And Serialization

Bevy assets should store decoded immutable artifacts: parsed BFXML documents, textures, sounds, models, materials, shader modules, scene fragments, and possibly compiled UI templates. Domain/runtime records should store ids or handles instead of copied payloads.

Handles are cheap references. They are the right representation for repeated texture/model/sound/material references across UI, entities, terrain, and effects.

Reflection and world serialization are developer/runtime tools. Use reflection for inspectors, diagnostics, and save/debug tooling where it helps. Keep the original source formats and type registries authoritative.

Scenes are useful for Bevy-native debug/test fixtures and imported GLTF content. Original Zoo Tycoon 2 layouts, entities, maps, and assets should still hydrate from their recovered source formats rather than being converted into Bevy scenes as the source of truth.

Tasks And Parallelism

The multi_threaded, async_executor, async-io, and task-pool surfaces are how expensive loading and hydration work should stop blocking the frame. Archive mounting, document parse, model/material decode, terrain chunk mesh generation, and thumbnail/icon preparation can run off the main thread, then report compact results back through messages or asset handles.

Parallel ECS systems should own normal frame work: AI ticks, animation state, dirty UI updates, terrain projection, audio command preparation, and visibility or culling data. The target is result compatibility with the original update loop, using Bevy's dependency graph to run independent work concurrently.

Bevy 0.19 Capability Map

This section treats the full Bevy 0.19 feature surface as the planning map, not just the subset currently enabled in bevy. Each feature family below should be considered when it improves either performance or fidelity to the original game. Feature flags are named explicitly so no major Bevy surface is lost in a vague "renderer" bucket.

Core Runtime And Platform

Relevant features:

default
default_app
std
default_no_std
default_platform
common_api
critical-section
libm
ff
multi_threaded
async_executor
async-io
bevy_app
bevy_ecs
bevy_tasks
bevy_time
bevy_state
bevy_transform
bevy_window
bevy_winit
wayland
x11
web
webgl2
webgpu
android-game-activity
android-native-activity
bevy_android
raw_vulkan_init
dynamic_linking
hotpatching

Use this surface for the engine frame loop, window/backend integration, task pools, app/schedule registration, time, transform propagation, and platform ports. Desktop OpenZT2 should prefer native Wayland/X11/wgpu paths. Web and Android remain portability targets for later work after the first faithful desktop reconstruction.

ECS, Scheduling, Reflection, Debug Storage

Relevant features:

bevy_ecs
bevy_ecs_macros
bevy_state
bevy_state_macros
schedule_data
bevy_reflect
bevy_reflect_derive
reflect_auto_register
reflect_auto_register_static
reflect_documentation
reflect_functions
bevy_world_serialization
serialize
track_location
type_label_buffers
debug
debug_glam_assert
glam_assert
detailed_trace
trace
trace_chrome
trace_tracy
trace_tracy_memory
bevy_debug_stepping

Use ECS/scheduling features for the canonical runtime layout. Use reflection and serialization for debugging, inspectors, automated validation, and save-tool helpers. Use tracing/debug stepping when investigating frame stalls, bad ordering, or runaway systems. Do not use reflection or serialized worlds as a replacement for original source formats.

Assets, File Watching, And External Formats

Relevant features:

bevy_asset
bevy_asset_macros
asset_processor
embedded_watcher
file_watcher
bevy_asset_loader
standard_dynamic_assets
progress_tracking
web_asset_cache
http
https
compressed_image_saver
zlib
zstd_c
zstd_rust

The target is a Z2F-backed asset path: mounted archives feed Bevy asset readers and loaders lazily. File watchers and the asset processor are useful for development rebuilds and generated/debug assets. Web cache and HTTP(S) are secondary surfaces. Compression features matter for archived payloads and future save/package handling.

Images And Texture Containers

Relevant features:

bevy_image
png
jpeg
tga
dds
ktx2
basis-universal
bmp
gif
hdr
exr
ico
pnm
qoi
tiff
webp
zlib
zstd_c
zstd_rust

Use Bevy image assets and GPU texture upload for UI skins, icons, terrain textures, decals, sky/lighting resources, particles, and model materials. Original texture references should hydrate to asset ids/handles; image bytes should not be copied into domain records. DDS/KTX2/Basis are important for GPU friendly compressed paths if original or converted assets justify them.

Audio

Relevant features:

audio
audio-all-formats
bevy_audio
wav
vorbis
flac
mp3
mp4
aac
symphonia-wav
symphonia-vorbis
symphonia-flac

Use Bevy audio for playback, handles, sinks, volume, looping, and eventually spatial attachment to world entities. Domain managers should produce original audio commands; Bevy owns the concrete sink/player state. WAV is currently closest to the shipped audio path, while broader formats remain available for tooling or later asset compatibility.

Input, Focus, Picking, And Interaction

Relevant features:

bevy_input
keyboard
mouse
touch
gestures
gamepad
bevy_gilrs
bevy_input_focus
bevy_picking
picking
mesh_picking
sprite_picking
ui_picking
bevy_clipboard
system_clipboard
clipboard_image
custom_cursor

Input systems should translate host events into original UI/game commands. Picking should replace ad hoc screen-coordinate scans for UI and world selection while preserving the original target/message semantics. Mesh picking is central for terrain/object placement, entity selection, and camera/world queries. Input focus is important for UI modal behaviour. Clipboard/gamepad are optional surfaces until an original behaviour requires them or they improve debug tooling.

UI, Text, Fonts, And Accessibility

Relevant features:

ui
ui_api
ui_bevy_render
bevy_ui
bevy_ui_render
bevy_ui_widgets
bevy_ui_debug
bevy_feathers
ghost_nodes
bevy_text
default_font
system_font_discovery
bevy_a11y
accesskit_unix

Use Bevy UI as the presentation and interaction backend for original UI documents. The authored UI layout remains the source contract. Bevy entities carry source node ids, visual state, text/image handles, layout components, focus/picking components, and dirty markers. Text/font handling must preserve the original font selection, localization, sizing, alignment, and color semantics. Default/system fonts only cover fallback and development use while original fonts are available.

2D Sprites, Atlases, Tiles, And UI Imagery

Relevant features:

2d
2d_api
2d_bevy_render
bevy_sprite
bevy_sprite_render
sprite_picking
bevy_color

Use 2D rendering for UI art, cursors, overlays, icons, previews, debug maps, and possibly tile-like minimap or editor layers. Sprite picking helps pointer dispatch. Atlas-style batching should be considered for UI skins and icon sets so the menu/frontend does not become thousands of independent texture binds.

3D Rendering, Meshes, Materials, And Models

Relevant features:

3d
3d_api
3d_bevy_render
bevy_render
bevy_core_pipeline
bevy_mesh
bevy_material
bevy_material_macros
bevy_shader
bevy_pbr
bevy_mikktspace
bevy_gltf
gltf_animation
scene
bevy_scene
bevy_scene_macros
bevy_world_serialization

Use Bevy mesh/material/render assets for terrain, water, paths, fences, animals, guests, buildings, vegetation, particles, and placement previews. Original BFB, NIF, BFMat, texture, and animation formats should hydrate through source/domain loaders into Bevy mesh/material/animation assets. GLTF scenes are useful for developer fixtures or converted inspection assets. Original files remain the canonical source.

Terrain Editing And Mesh Mutation

Relevant features:

bevy_mesh
bevy_render
bevy_pbr
mesh_picking
bevy_gizmos
bevy_gizmos_render

Terrain raise/lower/paint/flatten/path/fence placement should operate on domain terrain chunks and dirty regions, then update Bevy mesh assets for only the affected chunks. Mesh picking supplies brush hits and placement queries. Gizmos should visualize brush radius, selected cells, path/fence segments, surface normals, and dirty chunk boundaries during development.

Lighting, Shadows, Fog, Sky, And PBR

Relevant features:

bevy_light
bevy_pbr
area_light_luts
dfg_lut
bluenoise_texture
tonemapping_luts
pbr_anisotropy_texture
pbr_clustered_decals
pbr_light_textures
pbr_multi_layer_material_textures
pbr_specular_textures
pbr_transmission_textures
experimental_pbr_pcss
bevy_solari

Use these surfaces to approximate or surpass the original renderer while preserving visual intent: sun/ambient setup, time-of-day colour, shadows, terrain/object materials, decals, water/material effects, skybox/atmosphere presentation, and fog. The original renderer's material and lighting contracts must drive the inputs; Bevy can supply a modern implementation.

Post-Processing, Anti-Alias, Tone Mapping, Bloom, Blur, Color

Relevant features:

bevy_post_process
bevy_anti_alias
smaa_luts
tonemapping_luts
dlss
force_disable_dlss
hdr
bevy_color

Use post-processing to match the original game's visible output: gamma/color space, bloom-like effects, fog/color grading, anti-aliasing, and any screen effects recovered from renderer contracts. DLSS/HDR are optional modern capabilities; they must not change the default fidelity target unless exposed as explicit graphics options.

Shaders And GPU Pipeline Control

Relevant features:

bevy_shader
shader_format_glsl
shader_format_spirv
shader_format_wesl
spirv_shader_passthrough
statically-linked-dxc
raw_vulkan_init
meshlet
meshlet_processor

Use custom shaders for original-specific terrain blending, water, decals, foliage, UI effects, particle effects, and material features that standard PBR cannot represent. Meshlet features are a future optimization path for dense world geometry if profiling shows classic chunked meshes are insufficient.

Animation, Easing, Morphs, Timelines, And Effects

Relevant features:

bevy_animation
bevy_animation_macros
morph
morph_animation
gltf_animation
bevy_time

Use Bevy animation assets/systems for skeletal/model animation once original animation formats are mapped. Morph support is relevant for facial/body morphs or converted model data if the source assets require it. UI easing, tweening, and timeline behaviour can be implemented as domain/runtime components driven by Bevy time and systems; do not invent animation semantics that conflict with recovered UI or renderer handlers.

Cameras And Projection

Relevant features:

bevy_camera
bevy_camera_controller
free_camera
pan_camera
bevy_transform

Camera concepts and legal transitions should be domain-defined where they represent original game concepts: shell camera, world camera, panning, zooming, rotation, training/cinematic views, and selection focus. Bevy owns the live camera components/resources and implements the host view. Free/pan camera helpers are useful for development and may inform player controls only where they match recovered behaviour.

Devtools, Diagnostics, Gizmos, Remote, And Inspectors

Relevant features:

bevy_dev_tools
bevy_debug_stepping
bevy_diagnostic
sysinfo_plugin
bevy_gizmos
bevy_gizmos_render
bevy_remote
bevy_ui_debug
bevy_log
trace
trace_chrome
trace_tracy
trace_tracy_memory

Use diagnostics for frame time, asset loading, system cost, entity counts, terrain chunk rebuilds, UI dirty updates, draw-call pressure, memory use, and audio/asset queues. Gizmos should be standard for reconstruction debugging: camera frustums, placement grids, path/fence routes, terrain chunks, selection rays, AI targets, and nav/path queries. Keep remote/devtools in the development tooling surface.

Logging And Settings

Relevant features:

bevy_log
bevy_settings
sysinfo_plugin

Use logging for source loading failures, missing assets, contract mismatches, performance warnings, and validation diagnostics. Settings can back modern graphics/audio/input preferences only when mapped cleanly to original options or explicitly separated as host settings.

Windowing, Cursor, And Host Shell

Relevant features:

bevy_window
bevy_winit
custom_cursor
wayland
x11
web
webgl2
webgpu

Use Bevy windowing for fullscreen/windowed mode, resize handling, cursor projection, DPI handling, input capture, and platform backend selection. The original graphics options and startup/window behaviour define the domain contract; Bevy implements the host mechanics.

Scene, GLTF, Serialization, And Tooling Imports

Relevant features:

bevy_scene
scene
bevy_gltf
gltf_animation
bevy_world_serialization
serialize

Use scenes/GLTF for tooling, visual regression fixtures, converted inspection assets, or temporary developer views. The canonical game data path remains the original Z2F/source formats. World serialization can support debugging and test snapshots; original saves/packages remain their own compatibility surface.

Platform, CI, And Build-Time Features

Relevant features:

bevy_ci_testing
dev
dynamic_linking
hotpatching
embedded_watcher
file_watcher
asset_processor
reflect_documentation

Use these to speed development, CI, and introspection. Dynamic linking and hotpatching can shorten iteration but should not become assumptions in release behaviour. CI testing should exercise source loading, deterministic domain handlers, and representative Bevy app schedules without needing the full interactive shell for every check.

Source Documents

Source parsing should produce one compact representation of a document. The XML/BFXML model must preserve ordered mixed content and attributes while avoiding duplicate owned children, content, and text trees.

The near-term shape is:

pub struct DataNode {
    pub name: String,
    pub attributes: Vec<DataAttribute>,
    pub children: Vec<DataChild>,
}

pub enum DataChild {
    Element(DataNode),
    Text(String),
}

Convenience APIs can expose element_children() or text() views. They should not own a second recursive tree.

The fuller performance target is an arena/range representation:

struct BfxmlDocument {
    nodes: Vec<BfxmlNode>,
    children: Vec<BfxmlChild>,
    attrs: Vec<BfxmlAttr>,
    text: Vec<Arc<str>>,
}

Nodes refer to child and attribute ranges. That preserves source semantics, reduces allocation overhead, allows stable node ids, and gives UI/domain hydrators cheap references into the parsed document.

Asset Loading

The source-compatible path is:

ZT2 path -> mounted archive entry -> lazy bytes -> Bevy AssetLoader -> Handle<T>
domain-defined asset type -> Bevy AssetLoader -> Assets<T> -> Handle<T>

The runtime should avoid extracting every asset into a temp directory as the main architecture. A temporary extraction bridge may exist while loaders are being replaced. The final engine should use archive-backed asset readers and Bevy loaders for images, models, materials, audio, UI documents, and other decoded artifacts.

Domain records should store source ids, path ids, type ids, or asset ids. Bevy presentation should store cheap Handle<T> values. Bitmap/model/audio bytes should not be copied into every UI node, material, entity definition, or world instance that refers to them.

Loaded asset instances should live in Bevy asset storage or Bevy-owned runtime resources/components. A domain collection of loaded values is valid only when evidence shows an original-game manager owns that collection as gameplay state with special behaviour. Otherwise it is a duplicate asset store and should be moved to Bevy, replaced by handles/references, or deleted.

UI Runtime

The UI should be a data-authored structure with domain-defined runtime contracts and Bevy-owned live state/presentation:

UiDocument asset owns authored structure.
UiLayoutRegistry indexes document/node ids.
Bevy entity tree is spawned from source node ids.
Each UI entity carries:
  UiSourceNode { document_id, node_id }
  UiWidgetRuntimeState or a reference to domain widget state
  Bevy Node/Image/Text/etc. presentation components
Input converts Bevy Interaction -> original UI message/event.
Domain handlers mutate UI/app/runtime state.
Projection systems update only changed entities.

Clicking a button should not execute invented Bevy behaviour. It should dispatch the original UI message contract into domain code, then Bevy should reflect the result by changing visibility, text, images, layout state, cursor, audio, or other presentation components.

Use the Bevy entity tree as the projection cache. Prefer concrete lookup indexes such as UiNodeId -> Entity or AssetPathId -> Handle<Image> when they solve a specific runtime problem.

World, Terrain, And Simulation

World entities fit Bevy ECS naturally. Animals, guests, staff, placed objects, vehicles, and interactable world objects should be Bevy entities with domain-defined components and ids tied back to the original entity/type system.

Terrain should not be represented as one entity per tile. Terrain wants packed arrays, chunks, dirty regions, and generated mesh assets:

terrain/map source data -> Bevy terrain resources/chunks using domain-defined data
dirty chunk/region -> generated Bevy mesh/material update
camera domain state -> Bevy Camera transform/projection

Simulation systems should mutate domain components/resources directly in Bevy storage. Presentation systems should observe changes and update render/UI/audio components. This avoids the pattern of continuing to mutate a boot-time session graph after the domain has been published into ECS.

Runtime Memory Rules

Immutable authored data should be stored once and shared by id/handle:

archive index
parsed document arena
localization table
entity/type registries
material/model/audio metadata
mode/config registries

Mutable runtime state should be stored once in Bevy resources/components:

app lifecycle
active UI/widget state
mode/world/app state
entity instance state
AI task state
terrain edit state
camera/input state
economy/status/progression state

Presentation should be derived and dirty-updated:

Bevy UI entities
text/image/layout components
mesh/material handles
audio players/sinks
camera transforms
animation/particle projections

Transient caches are valid only when they are indexes, handles, generations, or dirty sets over one owner. They must not become a second truth:

allowed: UiNodeId -> Entity
allowed: Assets<ZT...> storing loaded source/domain value types
allowed: AssetPathId -> Handle<Image>
allowed: dirty terrain chunks
allowed: changed widget ids
not allowed: copied UI document tree with independent state
not allowed: domain-owned loaded document collections duplicating Assets<T>
not allowed: domain-owned asset registries or caches mirroring Bevy asset storage
not allowed: duplicated entity definition records in presentation code
not allowed: copied world object graph plus ECS object graph

System Connection Pattern

The bridge between source/domain and Bevy should be ordinary Bevy systems:

load source asset -> hydrate domain registry resource
input event -> domain message handler
domain state changed -> update presentation components
asset handle ready -> attach image/mesh/material/audio
simulation tick -> mutate domain components/resources

This gives the reconstruction Rust/Bevy performance while retaining the original game's source compatibility and semantic contracts. The original files and domain meanings stay canonical; the original C++ heap mechanics do not.