103 lines
5.2 KiB
Markdown
103 lines
5.2 KiB
Markdown
---
|
|
name: simulation-development
|
|
description: Maintain and extend VampireLike SimulationWorld (P2 baseline). Use for Simulation data contracts, lifecycle sync, Job/Burst pipeline, collision settlement, and rollback-safe runtime switches.
|
|
---
|
|
|
|
# Simulation Development
|
|
|
|
## Quick Start
|
|
|
|
1. Read the design spec first: `./references/SimulationDevelopmentSkill.md`.
|
|
2. If performance conclusions change, sync evidence to `../../docs/P2 Job System + Burst 落地.md`.
|
|
3. Classify change scope before coding:
|
|
- `SimData/JobData` contracts
|
|
- lifecycle sync (`SimulationWorld.EntitySync`)
|
|
- Job/Burst execution pipeline (`SimulationWorld.EnemyJobs`, `SimulationWorld.ProjectileJobs`)
|
|
- collision query/settlement semantics
|
|
- presentation write-back (`SimulationWorld.Presentation`)
|
|
4. Decide rollback behavior up front:
|
|
- `UseSimulationMovement` off path
|
|
- `UseJobSimulation` off path
|
|
5. Add/adjust both EditMode and PlayMode regression tests.
|
|
|
|
## Source Map
|
|
|
|
- Simulation core: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.cs`
|
|
- Job data channel: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.JobDataChannel.cs`
|
|
- Enemy jobs: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.EnemyJobs.cs`
|
|
- Projectile jobs: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.ProjectileJobs.cs`
|
|
- Lifecycle sync: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.EntitySync.cs`
|
|
- Presentation sync: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.Presentation.cs`
|
|
- Target selection index: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.TargetSelectionSpatialIndex.cs`
|
|
- Tick context: `../../Assets/GameMain/Scripts/Simulation/SimulationTickContext.cs`
|
|
- Index binding: `../../Assets/GameMain/Scripts/Simulation/EntityBinding.cs`
|
|
- Battle entry: `../../Assets/GameMain/Scripts/Procedure/Game/GameStateBattle.cs`
|
|
- Battle state gate: `../../Assets/GameMain/Scripts/Procedure/Game/ProcedureGame.cs`
|
|
- Damage/collision utility: `../../Assets/GameMain/Scripts/Utility/AIUtility.cs`
|
|
- Global component init: `../../Assets/GameMain/Scripts/Base/GameEntry.Custom.cs`
|
|
- Enemy old path gate:
|
|
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Enemy/MeleeEnemy.cs`
|
|
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Enemy/RemoteEnemy.cs`
|
|
- Regression tests:
|
|
- `../../Assets/Tests/Simulation/EditMode/SimulationWorldTickTests.cs`
|
|
- `../../Assets/Tests/Simulation/PlayMode/SimulationWorldPlayModeTests.cs`
|
|
|
|
## Non-Negotiable Invariants
|
|
|
|
- Maintain `EntityId <-> SimulationIndex` consistency.
|
|
- Use swap-back removal (`move last -> remove last -> remap index`).
|
|
- Keep lifecycle registration/removal inside `EntitySync` event flow; do not double-write containers from gameplay code.
|
|
- Keep logic/presentation boundary:
|
|
- Simulation computes logical outputs.
|
|
- Presentation writes back `Transform`.
|
|
- Keep A/B rollback path (`UseSimulationMovement`/`UseJobSimulation`).
|
|
- `SetUseSimulationMovement` and `SetUseJobSimulation` must not hot-switch during `Battle`.
|
|
- Keep area query snapshot semantics (`SourceWasActiveAtQueryTime`) intact.
|
|
- Keep dodge semantics using `Value` (additive), not `Percent`.
|
|
- Avoid new managed allocations in Tick hot paths.
|
|
|
|
## Change Recipes
|
|
|
|
### Add or Change SimData Fields
|
|
|
|
1. Update target structs in `Simulation/SimData/` and Job channel structs.
|
|
2. Populate defaults in `Create*InitialSimData` / lifecycle registration path.
|
|
3. Apply runtime updates in simulation stages.
|
|
4. Consume visual fields in `Presentation` only.
|
|
5. Ensure backward compatibility when `UseSimulationMovement` is off.
|
|
|
|
### Extend Job/Burst Pipeline
|
|
|
|
1. Keep deterministic stage ownership (Build/Schedule/Complete/Commit).
|
|
2. Preserve state semantics; avoid UI/audio/effect side effects in simulation loops.
|
|
3. Keep `ProfilerMarker` coverage for new or changed stages.
|
|
4. Keep hot paths data-driven (no direct `Transform` reads/writes).
|
|
|
|
### Modify Collision / Area Query Behavior
|
|
|
|
1. Treat broad phase candidate generation and main-thread settlement as separate steps.
|
|
2. Preserve `MaxTargets` semantics across player + enemy candidates.
|
|
3. If adding query metadata, flow it through:
|
|
- request buffer -> collision query input -> candidate -> settlement.
|
|
4. Keep area-source snapshot behavior and avoid runtime-state race regressions.
|
|
|
|
### Add or Adjust Runtime Switches
|
|
|
|
1. Define exact effective timing (`Battle` or out-of-`Battle`) before implementation.
|
|
2. For high-risk switches, enforce out-of-battle-only changes.
|
|
3. Provide clear warning logs for ignored runtime switch attempts.
|
|
|
|
## Validation Checklist
|
|
|
|
- `UseSimulationMovement = false` and `true` both run correctly.
|
|
- `UseJobSimulation = false` and `true` both run correctly under simulation mode.
|
|
- No duplicate registration or stale index after entity hide/destroy.
|
|
- Battle loop remains stable (`Battle -> LevelUp -> Shop -> Battle`).
|
|
- No new per-frame GC spikes in hot paths.
|
|
- Main flow has no new Error/Exception logs.
|
|
- Keep these regression tests green in both EditMode and PlayMode:
|
|
- `TickProjectiles_LimitsCandidatesToMaxTargets_IncludingPlayerCandidate`
|
|
- `SetUseSimulationAndJob_AreIgnored_WhenBattleStateIsActive`
|
|
- `EnqueueAreaQuery_CapturesInactiveSourceSnapshot_WhenSourceEntityUnavailable`
|
|
- Update `./references/SimulationDevelopmentSkill.md` when contracts, boundaries, or rules change.
|