Part of #41: the comments of `benilla-world`, Rust and WGSL, are rewritten to the rule in `docs/METHOD.md`, which is what the code does and the reference fact behind it, in a line. 24,226 comment lines become 8,863. - **The mechanical strip.** The citations that were only a private record number go first, and each edit is shown to be a pure removal. - **Wrong facts corrected.** The rewrite corrects the comments that stated wrong facts. Among them: - `0x6b62e0` is the WMO group's liquid renderer, not a doodad drawer. - The reference creates a WMO's props once, when a group enters its streaming window (`0x698720` → `0x695aa0`). It then admits them each frame the portal walk visits the group (`0x685d70` → `0x6838f0`). The old text had them created per visible group. - The liquid query's comments now state the reference's order: the map-object leg first, then the ADT (`0x69b6d0`). They no longer call the Outdoors/Inside split a match. - The interior probe runs from the character, not the camera. - The reference lights ground clutter. The old comment said it draws unlit. - The model-particle "pool order" deviation was wrong. Each instance is its own mesh, depth-sorted every frame. - The reference's vertical field of view follows the aspect ratio (44.1° at 16:9). The comment now gives it beside our fixed 45°. - The effect shader's far wall is the live `farclip`, 177 to 777 yd, not a fixed 777 yd. - Dozens more turned up on the way: renamed or deleted items, docs sitting on the wrong item, stale counts and links. - **Deviation labels.** "Deviation:" now marks only a choice with a reason. An unbuilt behaviour says so plainly. - **Verification.** Every file strips to identical code, and `cargo fmt --check` is clean. Five second readers compared every file old against new, restored the facts the rewrite had dropped, and checked each new citation against the reference. Defects the rewrite surfaced outside the comments are filed as their own issues (#106, #114, #115, #116). The comments here state what the code does. String literals are untouched; they are #92. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
127 lines
4.8 KiB
Rust
127 lines
4.8 KiB
Rust
//! The frame ordering contract for the world-transition pipeline: a teleport's loading screen must
|
|
//! cover the swap the same frame, so four subsystems run in [`WorldStage`] order within `Update`.
|
|
//! Plugins join a stage with `.in_set(..)` and never name one another's functions.
|
|
|
|
use bevy::prelude::*;
|
|
|
|
/// The run condition every world-owning subsystem gates on: the world exists only while a
|
|
/// character is in it. The camera's gate (`player::setup::gate_world_camera`) is wider: it also
|
|
/// renders under an opaque loading screen, which compiles the world's pipelines early.
|
|
pub(crate) fn world_is_live(live: Res<WorldLive>) -> bool {
|
|
live.0
|
|
}
|
|
|
|
/// Whether a world is live, written by whatever owns the session. Not a `States`: a mirrored state
|
|
/// applies at the next transition point, a frame late for every teardown.
|
|
#[derive(Resource, Default, Clone, Copy, PartialEq, Eq)]
|
|
pub struct WorldLive(pub bool);
|
|
|
|
/// The falling edge of [`WorldLive`], the world's teardown trigger: the run condition only stops
|
|
/// upkeep, so without it a logout leaves the streamed world resident. Each gated system has its
|
|
/// own `Local`, so each sees the edge once.
|
|
pub(crate) fn world_left(live: Res<WorldLive>, mut was_live: Local<bool>) -> bool {
|
|
let left = *was_live && !live.0;
|
|
*was_live = live.0;
|
|
left
|
|
}
|
|
|
|
/// Ordered stages of the per-frame world-transition pipeline (configured `.chain()`ed in `Update`).
|
|
#[derive(SystemSet, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum WorldStage {
|
|
/// `net::apply_net_updates`: the world stream into entities, teleport and worldport surfaced
|
|
/// before the player reads them.
|
|
Net,
|
|
/// `player::control`: input and the teleport or worldport snap.
|
|
Input,
|
|
/// `terrain_stream::stream_terrain`: tiles around the possibly just-snapped position, and the
|
|
/// residency (`loading_screen::WorldLoadProgress`) the cover reads.
|
|
Stream,
|
|
/// `loading_screen::drive_loading_screen`: the cover while the surrounding tiles are not
|
|
/// resident, set here and rendered the same frame.
|
|
Present,
|
|
}
|
|
|
|
/// Installs the [`WorldStage`] order and the boot-order fix below; add it after `DefaultPlugins`,
|
|
/// whose `StatesPlugin` seeds the order the fix moves.
|
|
pub(crate) struct SchedulePlugin;
|
|
|
|
impl Plugin for SchedulePlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.init_resource::<WorldLive>();
|
|
app.configure_sets(
|
|
Update,
|
|
(
|
|
WorldStage::Net,
|
|
WorldStage::Input,
|
|
WorldStage::Stream,
|
|
WorldStage::Present,
|
|
)
|
|
.chain(),
|
|
);
|
|
move_initial_state_transition_after_startup(app);
|
|
}
|
|
}
|
|
|
|
/// Run the initial state's `OnEnter` after startup. `bevy_state` seeds the startup
|
|
/// `StateTransition` before `PreStartup` (`bevy_state-0.18.1/src/app.rs:309`), so an `OnEnter`
|
|
/// for the boot state would run before the patch chain, the Lua VM, the mixer and every catalog;
|
|
/// this moves it after `PostStartup`. Safe while no `Startup` system writes `NextState`;
|
|
/// `insert_state`/`init_state` insert `State<S>` at plugin build either way.
|
|
fn move_initial_state_transition_after_startup(app: &mut App) {
|
|
use bevy::app::MainScheduleOrder;
|
|
use bevy::state::state::StateTransition;
|
|
|
|
let mut order = app.world_mut().resource_mut::<MainScheduleOrder>();
|
|
let before = order.startup_labels.len();
|
|
order.startup_labels.retain(|l| !(**l).eq(&StateTransition));
|
|
// Re-seat only what was there: if `bevy_state` stops seeding it, do not invent it.
|
|
if order.startup_labels.len() < before {
|
|
order.insert_startup_after(PostStartup, StateTransition);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use bevy::prelude::*;
|
|
use bevy::state::app::StatesPlugin;
|
|
|
|
use super::SchedulePlugin;
|
|
|
|
/// A stand-in for the composing binary's states.
|
|
#[derive(States, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
|
enum Screen {
|
|
#[default]
|
|
InWorld,
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
struct BuiltAtStartup;
|
|
|
|
#[test]
|
|
fn the_initial_states_on_enter_sees_what_startup_built() {
|
|
#[derive(Resource, Default)]
|
|
struct Saw(Option<bool>);
|
|
|
|
let mut app = App::new();
|
|
app.add_plugins((MinimalPlugins, StatesPlugin))
|
|
.add_plugins(SchedulePlugin)
|
|
.insert_state(Screen::InWorld)
|
|
.init_resource::<Saw>()
|
|
.add_systems(Startup, |mut c: Commands| c.insert_resource(BuiltAtStartup))
|
|
.add_systems(
|
|
OnEnter(Screen::InWorld),
|
|
|built: Option<Res<BuiltAtStartup>>, mut saw: ResMut<Saw>| {
|
|
saw.0 = Some(built.is_some());
|
|
},
|
|
);
|
|
|
|
app.update();
|
|
|
|
assert_eq!(
|
|
app.world().resource::<Saw>().0,
|
|
Some(true),
|
|
"the initial state's OnEnter ran before Startup — the boot-order trap is back"
|
|
);
|
|
}
|
|
}
|