Match living entity input, climbing and air travel phases

This commit is contained in:
Ludovic Marie committed 2026-10-07 02:28:48 +02:00
1 parent 921f092c0f
commit b43c468a6f
7 files changed
+843

No files matched your search

@@ -0,0 +1,226 @@
{
"schema": 1,
"minecraft": "26.3",
"manifest_sha1": "4fe1aa1ef8da1cb95c5bad1fb98890ca56dd8ca3",
"platform": "Linux-7.0.0-31-generic-x86_64-with-glibc2.43",
"java": "openjdk 25.0.4.1 2026-08-18",
"rustc": "rustc 1.99.0 (b940084d7 2026-09-28)",
"fixtures": 35655,
"sources_sha256": {
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaLivingAirOracle.java": "787aa79779b3bf2445a566840759d15dfc85f57e2d80d2d41948cfc5694b68b7",
"tools/test_living_air_parity.py": "e629186b1e4bd8faa1c535fe469a084ac0f5ccf04b2961b3e8cfc322417adac3",
"tools/test_rust_parity.py": "29d3db08005873528894b45ca10dcd6278753650473b3eb574e53e06ede40ec6",
"tools/lab.py": "d00bf107fa01b6c579734a082c3ca4ade3018f0d6851d46844acf17574f66e64",
"Cargo.toml": "3f93319c1eb70dbd7ba25cd74ef343fbf35c52c7c4752f955605c58699cbff9d",
"Cargo.lock": "cb1e87d449114a63edd904c0559d631e8fa9feeb27efd6539aacdcfeae178876",
"crates/horizon-core/Cargo.toml": "e21b502c949da93cf67826592459b687a8cbf737ef92fee514e3ed2cc7cd27ad",
"crates/horizon-world/Cargo.toml": "977338bf3e654193685b015d383493b9f59ff6f5d6210bec212cef8ac4a50bed",
"crates/horizon-core/src/bin/density_parity.rs": "e5b1dd33b7d01306c73cf072629b4fb186e9ab87b672a00108999d1a72263fd0",
"crates/horizon-core/src/bin/float_log_parity.rs": "4a655fcf8822ee7668c4bd126bc84d0b118864a6fc7f5a6aeee667d8bf2590b1",
"crates/horizon-core/src/bin/geometry_parity.rs": "27f6c09fe5018ac3de8e70e0f0bbf78f9abb14f5e4783bcaf46e8ca87b9c6f8a",
"crates/horizon-core/src/bin/noise_parity.rs": "c135bfc708d853e7061e81487d2cfe10de64b2f65677d3b4837cbfe0b8341010",
"crates/horizon-core/src/bin/parity.rs": "f35d928c66f958de39fac5e7e836a657eed95f83599e84899f7ea7a5802ba481",
"crates/horizon-core/src/bin/tick_parity.rs": "a54c164fe4814034d369947a887f5273966f5a878ba849204b80d1c729526a8f",
"crates/horizon-core/src/biome/seed_hash.rs": "5afbb4921c750826b395a08bf06f382fc7f01b5759a93de02a2749c523e2a317",
"crates/horizon-core/src/biome.rs": "908efa8cd4aa0a7adf1cb5e1a222e3dfb640eed5e9172e0fe7f0d1287afae7e8",
"crates/horizon-core/src/carving/ellipsoid.rs": "09232a7588610e8a9176fd9c62d40afb1fb89f2ecab6d555536a1d847b142d86",
"crates/horizon-core/src/carving.rs": "0aa3093caa0437868a8c0ed52a6c6e1993bd51c03583c670a2837e749eae5426",
"crates/horizon-core/src/density/arithmetic.rs": "372faec96c923e2cf4aa6c66c1ac398e676853274557823850dbc8933dd15ab1",
"crates/horizon-core/src/density/beardifier.rs": "bb1052e27dae4a01954ca78d7d5babafef85f3b2c704ccaf1920cb85a098cb50",
"crates/horizon-core/src/density/cache.rs": "38d0b6c9dd04ffef979fdad3f29cfebf98d331c8c9d430be5f39aa34f6c30975",
"crates/horizon-core/src/density/end_islands.rs": "168b9384237bd2e41d0ae5a74e944da4dc74e493bdec31fb73184c9a49e3de55",
"crates/horizon-core/src/density/graph/compiler.rs": "ac67deeb16f16d0859aa20e5a165811a29aca0b910037ee6bf5098211f3a6ede",
"crates/horizon-core/src/density/graph/mod.rs": "b776e7da934cb03051a3053d56d461c71e9978e084922fe4194147aa580c07bf",
"crates/horizon-core/src/density/graph/seeded.rs": "6bcdcaa3dffcfa9df673bbbea35120057a16ba3d2b506c52709c36cf8976b74a",
"crates/horizon-core/src/density/graph/tests.rs": "6bfb8cbff462587dd147b0775ea01d370abbd97544b9bd596c792df1b5f7e634",
"crates/horizon-core/src/density/interpolation.rs": "8c890f52b6467f38a94c654986a6a484b8e0b296ab98c398e60a6ce465b5b010",
"crates/horizon-core/src/density/interval.rs": "b42629163baa6b599a233afe8596d1c370cd81d015cc6fc36a9663aa47b98424",
"crates/horizon-core/src/density/mod.rs": "ca0d77d3282e3746ddcbc92bee97dbf640b9a56214e6ac1537f51f9a5b63d6e7",
"crates/horizon-core/src/density/power.rs": "d5b7270a128d4264268cd772109ad16d71a8ec3ff2d3b63b84cb985296d54a91",
"crates/horizon-core/src/density/rounding.rs": "71840c5206ff8d218ac29bf6f66915d5212764ba270c675711a866ba5b55a7a6",
"crates/horizon-core/src/density/selection.rs": "0dd26af2e85004ec5e053039ad11c384c17c56ace9ab45eb3f5cb3503c0b0330",
"crates/horizon-core/src/density/slice.rs": "5d77605573c0deda47778f1f78f7fa3fbf1944d8f5efbcc65cf589181cadf80b",
"crates/horizon-core/src/density/spline.rs": "6bb2e40f940fc6544d6fb09cb0b8cac722be03bc663dbdfb0f61faae207400bc",
"crates/horizon-core/src/density/surface.rs": "159e0e69cda74f870e80ea64fe523c4397e64af4ccb861bb9fd07b2c3cb91b00",
"crates/horizon-core/src/density/terrain_noise.rs": "8d0059d25eb5d248cb97a4c5a2e670d61528928ea151495c004f25adb723fe3e",
"crates/horizon-core/src/density/tests.rs": "7817796ee40d0ae241bfbebec6bca190e0a8e7d5a1caa8ddf858c3eaa58b8858",
"crates/horizon-core/src/density/world_fields.rs": "c1ce305cb8046b384d90c564cafb24af7365d580389637910f3d8b0cc18eb583",
"crates/horizon-core/src/geometry/border.rs": "1386f8080521231d05ba3e84d94a3e1d5218d35ccb3d5e9fe2bbb05a8739e573",
"crates/horizon-core/src/geometry/mod.rs": "c650386f9860e44a96c55f18c8f1428ca715fcb0bc5c2434db5b1caa43df27fe",
"crates/horizon-core/src/geometry/movement.rs": "bcfb452752940ce53ae6dc267a3c4eb29459046a063c1f884684ab4f4bd0068f",
"crates/horizon-core/src/geometry/shape/create.rs": "189812b91d5e0e3ad963afcd1a6e2831b31b8188df91a904ef27061e644806ad",
"crates/horizon-core/src/geometry/shape/face.rs": "f243bce81384040a95ce7984b02b5699206c596c537b2713097e86005b4d3a5c",
"crates/horizon-core/src/geometry/shape/join.rs": "f1b51887b7bf9482557e3ffa99e136f2e5db07ceeb05fdb116adf45e87129075",
"crates/horizon-core/src/geometry/shape.rs": "e8d88a763de1525f77a30b99591641e8a8b80946263acbde035a9bcc356df960",
"crates/horizon-core/src/geometry/sweep.rs": "abd6009c61555161ef2f18b431b2aa384b126c0871cae8b96a62358498a56a1d",
"crates/horizon-core/src/geometry/traversal.rs": "77a3da570a0b85582b669cf4d841cba4b06327006dda26d4a26df4e8ce05bae4",
"crates/horizon-core/src/geometry/trig.rs": "05cef9341a298a474221a0556a11ddf47650393ea7a97b4b2022a4da6628fe37",
"crates/horizon-core/src/lib.rs": "4255e16837fde42a52ba118f60581d197c571bb530b60d635e506184ebf4db0b",
"crates/horizon-core/src/noise/mod.rs": "1dab5a713abf702402e69ace1bf9e476bba544b0ede5a61c3c3afc60af0a03f3",
"crates/horizon-core/src/noise/normal.rs": "e9e7a46472a54a02c98c46da819842090567153b32fe0c84249009ef19af7aad",
"crates/horizon-core/src/noise/perlin.rs": "e73815447432eab7542f67366cb3f1b368d164e33f6c9cdbd045ac8e4db0932a",
"crates/horizon-core/src/noise/simplex.rs": "6c0dbc15b2b7510195dd28fceca01dcaac1847ccc4a84d299c351589c642fe7a",
"crates/horizon-core/src/noise/stack.rs": "7f6ef0e7d920139ef1a6ad3ec5640f92765715f86dcc5ec29f1a149984f45fa3",
"crates/horizon-core/src/noise/volume.rs": "3f05d2b1780acfdfee60037677d309937a5033b45ef428fc2d540942d4b56b43",
"crates/horizon-core/src/position/iter.rs": "32d2d8e74821cc4e49e3354202d35d3120e4415bfdda9375a73f2137ef651129",
"crates/horizon-core/src/position.rs": "e10101088e6902386b9b6d27773d44312f1ff72bebb19e57967a54945dde9dcd",
"crates/horizon-core/src/random/hash.rs": "0f88a127a1ba2705d3d6c0ebd009324d6ba86ffa2d27edf2d2a84765e690e4a3",
"crates/horizon-core/src/random/positional.rs": "35494745e5d4cf89e282c3ae0ee245e9f2640ddbbc03bc0055df742006a9c862",
"crates/horizon-core/src/random/worldgen.rs": "9f07ff33bcc038d34e27aa5465753bb21df18f2975e43cae201f709bc186945a",
"crates/horizon-core/src/random.rs": "ddb95d3a83e28ad605ff1f49f5df270cc543ca5ef1130e37d989dc74c8d861e6",
"crates/horizon-core/src/storage.rs": "f6c32201c64aefde06e57a2c767be46918df613548a322801546b133799cc33d",
"crates/horizon-core/src/text.rs": "e6553ddb5db5039e8dc4614b6a6dc9f35a26dc3d1673b68a04e72e7983b67abb",
"crates/horizon-core/src/ticks/generation.rs": "be1237e790693f633a61714ddae68c6506a777588a8a3ab5efbe53a35774dbd2",
"crates/horizon-core/src/ticks/heap.rs": "bf28afab8af77c3d243aa96cd8a1fb8d934140a4dbd07dbfdbf4e7908bb4b845",
"crates/horizon-core/src/ticks/index.rs": "1f1a6a568c2a30eafecb020ca4d5f5fc414860de85b8b381fc419a2e3e65c24a",
"crates/horizon-core/src/ticks/mod.rs": "01634630668172516b8b79d0907bad47f6e2c543a6d499c2fa4b201823b375cb",
"crates/horizon-world/src/bin/worldgen_parity.rs": "3143ceb9b56eecfd7667e5feb5f9f0cd13cfb8754b38d4ea338dbba97f2819da",
"crates/horizon-world/src/block_collision.rs": "39207247f2f6dd3ddc77640229044246f91b32054563f88a435f1bd92ad2092c",
"crates/horizon-world/src/block_collision_scan.rs": "20802862364c110ff85eeaf48606596a8468b83768dda46b412d337958790b41",
"crates/horizon-world/src/block_entities.rs": "a9deae92e6e5a1fcf4f0476c33ea4d170ddad6fd4b3303e1bb66d933973d5e06",
"crates/horizon-world/src/block_entity_push.rs": "12ee91bf604946234b24a0da4333f07d1830ab9743a422d41c8d0afac7d49cfd",
"crates/horizon-world/src/block_landing.rs": "33083fe39266fbefec1b3ea1a19f2afc609791d189da247c895e116ad6eb266a",
"crates/horizon-world/src/block_placement.rs": "524f4892d50bab77b7d89d19f7b048ffe746996f2ed7f376db2c6ab00ed75c24",
"crates/horizon-world/src/block_properties.rs": "b0bd8a983336c48e488a20caa77dd5c39b1a74bbd14ebc03b3b64556a1c864fc",
"crates/horizon-world/src/block_render.rs": "8df52ee11aef406a1571198a64048062a0ef6864e0058d9293a57f64b73c916a",
"crates/horizon-world/src/block_support.rs": "ade4fbd47284b450dabdd682dc86138b2ac05a0fd379525d7110648908245476",
"crates/horizon-world/src/block_survival.rs": "28ce64375e09819a4f13da9cfbe37c08b5ad0daf01b289c1c360b4567e50e811",
"crates/horizon-world/src/chunk.rs": "8843e6f48dbbc4245ce4e95564dfba3a4d7a051ba0b1577fb038c07adb0ff0f9",
"crates/horizon-world/src/chunk_status.rs": "dbb8583cfa775203c544d24d69e03720385428f15a267a561356c21f5025e9c7",
"crates/horizon-world/src/collision.rs": "a749794d5c27ccd6c0d964ad02f9dc31d49d9f4fe4b7366cd4bd8155e681b00b",
"crates/horizon-world/src/collision_context.rs": "2176c7034e07f547510a8327cdad9d3b63f26e4754032b76b7d5fe13166c333c",
"crates/horizon-world/src/compression.rs": "4db73e6ca9a0d552d415ce60e7e88b89c9cf2b7d060a669ff8328f518316e101",
"crates/horizon-world/src/dynamic_support.rs": "5996bc1c436fb6215d8fc3d0bb4de5dd9b966d842d432580d624195771697fb8",
"crates/horizon-world/src/edge_backoff.rs": "5259d7aa44e64f88351d1556c44dd0edcad3b400a099c659755792efba7b5773",
"crates/horizon-world/src/entity_collision.rs": "09f2fd7f6cd56fc282f468ecfa765a94506929e9684bd3a5c90123e5b51cd627",
"crates/horizon-world/src/entity_move.rs": "a40a50d3e841625a75d4cfbb7c2630ab5a62a574456567e7234f401ae8441b32",
"crates/horizon-world/src/entity_obstruction.rs": "a4b28a19bf83b23611c59d94535c488db37e4aee24b22c973c545910894a809f",
"crates/horizon-world/src/fall_damage.rs": "8c28e2933493569fe05dea22332024287d28b0746b514dd465681040b003296b",
"crates/horizon-world/src/fluid.rs": "a0a1f34ba94d8b59dc975becee8952960764d67ae08cf2d6a8bcd40a614b15c4",
"crates/horizon-world/src/fluid_shape.rs": "28bb65a72f5bd074a354ba38a1b1707fcb0947537977a11540bba0adb85995c2",
"crates/horizon-world/src/ground_support.rs": "3e371d74ecede4d30beef0a7e8a2ee33463584a5b1ed3d852b394efcce1ffbe0",
"crates/horizon-world/src/heightmap.rs": "a5edef082b5af40d814421ea17e129b3b06d70abee6434ed263e4bba58571698",
"crates/horizon-world/src/interaction_shapes.rs": "f321284ddab440a394372b6dedc8b5cc29a653c0745251a9e96c650f21c33dea",
"crates/horizon-world/src/lib.rs": "6c3ba8a4db5b04508f5bc0633fd864095c7afbcc024523c9a6219134210489a2",
"crates/horizon-world/src/liquid_collision.rs": "0f0a83b04e5a5bc9d98ed05fde4d6584ba69642e93522e726e4cfc325d6fcb1d",
"crates/horizon-world/src/living_air.rs": "b2de36bb50bed15e2808fe4a874fcef07f9fea0d2c96385b7b5e8ee9560d4442",
"crates/horizon-world/src/living_fall.rs": "da0f176f4731e1c86e08bfeee8167742fd1b86380ff0e9304c13c1ce3f1c67ab",
"crates/horizon-world/src/living_landing.rs": "8bca4eb7977abc2b14fb7174be4ea355352106ea1e76ff5f3ad8696969d9eefd",
"crates/horizon-world/src/main.rs": "fce57418b8c22a6a0a9044baa89ed3d9c243bc2e8413fea3ff0f32985daba021",
"crates/horizon-world/src/movement_emission.rs": "76e7d6f5b19c94676190f54389f9c4ce12cf89945ccfcb9c750de473223e7753",
"crates/horizon-world/src/movement_properties.rs": "6f01ab920b376a13f5ae12c3718f4dd067e1dff2b829585af00a8b2100f3775d",
"crates/horizon-world/src/movement_restitution.rs": "04b4fe0947e7e52576145bd8ed15920278e8a538afcc74d125eaca513dffa0ef",
"crates/horizon-world/src/movement_support.rs": "02d85cf572847f2e60b5a7f9d60b856888a67b3c1f4df03e81998c66fdf874be",
"crates/horizon-world/src/nbt.rs": "60262c3de8c8f68bc2da0370ccb17393d32b85f5f5022c6358599a7d32119ea6",
"crates/horizon-world/src/piston_movement.rs": "7a3fd2549a582b5f3a5c21aa05d67d944d62ca1105856679e100ac5b44e9a52f",
"crates/horizon-world/src/piston_shape.rs": "399c2337103b8e7e0eb5667227c5aa14f9549d6a467b7be7da3d0717f0263500",
"crates/horizon-world/src/powder_snow_collision.rs": "7289946a21478d11abfd2bdcdddff3d7f98e25bf6a68564fed45c3cc01ac2a36",
"crates/horizon-world/src/region.rs": "72b642e87fed37ed17f54d4c30f96c3b64d26c14bc0589c31ef40ff1616188fc",
"crates/horizon-world/src/registry/json.rs": "7a683afcd1742c5307756927d7f0aa779c7d7992af87d8d371dd98108728e235",
"crates/horizon-world/src/registry.rs": "f2e58b2b4d944ac8fc6226bd3352cefc3d2052d8473e02ccf7dc402b176df435",
"crates/horizon-world/src/registry_collision_scan.rs": "a5021a168adcedc37d77f533a8921c02f09c59f46a01737586aaa33c5908b8d0",
"crates/horizon-world/src/registry_fall_ray.rs": "52935436132df505691144840dcbd858b15d00d8305997284e3a542ecf6bc0dc",
"crates/horizon-world/src/retrogen.rs": "6efd36a6293756688c1990a7965bd65609d7c5e2bf2a5f4f01d54932d2b9386b",
"crates/horizon-world/src/suffocation.rs": "bed219dd5bbab6263b98fbe3d0eb512cb96c52ae847210efe49514d05f22f11e",
"crates/horizon-world/src/tick_data.rs": "f8d04a69ea263f4168bce33f92e5b4ee2fe07d7caf50a1621c6b3ef6eb2479f3",
"crates/horizon-world/src/world_movement.rs": "f8fe9e34f2395d2a04c839d1c8ba78e09ce493c26de6f6e4e237b9c19c061da5",
"crates/horizon-world/src/world_ray.rs": "879bdbbe12f56deb705cc183933431489e840b71eade40c33391eed5949c2e61",
"crates/horizon-world/src/worldgen/anchor.rs": "d156b8a0b147a274cdd143409b441f4f43edecde6e8ee14ef9cf0309f743143a",
"crates/horizon-world/src/worldgen/aquifer/config.rs": "fcd2cc3a520c1527c88f095a3b5d38487e7ebb1ccecc5f757f93d04a069add4f",
"crates/horizon-world/src/worldgen/aquifer/noise_based.rs": "74daaa389b5c3dfdc99214dfff256a9e172f83548d2326cbc941d9637cc53fb7",
"crates/horizon-world/src/worldgen/aquifer.rs": "cb4b66d87de3f9f79ae6ffe4badd6f0f44886cd42ad9de2771b8b56c4f1e28c7",
"crates/horizon-world/src/worldgen/bamboo.rs": "d9b47113c99be34256e58308bc6f40072ff25c579d6bf995182aa862c0006102",
"crates/horizon-world/src/worldgen/biome.rs": "3fe316b875aa32683759c337dc71f624910faf0812a2d6d83b8098d6d0bac7a0",
"crates/horizon-world/src/worldgen/biome_chunk.rs": "8fdfe6ebe3ffeca97611fd5991a5bc6b2783ea1c62f4d8ef3b2dd53c04a5dc1d",
"crates/horizon-world/src/worldgen/biome_predicate.rs": "bfc581bc40077cc74ffda43e990a55fe997adc04c7130f98e039c3305ca79aac",
"crates/horizon-world/src/worldgen/biome_source/codec.rs": "2b9e4f5d679eb444cb73174f511e3b9f32e9eb138248ab12cffc6cfd76adf3a8",
"crates/horizon-world/src/worldgen/biome_source/runtime.rs": "f0b02c1521178e4d0377c6ca62694604b6a773f1f234f070ff0cde4685911d45",
"crates/horizon-world/src/worldgen/biome_source.rs": "e181e1736f3e0b75f7091a24c88de3fd116e01b98424d02382aea7a503d1eb54",
"crates/horizon-world/src/worldgen/biome_temperature.rs": "cde4bbab5e260c4065b113376c423b8511ade93c5aa5fd976e245ee8a58b5ad1",
"crates/horizon-world/src/worldgen/biome_weather.rs": "96b1f9494559ed31d06257b83d604d00cc069ccc8c7b68094117e034b4a71bd7",
"crates/horizon-world/src/worldgen/block_blob.rs": "c608c57b3d77279646ecb89e50677dd8e452b0422ffd357ba755536c5589eb89",
"crates/horizon-world/src/worldgen/block_column.rs": "f72c21a9066ee0aa68c2fb79fba436d05afb14c6ef5a2cb012f1ed35fc17cd22",
"crates/horizon-world/src/worldgen/block_feature.rs": "36b4e46ee7f7f73bcb94d8bce8d99013e4b16234c9a03542eeb3186e88dd1c21",
"crates/horizon-world/src/worldgen/block_pile.rs": "623e369b77e0526ed2756485a6c0bb09683cd28ad8876dea907360ca6665b39d",
"crates/horizon-world/src/worldgen/block_predicate.rs": "074c692367e3f2191a1bb28d87b23402430a843c246bd30a4ea838ee3500280e",
"crates/horizon-world/src/worldgen/blue_ice.rs": "eedd77bdaff808330b864166d303378096daa5c7d235e925770b171c05109247",
"crates/horizon-world/src/worldgen/bonus_chest.rs": "05d0f63fbc7412f13ba1fa37a7238114b8f70bfff318beb2dece590482d49cc0",
"crates/horizon-world/src/worldgen/bulk_section.rs": "eecf61532d7793f853884c5a18a7f436a59835c7b13d3ec9075804511553c9ba",
"crates/horizon-world/src/worldgen/carver/canyon.rs": "509c4d5a9d689849e98e894ab14a9fbf82d10707d38e9cc688ded3c4778df3e2",
"crates/horizon-world/src/worldgen/carver/generation.rs": "a4498d0d1457536de3922a08e9c40ccce8d2ef9cc263801c15a412327513c098",
"crates/horizon-world/src/worldgen/carver.rs": "46b251e28225fe1250de38f49dec5dacda4e2c4ba1e556e21e6d1e14e2651fc3",
"crates/horizon-world/src/worldgen/carving.rs": "4e77d4e5c4a0ca55ca3563b9bdf6f379342e0bdf9d019d60f7bc57ce4afb5fbd",
"crates/horizon-world/src/worldgen/chorus_plant.rs": "29224c164ede919e280a65a68f155c873e2c8fd0aa7d7e244d8fa9e468760250",
"crates/horizon-world/src/worldgen/climate/codec.rs": "d567adeb5d837816fca69102db51d790f71aec1b51c09298230d24612e400a14",
"crates/horizon-world/src/worldgen/climate/index.rs": "c5ce61679a5f0e0f2f0af2a373424effa124d0cce8250609eff38b7034650756",
"crates/horizon-world/src/worldgen/climate.rs": "1b9ad44407f40aee4c1cd5357a5c9c443c1b105728f01cf5c644072f99f8357e",
"crates/horizon-world/src/worldgen/decoration.rs": "75a79b20b21e133816e729f16e758be6165d0db18a64bfbd5fd3618325a2adf3",
"crates/horizon-world/src/worldgen/delta.rs": "c2bf49ddf3231d28c109e68871429bc13d76a7bebe14eb33e84aa856bdd66145",
"crates/horizon-world/src/worldgen/density.rs": "65a98c156a290a6b374ef670d28cd5dfbe0aa93171824d1bbd96422536273f84",
"crates/horizon-world/src/worldgen/disk.rs": "6f8f9e059755af44c9bfa1b91eba54a7d13fad811dce31717c5502d7f6df33d7",
"crates/horizon-world/src/worldgen/end_gateway.rs": "f53fde77d6a36a525cd15d890003b2c129d0689a4cbfa2cf443a0c2e3acae040",
"crates/horizon-world/src/worldgen/end_podium.rs": "8f6d0d6d60ff0fde63de5781e867239db321f82cf12639f0537d410a3731ee1d",
"crates/horizon-world/src/worldgen/feature.rs": "40500af71ee6628dfb27518262d99f08d0383ae6c7b9397452feef0c213eadd9",
"crates/horizon-world/src/worldgen/feature_catalog.rs": "efc7b17b227e71622ef34108be9abd010f5675b68ea0409fcab82581d9aab88a",
"crates/horizon-world/src/worldgen/feature_graph.rs": "da132fca9fdafb0d89a917d5f4b68c60b70fb33cadf948a107da0e35d83dcd91",
"crates/horizon-world/src/worldgen/feature_region.rs": "df0ff142a461cafa9a3b42b949ad3376887f2be8d4ea5cc794a3ed2e977bb499",
"crates/horizon-world/src/worldgen/feature_sort.rs": "3488a093dfe1321aaa29d8a30cfb115d8e666a81bf195514e87b170de626835c",
"crates/horizon-world/src/worldgen/fluid_predicate.rs": "64197c9e63bebf1ce04bc280bfe980bb6c1b9aa887ca5cded904aeb0d9ae6c46",
"crates/horizon-world/src/worldgen/height_provider.rs": "368d4dc119854742a045c4a717679c921456da681fc5f71aa9b37102d6f33b47",
"crates/horizon-world/src/worldgen/material_condition/codec.rs": "09b909bc384472f76d163c8069ec6b507c7d5c6a028a36d5e0e3df20deff7b3b",
"crates/horizon-world/src/worldgen/material_condition/density.rs": "df9d0761e978e5010663ae8b44f2d6c1ecb4907331e333bdb6a2b487c1e107de",
"crates/horizon-world/src/worldgen/material_condition/library.rs": "a55534c5da97575a819af5a7dc0dbec9069993fa8b2619c6c9d5576946e683fa",
"crates/horizon-world/src/worldgen/material_condition/noise.rs": "ffb59cc6be2275d7a5621bf7d768527e74a8326ed7ad78618746711540921675",
"crates/horizon-world/src/worldgen/material_condition/rule.rs": "fed643352efbcb1f68f29b6241896617db889fc7c577a6247564e01922fec1fe",
"crates/horizon-world/src/worldgen/material_condition.rs": "d638dcb8cbcb5da20b3cb29602b0ae6a86c4fdf9d8c0fb725de8ec5fc108717e",
"crates/horizon-world/src/worldgen/material_extensions.rs": "ab806eb679d5116e1aebb64fca70e1499ae71f83c9507a8cb4c3201c2b1bf037",
"crates/horizon-world/src/worldgen/material_stage.rs": "698cbc786eff13c246e2bc2ea062401918cd4265899fbc3d53abc87e45a8e7a1",
"crates/horizon-world/src/worldgen/material_surface.rs": "5d37b90099df3d6da0845dab164e71469fb287019c2ee74bc6714f3b9d6d6d5b",
"crates/horizon-world/src/worldgen/ore_feature.rs": "83b89fd3be691c5412c0215b6abefdcaa44119a05aa41217e061970eb7e12ebd",
"crates/horizon-world/src/worldgen/placement/chain.rs": "9218399b4d3757f7bbc550d7729a7201f32a1c83a7030865e0c12aab8a80d116",
"crates/horizon-world/src/worldgen/placement/context.rs": "a278304795136677ad4b4933ea50c972b9729a1c671c03fa309c193e224b1fd6",
"crates/horizon-world/src/worldgen/placement/layer.rs": "a0f5ca776f33f9d4f72b8fdcd163426152e5e43cb4a7572fc1d4fc57bf965de1",
"crates/horizon-world/src/worldgen/placement.rs": "b0397e5818fae84358546193a95f84bcb0b5bffafce909e6fcb3386179ee8023",
"crates/horizon-world/src/worldgen/replace_blobs.rs": "bf3377d86d2570cd15288ba69dde64a2cf67c5bcbb9a31d0c23421964af74afa",
"crates/horizon-world/src/worldgen/router.rs": "2cee7cf15a0d2ada12be6b39d83e78177fd3033922e4f4cce87a64073cec2847",
"crates/horizon-world/src/worldgen/rule_test.rs": "d1662ec492489ebaa4b87e20f9a8c809dcf3a223a151211bd65ec241a63692fc",
"crates/horizon-world/src/worldgen/settings.rs": "a8fe87752e1982ef11cb67f8d80d8e3428b2c27db178044cb425ba803e689e59",
"crates/horizon-world/src/worldgen/simple_block.rs": "9ba1a88d5db4925f8c37366557887f776c805f9a6444781615b5dbaff52e92a4",
"crates/horizon-world/src/worldgen/snow_freeze.rs": "9040be3d5c7f8f0fd812d2df45e154bf8a9eeef038530b83fa4159d246eac35f",
"crates/horizon-world/src/worldgen/speleothem.rs": "c71651c1c97818a8a85863e14414d6139ea3bdeb897fa422043bcc1499d99aae",
"crates/horizon-world/src/worldgen/spike.rs": "eacf0d9d3d2bc3d4bcf62bc87555f90031138236a5bfef0eb5270204f7c2a4fc",
"crates/horizon-world/src/worldgen/spring.rs": "830849e9b89fcdf09e9b06fbefdcdebe3c8c3f82804f60b8bd5de04ba303cb62",
"crates/horizon-world/src/worldgen/state_provider/catalog.rs": "c8687e15a4887a9200c8d365857d801efaa8f90e669eee3e600a1db4905119eb",
"crates/horizon-world/src/worldgen/state_provider/noise.rs": "7ee369c2a032e5620cb9bdf9ee7adad1f70870fb0a27efb7b7c514d92f83491f",
"crates/horizon-world/src/worldgen/state_provider/properties.rs": "9909139aaca1dc4f743957257fadaa9d423d21fa401fa9abc050505f79365139",
"crates/horizon-world/src/worldgen/state_provider.rs": "be29ada818826a90afe01ab60916360fdfc4cbde5af15c9359cd56b1f1f7b156",
"crates/horizon-world/src/worldgen/tags.rs": "d35ded93fe6e95ea045cadcf4925e656dc34ef832b742179b9ad0cc49f902f31",
"crates/horizon-world/src/worldgen/terrain.rs": "fd1f2e0afc15daf66f484ea40a1f2b7013650bda0941b23c64c81ee9f79cb673",
"crates/horizon-world/src/worldgen/underwater_magma.rs": "7317e40af5ee5a9780f90ce358fa5d3e7f5b3d513b731df6ff97754d9c2a0154",
"crates/horizon-world/src/worldgen/value_provider.rs": "3358b563db8cb0bc8a9cfbbe2b8b3e70941cd2d37a0b519fbb6545f8d0dcbb69",
"crates/horizon-world/src/worldgen/vines.rs": "ee9b79b65012bd86a838241d2ef708680f7fe8eafc8aa656dae9cf2abf3c6418",
"crates/horizon-world/src/worldgen/weighted.rs": "839840aae25302933bbd97a81a2336330e2d03a0ad1684e1e16ac769ed408e6b",
"crates/horizon-world/src/worldgen/write_zone.rs": "8e17a179764d3f68c05882aef35f6810c28a0000f9a83e58bd6030660b76e64e",
"crates/horizon-world/src/worldgen.rs": "e8e9f099ee1fcec8eedce31805d676d3f89c18e84f494a147ffcbfee23d3d54f",
"crates/horizon-world/examples/living_air_fixture.rs": "4736e209a6772840a953b1aabd736cbc4eef064b9658300aa152f081345190c1"
},
"fixtures_sha256": {
".local/rust-living-air-parity/inputs.txt": "975ea006fdc523f37ccef52b654630ed653a0766ab1a5faf0b006f829bc73618"
},
"rust_output_sha256": "c1f207978d91c4ee96a148c47f1a5962270d0272b0c9aa9f7829714821bc511c",
"references": [
{
"side": "client",
"jar_sha256": "4508d006323f24fa02876310c192d739af56516eb259000ac50f0909a68c9a2d",
"output_sha256": "c1f207978d91c4ee96a148c47f1a5962270d0272b0c9aa9f7829714821bc511c",
"matched_output_lines": 443554
},
{
"side": "server",
"jar_sha256": "a362163eec5d1612d520772bc16e5b39c09e3b234fdc045f56bf544284ee8ae6",
"output_sha256": "c1f207978d91c4ee96a148c47f1a5962270d0272b0c9aa9f7829714821bc511c",
"matched_output_lines": 443554
}
],
"scope": "Actual LivingEntity.travelInAir, handleRelativeFrictionAndCalculateMovement, handleOnClimbable, getFrictionInfluencedSpeed, computeModifiedFriction and Entity.getInputVector. Traces native moveRelative and state writes, both Player/nonplayer ladder guards, registered scaffolding/boots checks, levitation, missing client chunks, float friction/drag, callback mutations and failures. Entity.move, effective gravity, ground/climb predicates and attributes use controlled providers; live world integration and complete player travel remain pending."
}
@@ -0,0 +1,246 @@
use horizon_core::{geometry::Vec3, position::BlockPos};
use horizon_world::living_air::*;
use serde_json::Value;
use std::{
fs,
io::{self, Write},
path::Path,
};
fn number(v: &Value) -> f64 {
f64::from_bits(u64::from_str_radix(v.as_str().unwrap(), 16).unwrap())
}
fn single(v: &Value) -> f32 {
f32::from_bits(u32::from_str_radix(v.as_str().unwrap(), 16).unwrap())
}
fn vec(v: &Value) -> Vec3 {
Vec3::new(number(&v[0]), number(&v[1]), number(&v[2]))
}
fn bits(v: f64) -> u64 {
if v.is_nan() {
0x7ff8000000000000
} else {
v.to_bits()
}
}
fn fbits(v: f32) -> u32 {
if v.is_nan() { 0x7fc00000 } else { v.to_bits() }
}
fn vector(v: Vec3) -> String {
format!("{:016x} {:016x} {:016x}", bits(v.x), bits(v.y), bits(v.z))
}
struct World<'a> {
f: &'a Value,
out: &'a mut dyn Write,
calls: i64,
ground_calls: usize,
climb_calls: usize,
velocity: Vec3,
fall: f64,
moved: bool,
}
impl World<'_> {
fn flag(&self, k: &str) -> bool {
self.f[k].as_bool().unwrap()
}
fn query(&mut self, s: impl AsRef<str>) -> io::Result<()> {
writeln!(self.out, "{}", s.as_ref())?;
let n = self.calls;
self.calls += 1;
if n == self.f["fail"].as_i64().unwrap() {
Err(io::Error::other("injected travel failure"))
} else {
Ok(())
}
}
fn sequence(&self, k: &str, n: usize) -> bool {
let a = self.f[k].as_array().unwrap();
a[n.min(a.len() - 1)].as_bool().unwrap()
}
}
impl LivingAirWorld for World<'_> {
type Error = io::Error;
fn movement_support_position(&mut self) -> io::Result<BlockPos> {
self.query("support")?;
Ok(BlockPos::new(17, -64, -33))
}
fn on_ground(&mut self) -> io::Result<bool> {
self.query("ground")?;
let b = self.sequence("ground", self.ground_calls);
self.ground_calls += 1;
Ok(b)
}
fn block_friction(&mut self, p: BlockPos) -> io::Result<f32> {
self.query(format!("state {} {} {}", p.x, p.y, p.z))?;
self.query("friction")?;
Ok(single(&self.f["friction"]))
}
fn friction_modifier(&mut self) -> io::Result<f64> {
self.query("friction-modifier")?;
Ok(number(&self.f["friction_modifier"]))
}
fn speed(&mut self) -> io::Result<f32> {
self.query("speed")?;
Ok(single(&self.f["speed"]))
}
fn flying_speed(&mut self) -> io::Result<f32> {
self.query("flying-speed")?;
Ok(single(&self.f["flying_speed"]))
}
fn yaw(&mut self) -> io::Result<f32> {
self.query("yaw")?;
if self.flag("yaw_mutate") {
self.velocity = Vec3::new(17.0, 18.0, 19.0);
}
Ok(single(&self.f["yaw"]))
}
fn velocity(&self) -> Vec3 {
self.velocity
}
fn set_velocity(&mut self, v: Vec3) -> io::Result<()> {
self.query(format!("set {}", vector(v)))?;
self.velocity = v;
Ok(())
}
fn on_climbable(&mut self) -> io::Result<bool> {
self.query("climb")?;
let b = self.sequence("climb", self.climb_calls);
self.climb_calls += 1;
Ok(b)
}
fn reset_fall_distance(&mut self) -> io::Result<()> {
self.query("reset")?;
self.fall = 0.0;
Ok(())
}
fn in_scaffolding(&mut self) -> io::Result<bool> {
self.query("in-block")?;
Ok(self.flag("scaffolding"))
}
fn suppressing_ladder_slide(&mut self) -> io::Result<bool> {
self.query("suppress")?;
Ok(self.flag("suppress"))
}
fn is_player_class(&self) -> bool {
self.flag("player")
}
fn move_self(&mut self, v: Vec3) -> io::Result<()> {
self.query(format!("move {}", vector(v)))?;
self.moved = true;
if self.flag("move_mutate") {
self.velocity = vec(&self.f["after_velocity"]);
}
Ok(())
}
fn horizontal_collision(&self) -> bool {
self.flag(if self.moved {
"after_horizontal"
} else {
"horizontal"
})
}
fn jumping(&self) -> bool {
self.flag(if self.moved {
"after_jumping"
} else {
"jumping"
})
}
fn was_in_powder_snow(&self) -> bool {
self.flag(if self.moved { "after_snow" } else { "snow" })
}
fn can_walk_powder_snow(&mut self) -> io::Result<bool> {
self.query("powder-tag")?;
if self.flag("powder_tag") {
Ok(true)
} else {
self.query("feet")?;
Ok(self.flag("boots"))
}
}
fn levitation_amplifier(&mut self) -> io::Result<Option<i32>> {
self.query("levitation")?;
Ok(self.f["levitation"].as_i64().map(|v| v as i32))
}
fn is_client_side(&mut self) -> io::Result<bool> {
self.query("client")?;
Ok(self.flag("client"))
}
fn has_chunk_at(&mut self, p: BlockPos) -> io::Result<bool> {
self.query(format!("chunk {} {} {}", p.x, p.y, p.z))?;
Ok(self.flag("chunk"))
}
fn effective_gravity(&mut self) -> io::Result<f64> {
self.query("gravity")?;
Ok(number(&self.f["gravity"]))
}
fn y(&self) -> f64 {
number(&self.f["y"])
}
fn minimum_y(&mut self) -> io::Result<i32> {
self.query("min-y")?;
Ok(self.f["min_y"].as_i64().unwrap() as i32)
}
fn discard_friction(&mut self) -> io::Result<bool> {
self.query("discard")?;
Ok(self.flag("discard"))
}
fn air_drag_modifier(&mut self) -> io::Result<f64> {
self.query("drag-modifier")?;
Ok(number(&self.f["drag_modifier"]))
}
fn omnidirectional_air_mover(&mut self) -> io::Result<bool> {
self.query("omni")?;
Ok(self.flag("omni"))
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let arg = std::env::args().nth(1).unwrap();
let dir = Path::new(&arg);
let mut out = io::BufWriter::new(fs::File::create(dir.join("rust.txt"))?);
for line in fs::read_to_string(dir.join("inputs.txt"))?.lines() {
let f: Value = serde_json::from_str(line)?;
let mut w = World {
f: &f,
out: &mut out,
calls: 0,
ground_calls: 0,
climb_calls: 0,
velocity: vec(&f["velocity"]),
fall: number(&f["fall"]),
moved: false,
};
let input = vec(&f["input"]);
let friction = single(&f["friction"]);
let result: io::Result<()> = match f["mode"].as_str().unwrap() {
"air" => travel_in_air(&mut w, input),
"relative" => relative_friction_movement(&mut w, input, friction)
.and_then(|v| writeln!(w.out, "vector {}", vector(v))),
"climb" => handle_on_climbable(&mut w, input)
.and_then(|v| writeln!(w.out, "vector {}", vector(v))),
"speed" => friction_influenced_speed(&mut w, friction)
.and_then(|v| writeln!(w.out, "float {:08x}", fbits(v))),
"input" => writeln!(
w.out,
"vector {}",
vector(input_vector(input, single(&f["speed"]), single(&f["yaw"])))
),
"friction" => writeln!(
w.out,
"float {:08x}",
fbits(modified_friction(
friction,
number(&f["friction_modifier"]) as f32
))
),
_ => panic!("unknown mode"),
};
writeln!(
w.out,
"result {}",
if result.is_ok() { "ok" } else { "error" }
)?;
writeln!(w.out, "final {} {:016x}", vector(w.velocity), bits(w.fall))?;
writeln!(w.out, "queries {}", w.calls)?;
}
Ok(())
}
+1
View File
@@ -28,6 +28,7 @@ pub mod ground_support;
pub mod heightmap;
pub mod interaction_shapes;
pub mod liquid_collision;
pub mod living_air;
pub mod living_fall;
pub mod living_landing;
pub mod movement_emission;
+171
View File
@@ -0,0 +1,171 @@
//! LivingEntity walking, climbing and airborne velocity integration.
use horizon_core::{
geometry::{Vec3, trig},
position::BlockPos,
};
pub trait LivingAirWorld {
type Error;
fn movement_support_position(&mut self) -> Result<BlockPos, Self::Error>;
fn on_ground(&mut self) -> Result<bool, Self::Error>;
fn block_friction(&mut self, position: BlockPos) -> Result<f32, Self::Error>;
fn friction_modifier(&mut self) -> Result<f64, Self::Error>;
fn speed(&mut self) -> Result<f32, Self::Error>;
/// Includes entity-type overrides (notably Player).
fn flying_speed(&mut self) -> Result<f32, Self::Error>;
fn yaw(&mut self) -> Result<f32, Self::Error>;
fn velocity(&self) -> Vec3;
fn set_velocity(&mut self, velocity: Vec3) -> Result<(), Self::Error>;
fn on_climbable(&mut self) -> Result<bool, Self::Error>;
fn reset_fall_distance(&mut self) -> Result<(), Self::Error>;
fn in_scaffolding(&mut self) -> Result<bool, Self::Error>;
fn suppressing_ladder_slide(&mut self) -> Result<bool, Self::Error>;
fn is_player_class(&self) -> bool;
/// Bind to Entity.move(SELF, movement), including collision and landing.
fn move_self(&mut self, movement: Vec3) -> Result<(), Self::Error>;
fn horizontal_collision(&self) -> bool;
fn jumping(&self) -> bool;
fn was_in_powder_snow(&self) -> bool;
fn can_walk_powder_snow(&mut self) -> Result<bool, Self::Error>;
fn levitation_amplifier(&mut self) -> Result<Option<i32>, Self::Error>;
fn is_client_side(&mut self) -> Result<bool, Self::Error>;
fn has_chunk_at(&mut self, position: BlockPos) -> Result<bool, Self::Error>;
fn effective_gravity(&mut self) -> Result<f64, Self::Error>;
fn y(&self) -> f64;
fn minimum_y(&mut self) -> Result<i32, Self::Error>;
fn discard_friction(&mut self) -> Result<bool, Self::Error>;
fn air_drag_modifier(&mut self) -> Result<f64, Self::Error>;
fn omnidirectional_air_mover(&mut self) -> Result<bool, Self::Error>;
}
pub fn modified_friction(friction: f32, modifier: f32) -> f32 {
(1.0 - (1.0 - friction) * modifier).clamp(0.0, 1.0)
}
/// Entity.getInputVector: normalize only above unit length, then rotate using
/// the native float-angle sine table. Tiny input returns canonical positive zero.
pub fn input_vector(input: Vec3, speed: f32, yaw: f32) -> Vec3 {
let length = input.length_squared();
if length < 1.0e-7 {
return Vec3::ZERO;
}
let input = if length > 1.0 {
input.normalize()
} else {
input
};
let input = input.scale(f64::from(speed));
let angle = f64::from(yaw * trig::DEG_TO_RAD);
let sin = f64::from(trig::sin(angle));
let cos = f64::from(trig::cos(angle));
Vec3::new(
input.x * cos - input.z * sin,
input.y,
input.z * cos + input.x * sin,
)
}
pub fn move_relative<W: LivingAirWorld>(
world: &mut W,
input: Vec3,
speed: f32,
) -> Result<(), W::Error> {
let input = input_vector(input, speed, world.yaw()?);
let old = world.velocity();
world.set_velocity(Vec3::new(old.x + input.x, old.y + input.y, old.z + input.z))
}
pub fn handle_on_climbable<W: LivingAirWorld>(
world: &mut W,
mut velocity: Vec3,
) -> Result<Vec3, W::Error> {
if world.on_climbable()? {
world.reset_fall_distance()?;
let limit = f64::from(0.15f32);
velocity.x = velocity.x.clamp(-limit, limit);
velocity.z = velocity.z.clamp(-limit, limit);
// Math.max must propagate NaN.
if !velocity.y.is_nan() {
velocity.y = velocity.y.max(-limit);
}
if velocity.y < 0.0
&& !world.in_scaffolding()?
&& world.suppressing_ladder_slide()?
&& world.is_player_class()
{
velocity.y = 0.0;
}
}
Ok(velocity)
}
pub fn friction_influenced_speed<W: LivingAirWorld>(
world: &mut W,
friction: f32,
) -> Result<f32, W::Error> {
if world.on_ground()? {
let speed = world.speed()?;
if f64::from(friction) > 0.6 {
Ok(speed * (0.21600002f32 / (friction * friction * friction)))
} else {
Ok(speed)
}
} else {
world.flying_speed()
}
}
pub fn relative_friction_movement<W: LivingAirWorld>(
world: &mut W,
input: Vec3,
friction: f32,
) -> Result<Vec3, W::Error> {
let speed = friction_influenced_speed(world, friction)?;
move_relative(world, input, speed)?;
let velocity = handle_on_climbable(world, world.velocity())?;
world.set_velocity(velocity)?;
world.move_self(world.velocity())?;
let mut velocity = world.velocity();
if (world.horizontal_collision() || world.jumping())
&& (world.on_climbable()?
|| (world.was_in_powder_snow() && world.can_walk_powder_snow()?))
{
velocity.y = 0.2;
}
Ok(velocity)
}
/// Ground friction is captured before movement; drag and gravity are queried
/// afterwards. This distinction preserves movement callbacks' field changes.
pub fn travel_in_air<W: LivingAirWorld>(world: &mut W, input: Vec3) -> Result<(), W::Error> {
let support = world.movement_support_position()?;
let friction = if world.on_ground()? {
let friction = world.block_friction(support)?;
modified_friction(friction, world.friction_modifier()? as f32)
} else {
1.0
};
let mut velocity = relative_friction_movement(world, input, friction)?;
if let Some(amplifier) = world.levitation_amplifier()? {
velocity.y += (0.05 * f64::from(amplifier.wrapping_add(1)) - velocity.y) * 0.2;
} else if !world.is_client_side()? || world.has_chunk_at(support)? {
velocity.y -= world.effective_gravity()?;
} else {
let y = world.y();
velocity.y = if y > f64::from(world.minimum_y()?) {
-0.1
} else {
0.0
};
}
if !world.discard_friction()? {
let modifier = world.air_drag_modifier()? as f32;
let drag = modified_friction(0.91, modifier);
let horizontal = friction * drag;
let vertical = if world.omnidirectional_air_mover()? {
drag
} else {
modified_friction(0.98, modifier)
};
velocity = Vec3::new(
velocity.x * f64::from(horizontal),
velocity.y * f64::from(vertical),
velocity.z * f64::from(horizontal),
);
}
world.set_velocity(velocity)
}
+18
View File
@@ -836,3 +836,21 @@ water changes, numeric boundaries, particle locations/counts, callback failures,
field mutations and climbing cleanup. Targeted Clippy passes. Fluid immersion,
changed-block enchantments, particle rendering and live gameplay binding remain
pending; those providers are controlled by this gate.
`living_air` implements input normalization/rotation, friction-influenced speed,
ladder/scaffolding limits, relative movement, collision-triggered climbing and
air travel. Ground friction is captured before movement while levitation,
gravity and drag are sampled afterwards. Player class identity controls ladder
slide suppression. Native float arithmetic and quantized trigonometry are kept.
`python3 tools/test_living_air_parity.py` invokes the actual native private air,
relative movement, climbing, speed, friction and input-vector methods. The
[air travel report](../benchmarks/rust-living-air-2026-10-07/scoped-parity.json)
records **443,554 matching lines per JAR**, including both player/nonplayer
classes, changed ground/climbing predicates, missing client chunks, levitation,
nonfinite boundaries, callback mutations and failures. Targeted Clippy passes.
Extreme effect amplifiers are injected directly for integer-boundary checks;
normal constructor clamping is outside this gate. Collision movement, gravity,
attributes and immersion remain controlled providers; live gameplay binding and
complete player travel are pending.
@@ -0,0 +1,84 @@
package dev.horizonlab.parity;
import com.google.gson.*;
import java.io.*;import java.lang.reflect.*;import java.nio.file.*;import java.util.*;
import net.minecraft.core.*;import net.minecraft.tags.*;import net.minecraft.world.entity.*;import net.minecraft.world.entity.ai.attributes.*;import net.minecraft.world.effect.*;import net.minecraft.world.item.*;import net.minecraft.world.level.block.*;import net.minecraft.world.level.block.state.*;import net.minecraft.world.phys.Vec3;
/** Actual native private air travel, relative movement and climbing helpers. */
public final class VanillaLivingAirOracle {
static ItemStack BOOTS;static Field amplifier;
static MobEffectInstance effect(Data d,Holder<MobEffect> type){if(d.f.get("levitation").isJsonNull())return null;var e=new MobEffectInstance(type,100,0);try{amplifier.setInt(e,d.f.get("levitation").getAsInt());}catch(ReflectiveOperationException ex){throw new AssertionError(ex);}return e;}
static final class Stop extends RuntimeException {}
static double number(JsonElement v){return Double.longBitsToDouble(Long.parseUnsignedLong(v.getAsString(),16));}
static float single(JsonElement v){return Float.intBitsToFloat(Integer.parseUnsignedInt(v.getAsString(),16));}
static Vec3 vec(JsonElement v){var a=v.getAsJsonArray();return new Vec3(number(a.get(0)),number(a.get(1)),number(a.get(2)));}
static String vector(Vec3 v){return String.format("%016x %016x %016x",Double.doubleToLongBits(v.x),Double.doubleToLongBits(v.y),Double.doubleToLongBits(v.z));}
static final class Data {JsonObject f;PrintWriter out;int calls,groundCalls,climbCalls;Vec3 velocity;
void query(String s){out.println(s);if(calls++==f.get("fail").getAsInt())throw new Stop();}
boolean flag(String k){return f.get(k).getAsBoolean();}
boolean sequence(String k,int n){var a=f.getAsJsonArray(k);return a.get(Math.min(n,a.size()-1)).getAsBoolean();}}
static final class FrictionBlock extends Block {Data d;FrictionBlock(){super(BlockBehaviour.Properties.of());}@Override public float getFriction(){d.query("friction");return single(d.f.get("friction"));}}
static final class State extends BlockState {Block block;State(){super(null,null,null);}@Override public Block getBlock(){return block;}}
static final class Level extends net.minecraft.server.level.ServerLevel {Data d;BlockState state;Level(){super(null,null,null,null,null,null,false,0L,List.of(),false);}
@Override public BlockState getBlockState(BlockPos p){d.query("state "+p.getX()+" "+p.getY()+" "+p.getZ());return state;}
@Override public boolean isClientSide(){d.query("client");return d.flag("client");}
@Override public boolean hasChunkAt(BlockPos p){d.query("chunk "+p.getX()+" "+p.getY()+" "+p.getZ());return d.flag("chunk");}
@Override public int getMinY(){d.query("min-y");return d.f.get("min_y").getAsInt();}}
static final class Actor extends net.minecraft.world.entity.decoration.ArmorStand {Actor(){super(null,null);}
Data d;
void configure(Level l){setLevel(l);}
@Override public BlockPos getBlockPosBelowThatAffectsMyMovement(){d.query("support");return new BlockPos(17,-64,-33);}
@Override public boolean onGround(){d.query("ground");return d.sequence("ground",d.groundCalls++);}
@Override public double getAttributeValue(Holder<Attribute> attribute){String n=attribute==Attributes.FRICTION_MODIFIER?"friction":attribute==Attributes.AIR_DRAG_MODIFIER?"drag":null;if(n==null)throw new AssertionError(attribute);d.query(n+"-modifier");return number(d.f.get(n+"_modifier"));}
@Override public float getSpeed(){d.query("speed");return single(d.f.get("speed"));}
@Override protected float getFlyingSpeed(){d.query("flying-speed");return single(d.f.get("flying_speed"));}
@Override public float getYRot(){d.query("yaw");if(d.flag("yaw_mutate"))d.velocity=new Vec3(17,18,19);return single(d.f.get("yaw"));}
@Override public Vec3 getDeltaMovement(){return d.velocity;}
@Override public void setDeltaMovement(Vec3 v){d.query("set "+vector(v));d.velocity=v;}
@Override public boolean onClimbable(){d.query("climb");return d.sequence("climb",d.climbCalls++);}
@Override public void resetFallDistance(){d.query("reset");fallDistance=0;}
@Override public BlockState getInBlockState(){d.query("in-block");return (d.flag("scaffolding")?Blocks.SCAFFOLDING:Blocks.STONE).defaultBlockState();}
@Override public boolean isSuppressingSlidingDownLadder(){d.query("suppress");return d.flag("suppress");}
@Override public void move(MoverType type,Vec3 v){if(type!=MoverType.SELF)throw new AssertionError(type);d.query("move "+vector(v));horizontalCollision=d.flag("after_horizontal");jumping=d.flag("after_jumping");wasInPowderSnow=d.flag("after_snow");if(d.flag("move_mutate"))d.velocity=vec(d.f.get("after_velocity"));}
@Override public boolean is(TagKey<EntityType<?>> tag){if(tag!=EntityTypeTags.POWDER_SNOW_WALKABLE_MOBS)throw new AssertionError(tag);d.query("powder-tag");return d.flag("powder_tag");}
@Override public ItemStack getItemBySlot(EquipmentSlot slot){if(slot!=EquipmentSlot.FEET)throw new AssertionError(slot);d.query("feet");return d.flag("boots")?BOOTS:ItemStack.EMPTY;}
@Override public MobEffectInstance getEffect(Holder<MobEffect> effect){if(effect!=MobEffects.LEVITATION)throw new AssertionError(effect);d.query("levitation");return effect(d,effect);}
@Override protected double getEffectiveGravity(){d.query("gravity");return number(d.f.get("gravity"));}
@Override public boolean shouldDiscardFriction(){d.query("discard");return d.flag("discard");}
@Override protected boolean omnidirectionalAirMover(){d.query("omni");return d.flag("omni");}
}
static final class Human extends net.minecraft.world.entity.player.Player {Human(){super(null,null);}
Data d;
void configure(Level l){setLevel(l);}
@Override public BlockPos getBlockPosBelowThatAffectsMyMovement(){d.query("support");return new BlockPos(17,-64,-33);}
@Override public boolean onGround(){d.query("ground");return d.sequence("ground",d.groundCalls++);}
@Override public double getAttributeValue(Holder<Attribute> attribute){String n=attribute==Attributes.FRICTION_MODIFIER?"friction":attribute==Attributes.AIR_DRAG_MODIFIER?"drag":null;if(n==null)throw new AssertionError(attribute);d.query(n+"-modifier");return number(d.f.get(n+"_modifier"));}
@Override public float getSpeed(){d.query("speed");return single(d.f.get("speed"));}
@Override protected float getFlyingSpeed(){d.query("flying-speed");return single(d.f.get("flying_speed"));}
@Override public float getYRot(){d.query("yaw");if(d.flag("yaw_mutate"))d.velocity=new Vec3(17,18,19);return single(d.f.get("yaw"));}
@Override public Vec3 getDeltaMovement(){return d.velocity;}
@Override public void setDeltaMovement(Vec3 v){d.query("set "+vector(v));d.velocity=v;}
@Override public boolean onClimbable(){d.query("climb");return d.sequence("climb",d.climbCalls++);}
@Override public void resetFallDistance(){d.query("reset");fallDistance=0;}
@Override public BlockState getInBlockState(){d.query("in-block");return (d.flag("scaffolding")?Blocks.SCAFFOLDING:Blocks.STONE).defaultBlockState();}
@Override public boolean isSuppressingSlidingDownLadder(){d.query("suppress");return d.flag("suppress");}
@Override public void move(MoverType type,Vec3 v){if(type!=MoverType.SELF)throw new AssertionError(type);d.query("move "+vector(v));horizontalCollision=d.flag("after_horizontal");jumping=d.flag("after_jumping");wasInPowderSnow=d.flag("after_snow");if(d.flag("move_mutate"))d.velocity=vec(d.f.get("after_velocity"));}
@Override public boolean is(TagKey<EntityType<?>> tag){if(tag!=EntityTypeTags.POWDER_SNOW_WALKABLE_MOBS)throw new AssertionError(tag);d.query("powder-tag");return d.flag("powder_tag");}
@Override public ItemStack getItemBySlot(EquipmentSlot slot){if(slot!=EquipmentSlot.FEET)throw new AssertionError(slot);d.query("feet");return d.flag("boots")?BOOTS:ItemStack.EMPTY;}
@Override public MobEffectInstance getEffect(Holder<MobEffect> effect){if(effect!=MobEffects.LEVITATION)throw new AssertionError(effect);d.query("levitation");return effect(d,effect);}
@Override protected double getEffectiveGravity(){d.query("gravity");return number(d.f.get("gravity"));}
@Override public boolean shouldDiscardFriction(){d.query("discard");return d.flag("discard");}
@Override protected boolean omnidirectionalAirMover(){d.query("omni");return d.flag("omni");}
@Override public net.minecraft.world.level.GameType gameMode(){return net.minecraft.world.level.GameType.SURVIVAL;}
}
static Method method(Class<?> owner,String name,Class<?>... args)throws Exception{var m=owner.getDeclaredMethod(name,args);m.setAccessible(true);return m;}
public static void main(String[] args)throws Exception{
net.minecraft.SharedConstants.tryDetectVersion();net.minecraft.server.Bootstrap.bootStrap();var u=Class.forName("sun.misc.Unsafe");var uf=u.getDeclaredField("theUnsafe");uf.setAccessible(true);var unsafe=uf.get(null);var allocate=u.getMethod("allocateInstance",Class.class);
amplifier=MobEffectInstance.class.getDeclaredField("amplifier");amplifier.setAccessible(true);BOOTS=(ItemStack)allocate.invoke(unsafe,ItemStack.class);var stackItem=ItemStack.class.getDeclaredField("item");stackItem.setAccessible(true);stackItem.set(BOOTS,Items.LEATHER_BOOTS.builtInRegistryHolder());var stackCount=ItemStack.class.getDeclaredField("count");stackCount.setAccessible(true);stackCount.setInt(BOOTS,1);
var air=method(LivingEntity.class,"travelInAir",Vec3.class);var relative=method(LivingEntity.class,"handleRelativeFrictionAndCalculateMovement",Vec3.class,float.class);var climb=method(LivingEntity.class,"handleOnClimbable",Vec3.class);var speed=method(LivingEntity.class,"getFrictionInfluencedSpeed",float.class);var input=method(Entity.class,"getInputVector",Vec3.class,float.class,float.class);var friction=method(LivingEntity.class,"computeModifiedFriction",float.class,float.class);var position=Entity.class.getDeclaredField("position");position.setAccessible(true);var jumping=LivingEntity.class.getDeclaredField("jumping");jumping.setAccessible(true);Path dir=Path.of(args[1]);
try(var out=new PrintWriter(Files.newBufferedWriter(dir.resolve(args[0]+".txt")));var lines=Files.lines(dir.resolve("inputs.txt"))){for(var line:(Iterable<String>)lines::iterator){
var f=JsonParser.parseString(line).getAsJsonObject();var d=new Data();d.f=f;d.out=out;d.velocity=vec(f.get("velocity"));var level=(Level)allocate.invoke(unsafe,Level.class);level.d=d;var block=(FrictionBlock)allocate.invoke(unsafe,FrictionBlock.class);block.d=d;var state=(State)allocate.invoke(unsafe,State.class);state.block=block;level.state=state;
LivingEntity entity;if(d.flag("player")){var e=(Human)allocate.invoke(unsafe,Human.class);e.d=d;e.configure(level);entity=e;}else{var e=(Actor)allocate.invoke(unsafe,Actor.class);e.d=d;e.configure(level);entity=e;}position.set(entity,new Vec3(0,number(f.get("y")),0));entity.fallDistance=number(f.get("fall"));entity.horizontalCollision=d.flag("horizontal");jumping.setBoolean(entity,d.flag("jumping"));entity.wasInPowderSnow=d.flag("snow");
try{Object result=switch(f.get("mode").getAsString()){case "air"->air.invoke(entity,vec(f.get("input")));case "relative"->relative.invoke(entity,vec(f.get("input")),single(f.get("friction")));case "climb"->climb.invoke(entity,vec(f.get("input")));case "speed"->speed.invoke(entity,single(f.get("friction")));case "input"->input.invoke(null,vec(f.get("input")),single(f.get("speed")),single(f.get("yaw")));case "friction"->friction.invoke(null,single(f.get("friction")),(float)number(f.get("friction_modifier")));default->throw new AssertionError();};if(result instanceof Vec3 v)out.println("vector "+vector(v));else if(result instanceof Float v)out.printf("float %08x%n",Float.floatToIntBits(v));out.println("result ok");}catch(InvocationTargetException e){if(e.getCause() instanceof Stop)out.println("result error");else throw e;}
out.printf("final %s %016x%n",vector(d.velocity),Double.doubleToLongBits(entity.fallDistance));out.println("queries "+d.calls);
}}
}
}
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""Compare LivingEntity air travel, climbing and input movement with vanilla."""
import argparse
import json
import os
from pathlib import Path
import platform
import subprocess
import random
import struct
import math
try:
from . import lab, test_rust_parity as base
except ImportError:
import lab
import test_rust_parity as base
def corpus():
def bits(v):return struct.pack('>d',float(v)).hex()
def single(v):return struct.pack('>f',float(v)).hex()
def row(**kw):
f=dict(mode='air',input=[.4,0,.8],velocity=[.1,-.08,-.2],after_velocity=[.3,-.6,.9],fall=6,friction=.6,friction_modifier=1,drag_modifier=1,speed=.1,flying_speed=.02,yaw=37,ground=[True,True],climb=[False,False],scaffolding=False,suppress=False,player=False,horizontal=False,jumping=False,snow=False,after_horizontal=False,after_jumping=False,after_snow=False,powder_tag=False,boots=False,levitation=None,client=False,chunk=True,gravity=.08,y=64,min_y=-64,discard=False,omni=False,yaw_mutate=False,move_mutate=False,fail=-1)
f.update(kw)
for k in ['input','velocity','after_velocity']:f[k]=[bits(v) for v in f[k]]
for k in ['fall','friction_modifier','drag_modifier','gravity','y']:f[k]=bits(f[k])
for k in ['friction','speed','flying_speed','yaw']:f[k]=single(f[k])
return f
vals=[-float('inf'),-1e30,-1,-.15,-1e-40,-0.0,0,1e-40,.02,.1,.15,.6,.91,.98,1,2,1e30,float('inf'),float('nan')]
for friction in vals:
for modifier in vals:yield row(mode='friction',friction=friction,friction_modifier=modifier)
for friction in vals+[.59999996,.60000002]:
for speed in vals:
for ground in [False,True]:yield row(mode='speed',friction=friction,speed=speed,flying_speed=speed,ground=[ground])
vectors=[[0,0,0],[-0.0,-0.0,-0.0],[.0001,0,0],[math.sqrt(1e-7),0,0],[1,0,0],[0,0,1],[1,1,1],[float('inf'),0,0],[float('nan'),.1,0],[0,-.15000000596046448,0],[0,-float('inf'),0]]
for i in range(4096):yield row(mode='input',yaw=i*360/4096,input=[.7,.3,-.8])
for v in vectors:
for yaw in vals+[90,180,270,360,-360]:
for speed in [.1,-0.0,float('inf'),float('nan')]:yield row(mode='input',input=v,yaw=yaw,speed=speed)
for v in vectors+[[.5,-.7,-.5],[0,-0.0,0]]:
for climb in [False,True]:
for player in [False,True]:
for scaffolding in [False,True]:
for suppress in [False,True]:
for fail in range(-1,5):yield row(mode='climb',input=v,climb=[climb],player=player,scaffolding=scaffolding,suppress=suppress,fail=fail)
for ground in [[False],[True],[True,False],[False,True]]:
for climb in [[False],[True],[False,True],[True,False]]:
for bits_mask in range(256):
flags={k:bool(bits_mask&(1<<i)) for i,k in enumerate(['player','scaffolding','suppress','after_horizontal','after_jumping','after_snow','powder_tag','boots'])}
yield row(mode='relative',ground=ground,climb=climb,**flags)
for levitation in [None,0,1,255,2147483647]:
for client in [False,True]:
for chunk in [False,True]:
for y in [-float('inf'),-64,-63,0,float('inf'),float('nan')]:
for discard in [False,True]:
for omni in [False,True]:
for fail in range(-1,24):yield row(levitation=levitation,client=client,chunk=chunk,y=y,discard=discard,omni=omni,fail=fail,move_mutate=True,yaw_mutate=True,climb=[True],after_horizontal=True,player=True,suppress=True)
rng=random.Random(0x414952)
flags=['player','scaffolding','suppress','horizontal','jumping','snow','after_horizontal','after_jumping','after_snow','powder_tag','boots','client','chunk','discard','omni','yaw_mutate','move_mutate']
for _ in range(12000):
f={k:bool(rng.randrange(2)) for k in flags}
for k in ['friction','speed','flying_speed','friction_modifier','drag_modifier','gravity','yaw']:f[k]=rng.choice(vals) if rng.randrange(3)==0 else rng.uniform(-2,2)
yield row(**f,input=rng.choice(vectors),velocity=rng.choice(vectors),after_velocity=rng.choice(vectors),ground=[bool(rng.randrange(2)),bool(rng.randrange(2))],climb=[bool(rng.randrange(2)),bool(rng.randrange(2))],levitation=rng.choice([None,None,0,1,255,2147483647]),fail=rng.choice([-1,-1,*range(24)]))
def main():
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--prepare',action='store_true');args=parser.parse_args()
build=lab.LOCAL/'rust-living-air-parity';build.mkdir(parents=True,exist_ok=True)
report_path=build/'report.json';report_path.unlink(missing_ok=True)
if args.prepare:lab.prepare()
lock,jars,libraries=base.verify_artifacts()
oracle=lab.ROOT/'mods/horizon/src/test/java/dev/horizonlab/parity/VanillaLivingAirOracle.java'
sources=[oracle,Path(__file__),lab.ROOT/'tools/test_rust_parity.py',lab.ROOT/'tools/lab.py',lab.ROOT/'Cargo.toml',lab.ROOT/'Cargo.lock',lab.ROOT/'crates/horizon-core/Cargo.toml',lab.ROOT/'crates/horizon-world/Cargo.toml',*sorted((lab.ROOT/'crates/horizon-core/src').rglob('*.rs')),*sorted((lab.ROOT/'crates/horizon-world/src').rglob('*.rs')),lab.ROOT/'crates/horizon-world/examples/living_air_fixture.rs']
tested_sources=base.source_hashes(sources)
classes=build/'classes';classes.mkdir(exist_ok=True)
def run(command,name):
with (build/(name+'.log')).open('w',encoding='utf-8') as log:base.run(list(map(str,command)),stdout=log,stderr=subprocess.STDOUT)
dependency_path=os.pathsep.join(map(str,libraries))
run(['javac','--release',lock['minecraft']['java_major'],'-proc:none','-cp',str(jars['server'])+os.pathsep+dependency_path,'-d',classes,oracle],'compile-java')
def java(side,mode,path):
run(['java','-Xmx512M','-cp',os.pathsep.join([str(classes),str(jars[side]),dependency_path]),'dev.horizonlab.parity.VanillaLivingAirOracle',mode,path],side+'-'+mode)
fixtures=list(corpus());inputs=build/'inputs.txt';inputs.write_text(''.join(json.dumps(value,separators=(',',':'))+'\n' for value in fixtures),encoding='utf-8')
fixture_paths=[inputs];tested_fixtures=base.source_hashes(fixture_paths)
run(['cargo','build','--release','-p','horizon-world','--example','living_air_fixture'],'compile-rust')
metadata=json.loads(subprocess.check_output(['cargo','metadata','--no-deps','--format-version','1'],cwd=lab.ROOT,text=True))
binary=Path(metadata['target_directory'])/'release/examples'/('living_air_fixture.exe' if os.name=='nt' else 'living_air_fixture')
run([binary,build],'rust');references=[]
for side,jar in jars.items():
java(side,side,build);reference=build/f'{side}.txt';matched=base.compare(reference,build/'rust.txt')
references.append({'side':side,'jar_sha256':lab.digest(jar,'sha256'),'output_sha256':lab.digest(reference,'sha256'),'matched_output_lines':matched})
print(f'{side}: {matched:,} living-air output lines match Rust',flush=True)
base.ensure_sources_unchanged(sources,tested_sources);base.ensure_sources_unchanged(fixture_paths,tested_fixtures)
report={'schema':1,'minecraft':lock['minecraft']['version'],'manifest_sha1':lock['minecraft']['manifest_sha1'],'platform':platform.platform(),'java':subprocess.check_output(['java','--version'],text=True).splitlines()[0],'rustc':subprocess.check_output(['rustc','--version'],text=True).strip(),'fixtures':len(fixtures),'sources_sha256':tested_sources,'fixtures_sha256':tested_fixtures,'rust_output_sha256':lab.digest(build/'rust.txt','sha256'),'references':references,'scope':'Actual LivingEntity.travelInAir, handleRelativeFrictionAndCalculateMovement, handleOnClimbable, getFrictionInfluencedSpeed, computeModifiedFriction and Entity.getInputVector. Traces native moveRelative and state writes, both Player/nonplayer ladder guards, registered scaffolding/boots checks, levitation, missing client chunks, float friction/drag, callback mutations and failures. Entity.move, effective gravity, ground/climb predicates and attributes use controlled providers; live world integration and complete player travel remain pending.'}
lab.write_json(report_path,report);print(f'Scoped living air parity passed: {report_path}')
if __name__=='__main__':main()