Repository navigation
Feat: Added partial gravity - #355
Open
luizinhoh2o1 wants to merge 22 commits into
Open
luizinhoh2o1 wants to merge 22 commits into
luizinhoh2o1 wants to merge 22 commits into
Conversation
…cate Per-category gravity magnitudes (living, item, arrow, thrown) and vertical air drag in a new physics module. Terminal velocity emerges from the drag, not a hardcoded clamp. Adds is_gravity_affected for the vanilla FallingBlock set (sands, gravels, concrete powders, anvils, dragon egg, pointed dripstone). Re-exports the constants from the crate root.
Classified error for when a shard's per-shard entity id counter runs out of the i32 space. Maps to ServerError::Internal, mirroring the existing TickOverflow handling.
GameInput SpawnEntity and DespawnEntity for server-driven non-player entities, and GameOutput EntitySpawned, EntityMoved, EntityDespawned for the session layer to map onto the wire packets.
Deterministic non-player entity store on SimShard (ordered BTreeMap, monotonic i32 id source). Per-tick step applies per-category gravity, integrates velocity, resolves vertical ground collision (sets on_ground, re-checks the floor each tick), and applies air drag. Falling blocks: an unsupported gravity block converts to a falling entity on place or break, falls, lands on a solid block, restores its block, and despawns, including whole-column collapse. Entities that fall past y -128 are despawned instead of falling forever. Integration tests cover store mechanics and bit-exact determinism.
Scope, status, and remaining work for simulated gravity: done steps (entity store, spawn/despawn, physics step, ground collision, falling blocks) and pending consumers (dropped items, projectiles, mobs, player).
Falling-block gravity now works end-to-end on the shard (place/break trigger, column collapse, void despawn). Notes the current limit: the falling entity is not yet drawn client-side (session wiring pending), so blocks relocate without a fall animation and other gravity entities stay unimplemented.
Adds a public SpawnedEntityKind (Simple, FallingBlock{block}) and threads it
on GameOutput::EntitySpawned so the session can pick the wire entity type and
type-specific data without querying the shard. Falling-block conversions carry
the removed block-state; the physics step stays type-agnostic.
Translates the shard's EntitySpawned/EntityMoved/EntityDespawned outputs into clientbound packets so a falling block visibly falls on real clients. Spawns a minecraft:falling_block (entity type 49, pinned against the same 1.21.8/proto 772 registry as the player id) carrying its block-state in the data field, broadcasts per-tick position updates, and removes it on landing. Entities get a network id from the shared player/entity counter so wire ids never collide; broadcasts are scoped to viewers in view distance and re-spawn a viewer that enters range mid-fall. Adds a deterministic per-entity UUID and the uuid dep.
Falling blocks now animate end-to-end: the session draws the fall via SpawnEntity/move/RemoveEntities. Updates FEATURES and the sim roadmap; notes that non-block gravity entities still lack a spawner.
Replaces the point + destination-cell collision with a per-axis swept AABB (sweep_move + clip_x/y/z). Each entity has a box (entity_dimensions) that is swept the full tick and clamped against every solid block along its path, one axis at a time (Y, X, Z), so a fast mover near terminal velocity no longer tunnels through a one-block floor and horizontal collision (walls, future piston-pushed blocks and projectiles) resolves too. apply_entity_physics now processes entities one at a time in ascending id order, writing a landed falling block back to the world immediately so a higher entity in a collapsing column sees it as solid and re-stacks correctly. Adds a tunnel regression test and a fixed-support test at the cell centre.
A falling block whose resting cell (directly above the support) already holds a non-full object (torch, pressure plate, button, lever, rail, redstone) breaks instead of settling, matching vanilla. Adds breaks_falling_block predicate and checks the resting cell only, so a wall torch on a side block never breaks a block falling down an adjacent column. The break despawns the entity now (no one-tick overlap needed since no block is drawn). Item drop on break is deferred until item entities exist; the object set is name-keyed pending a registry replaceable flag. Tests cover break-on-torch, side-torch-no-break, and the predicate.
Removes the one-tick deferred despawn (the EntityState.landed flag and its handling): a landed falling block now restores its block and despawns in the same tick, block change ordered first. Simplifies the physics step and the entity state. Updates the landing test to assert the same-tick pair.
…t stays A placed gravity block now falls only when the block below is air or replaceable (is_replaceable: fluids and soft growth), matching vanilla's !FallingBlock::isFree instead of requiring a full cube. So a block placed on redstone, a torch, a slab, or a fence rests instead of falling; it still breaks when it *lands* on such a block. Adds is_replaceable + is_falling_support (distinct from the is_solid_block collision test the sweep uses). Tests cover placing on redstone and the predicates.
…redicates is_solid_block and is_falling_support both fetched the block-state and short- circuited on a non-resident chunk; that read is now a single block_state_at free function. No behaviour change.
…t a fixed list Replaces the enumerated breaks_falling_block set with the vanilla rule: a falling block breaks when its resting cell holds a non-air, non-replaceable block, and a placed block is supported by the same. Both key off one is_replaceable set (the vanilla free set: fluids, grass/ferns, seagrass, fire, snow layer, vines, roots) via is_non_replaceable_block, so torches, saplings, signs, flowers, crops, plates, buttons, levers, rails, and redstone all break a faller without enumerating each. Removes breaks_falling_block. Test covers ten object types.
…ore sequence Hoists the sweep broadphase Vec to a tick-local reused across every entity so the physics step allocates once per tick instead of once per airborne entity. Adds an early return when the shard owns no entities, avoiding the id-snapshot allocation. Replaces the magic 0 sequence on a landed falling block's restore with a named NO_CLIENT_SEQUENCE constant.
A falling block that lands on a solid block shorter than a full cube (slab, soul sand, farmland, chest, cake, and similar) now breaks instead of settling on top, matching vanilla. The vendored blocks.json only records a coarse boundingBox with no per-shape collision height, so the sweep treats every block-box as a full cube and stops the faller on top; a name-keyed is_partial_solid_support set plus a slab type decode (slab_is_double, so a faller settles on a double slab and breaks on a single) restore the correct outcome. Empty-box objects (torch, rail) were already covered by the resting-cell test. Stairs and partials outside the set remain a gap.
…yst growth Pointed dripstone and amethyst clusters/buds carry a coarse block bounding box in the vendored data but have a pointed, non-full collision shape, so a falling block lands on top and settled instead of breaking. Adds them to is_partial_solid_support so a faller that lands on a stalagmite or amethyst cluster breaks, matching vanilla.
Adds more blocks a falling block breaks on when it lands atop them, all carrying a coarse block bounding box in the vendored data but a collision shape below a full cube: redstone repeater and comparator, calibrated sculk sensor, sea pickle, flower pot, lily pad, lanterns, end and lightning rods, turtle and sniffer eggs, pitcher crop, bamboo, floor mob heads and skulls, and every carpet, candle, and bed by suffix. Ambiguous or wall-mounted shapes (stairs, dripleaf, chorus, ladder, iron bars, wall heads) stay out pending real per-block collision shape data.
…lision_top_y Adds data/block_collision_heights.json (derived from PrismarineJS blockCollisionShapes 1.21.4: the max collision-box Y per block, per state where it varies) and generates a per-state collision_top field on BlockMetadata from it in build.rs. Exposes collision_top_y(state_id) returning the top height in blocks: 0.0 no collision, >=1.0 a full-height top, 0.0<h<1.0 a non-full support. A block absent from the derived file falls back to the coarse boundingBox. This gives the simulation an accurate, per-state collision height instead of the coarse block/empty flag.
…op name sets Replaces the name-keyed is_partial_solid_support set and the slab type decode with a data-driven breaks_on_support that reads the registry's per-state collision_top_y: a faller landing on a support whose collision top is 0<h<1 breaks, and settles on a full cube (h>=1). This makes the break exact for every block with no list to maintain, and fixes per-state cases the name set could not (a bottom slab breaks, a top or double slab settles, stairs settle). Empty-collision objects are still handled by the resting-cell test. Removes is_partial_solid_support and slab_is_double.
…the data Makes the derived per-state collision heights reproducible and provenance-tracked. Adds scripts/gen_collision_heights.py, which reduces the pinned PrismarineJS blockCollisionShapes to one top height per state. Regenerates the data from the exact pinned commit's 1.21.8 snapshot (was 1.21.4), so all 1105 blocks are covered with no boundingBox fallback. Moves the file beside the checksummed fixtures and registers it in manifest.toml with sha256 and byte length, and points the build script at that single provenance-tracked copy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I implemented gravity for falling blocks (sand, gravel, anvil, etc). Some debts remain, depending on other systems like item drops, pistons, and fluids.
Gravity blocks now fall and self-destruct in the right cases, like vanilla. Stacks collapse and re-stack correctly, and collision is tracked through the whole fall.
Landing rule
Follows vanilla: a falling block breaks if the cell it would land in isn't one it can occupy. Two cases:
For the second case I stopped guessing by name and made it data-driven: I vendored the real per-block collision heights (derived from PrismarineJS block collision shapes) into the registry and read the collision top per state. So a bottom slab breaks, a top or double slab settles, stairs and fences settle, all automatically, with no block list to maintain.
Water and lava are replaced. The check looks only at the resting cell and the support below, so a side-wall torch off the fall path doesn't interfere.
Placing: same rule reversed. A gravity block placed on any real object stays put; it falls only over air or a replaceable block, and breaks only if it falls onto the object.
Blocks falling into the void are removed at layer -128.
Technical debts
All covered by tests, passing formatting, lint, and audit.
ezgif-5f4d7702bdf23980.mp4