Match lazy block collision scanning and provider query order
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
{
|
||||
"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": 4176,
|
||||
"sources_sha256": {
|
||||
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaBlockCollisionScanOracle.java": "ee34da34195df5a0cdd4a24a4faf7154200b674d6523eba4700381439d556b2d",
|
||||
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaFaceSupportOracle.java": "9ce939a435842867786fed648951bbe77f6ab843f6df09af15f3deb1948c4877",
|
||||
"tools/test_block_collision_scan_parity.py": "5289ba6c555367d4dbfe7cbf8e577705c16a8426dfcc431c787aeed3e513970d",
|
||||
"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/mod.rs": "dc92f73885dd0a7760743bf74f1ab8afa839d61cef2dfef890f8a23b67b4742e",
|
||||
"crates/horizon-core/src/geometry/movement.rs": "930e34abef6f6eeec1ee7a6c920b5ba01bfe37b90678884490f4be53241f6b96",
|
||||
"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": "5d0f5ded49d34bb999d73a4e1b89a318fa66c0246e9904d3cbf810d3aa370312",
|
||||
"crates/horizon-world/src/block_collision_scan.rs": "20802862364c110ff85eeaf48606596a8468b83768dda46b412d337958790b41",
|
||||
"crates/horizon-world/src/block_entities.rs": "a9deae92e6e5a1fcf4f0476c33ea4d170ddad6fd4b3303e1bb66d933973d5e06",
|
||||
"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/entity_obstruction.rs": "a4b28a19bf83b23611c59d94535c488db37e4aee24b22c973c545910894a809f",
|
||||
"crates/horizon-world/src/fluid.rs": "a0a1f34ba94d8b59dc975becee8952960764d67ae08cf2d6a8bcd40a614b15c4",
|
||||
"crates/horizon-world/src/heightmap.rs": "a5edef082b5af40d814421ea17e129b3b06d70abee6434ed263e4bba58571698",
|
||||
"crates/horizon-world/src/lib.rs": "3f574287b721b86f39d976d98a69b632b87658cd38f4a7dc0e6c1b6623d5a6a3",
|
||||
"crates/horizon-world/src/liquid_collision.rs": "0f0a83b04e5a5bc9d98ed05fde4d6584ba69642e93522e726e4cfc325d6fcb1d",
|
||||
"crates/horizon-world/src/main.rs": "fce57418b8c22a6a0a9044baa89ed3d9c243bc2e8413fea3ff0f32985daba021",
|
||||
"crates/horizon-world/src/nbt.rs": "60262c3de8c8f68bc2da0370ccb17393d32b85f5f5022c6358599a7d32119ea6",
|
||||
"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/retrogen.rs": "6efd36a6293756688c1990a7965bd65609d7c5e2bf2a5f4f01d54932d2b9386b",
|
||||
"crates/horizon-world/src/tick_data.rs": "f8d04a69ea263f4168bce33f92e5b4ee2fe07d7caf50a1621c6b3ef6eb2479f3",
|
||||
"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/block_collision_scan_fixture.rs": "509420fc9601ece4ad17d4eec67a2d2ad4de0c653c55cbf01ba746a354575f17"
|
||||
},
|
||||
"fixtures_sha256": {
|
||||
".local/rust-block-collision-scan-parity/inputs.txt": "d87e1a985430aab7a9fd77e6f3a70e4810d19241c74a9fe8c324348d5c0737dc"
|
||||
},
|
||||
"rust_output_sha256": "f975369ad065b5417dbeacbfa554fc3f27ddaa4f2e634e57f5380e070b355d72",
|
||||
"references": [
|
||||
{
|
||||
"side": "client",
|
||||
"jar_sha256": "4508d006323f24fa02876310c192d739af56516eb259000ac50f0909a68c9a2d",
|
||||
"output_sha256": "f975369ad065b5417dbeacbfa554fc3f27ddaa4f2e634e57f5380e070b355d72",
|
||||
"matched_output_lines": 517820
|
||||
},
|
||||
{
|
||||
"side": "server",
|
||||
"jar_sha256": "a362163eec5d1612d520772bc16e5b39c09e3b234fdc045f56bf544284ee8ae6",
|
||||
"output_sha256": "f975369ad065b5417dbeacbfa554fc3f27ddaa4f2e634e57f5380e070b355d72",
|
||||
"matched_output_lines": 517820
|
||||
}
|
||||
],
|
||||
"scope": "Actual BlockCollisions cursor and selection algorithm over controlled block metadata, chunk providers and context shapes. Compares ordered chunk/state/suffocation/shape calls, missing-chunk retries, cached chunk reuse, face/edge/corner filtering, canonical full-block versus equal noncanonical shape behavior, exact emitted shape data, early consumer termination and injected provider failures. Finite bounded scans include thin/zero-size boxes, chunk crossings and wrapped integer positions. Registry-specific metadata/shape dispatch, live chunk loading and entity movement are separate integration work; unsupported cursor volumes and caller budgets use typed Rust errors."
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
use horizon_core::{
|
||||
geometry::{Aabb, Axis, ShapeOp, Vec3, VoxelShape},
|
||||
position::{BlockPos, ChunkPos},
|
||||
};
|
||||
use horizon_world::{
|
||||
block_collision_scan::{BlockCollisionScan, BlockCollisionWorld, CollisionBlock},
|
||||
collision_context::CollisionContext,
|
||||
registry::BlockStateId,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fs,
|
||||
io::{self, Write},
|
||||
path::Path,
|
||||
rc::Rc,
|
||||
};
|
||||
fn number(v: &Value) -> f64 {
|
||||
f64::from_bits(u64::from_str_radix(v.as_str().unwrap(), 16).unwrap())
|
||||
}
|
||||
fn values(
|
||||
out: &mut impl Write,
|
||||
label: &str,
|
||||
values: impl IntoIterator<Item = f64>,
|
||||
) -> io::Result<()> {
|
||||
write!(out, "{label}")?;
|
||||
for v in values {
|
||||
let bits = if v.is_nan() {
|
||||
0x7ff8_0000_0000_0000
|
||||
} else {
|
||||
v.to_bits()
|
||||
};
|
||||
write!(out, " {bits:016x}")?;
|
||||
}
|
||||
writeln!(out)
|
||||
}
|
||||
fn box_values(out: &mut impl Write, label: &str, b: Aabb) -> io::Result<()> {
|
||||
values(
|
||||
out,
|
||||
label,
|
||||
[
|
||||
b.min(Axis::X),
|
||||
b.min(Axis::Y),
|
||||
b.min(Axis::Z),
|
||||
b.max(Axis::X),
|
||||
b.max(Axis::Y),
|
||||
b.max(Axis::Z),
|
||||
],
|
||||
)
|
||||
}
|
||||
fn emit(out: &mut impl Write, shape: &VoxelShape) -> io::Result<()> {
|
||||
writeln!(
|
||||
out,
|
||||
"shape {} {} {}",
|
||||
shape.is_empty(),
|
||||
shape.boxes().len(),
|
||||
shape.is_cube()
|
||||
)?;
|
||||
for (axis, name) in Axis::ALL.into_iter().zip(["x", "y", "z"]) {
|
||||
values(out, name, shape.coordinates(axis).iter().copied())?;
|
||||
}
|
||||
let axes = shape.cube_coordinate_axes();
|
||||
writeln!(
|
||||
out,
|
||||
"axes {}",
|
||||
u8::from(axes[0]) + 2 * u8::from(axes[1]) + 4 * u8::from(axes[2])
|
||||
)?;
|
||||
values(
|
||||
out,
|
||||
"extrema",
|
||||
Axis::ALL
|
||||
.map(|a| shape.min(a))
|
||||
.into_iter()
|
||||
.chain(Axis::ALL.map(|a| shape.max(a))),
|
||||
)?;
|
||||
match shape.bounds() {
|
||||
Some(b) => box_values(out, "bounds", b)?,
|
||||
None => writeln!(out, "bounds none")?,
|
||||
}
|
||||
for b in shape.boxes() {
|
||||
box_values(out, "box", *b)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn shape(index: u64) -> VoxelShape {
|
||||
let cuboid = |min, max| VoxelShape::from_box(Aabb::new(min, max)).unwrap();
|
||||
match index {
|
||||
0 => VoxelShape::empty(),
|
||||
1 => VoxelShape::block(),
|
||||
2 => VoxelShape::block().moved(Vec3::ZERO),
|
||||
3 => cuboid(Vec3::ZERO, Vec3::new(1.0, 0.5, 1.0)),
|
||||
4 => cuboid(Vec3::new(-0.25, -0.5, -0.25), Vec3::new(1.25, 1.5, 1.25)),
|
||||
5 => cuboid(Vec3::ZERO, Vec3::new(1e-8, 1.0, 1.0)),
|
||||
6 => cuboid(Vec3::ZERO, Vec3::new(0.25, 1.0, 0.25))
|
||||
.join(
|
||||
&cuboid(Vec3::new(0.75, 0.0, 0.75), Vec3::new(1.0, 1.0, 1.0)),
|
||||
ShapeOp::OR,
|
||||
)
|
||||
.unwrap(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
struct Entry {
|
||||
block: CollisionBlock,
|
||||
shape: VoxelShape,
|
||||
suffocating: bool,
|
||||
}
|
||||
struct World<W> {
|
||||
out: Rc<RefCell<W>>,
|
||||
calls: i32,
|
||||
fail: i32,
|
||||
missing: i32,
|
||||
seed: i32,
|
||||
palette: Vec<Entry>,
|
||||
}
|
||||
impl<W: Write> World<W> {
|
||||
fn query(&mut self, value: &str) -> io::Result<()> {
|
||||
writeln!(self.out.borrow_mut(), "{value}")?;
|
||||
let index = self.calls;
|
||||
self.calls += 1;
|
||||
if index == self.fail {
|
||||
return Err(io::Error::other("injected collision scan failure"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<W: Write> BlockCollisionWorld for World<W> {
|
||||
type Error = io::Error;
|
||||
type Chunk = ChunkPos;
|
||||
fn collision_chunk(&mut self, p: ChunkPos) -> io::Result<Option<ChunkPos>> {
|
||||
self.query(&format!("chunk {} {}", p.x, p.z))?;
|
||||
Ok(
|
||||
if self.missing == 1 || self.missing == 2 && (p.x ^ p.z) & 1 != 0 {
|
||||
None
|
||||
} else {
|
||||
Some(p)
|
||||
},
|
||||
)
|
||||
}
|
||||
fn collision_block(&mut self, chunk: ChunkPos, p: BlockPos) -> io::Result<CollisionBlock> {
|
||||
assert_eq!(chunk, p.chunk());
|
||||
self.query(&format!("block {} {} {}", p.x, p.y, p.z))?;
|
||||
let hash =
|
||||
p.x.wrapping_mul(3)
|
||||
.wrapping_add(p.y.wrapping_mul(5))
|
||||
.wrapping_add(p.z.wrapping_mul(7))
|
||||
.wrapping_add(self.seed)
|
||||
& i32::MAX;
|
||||
Ok(self.palette[hash as usize % self.palette.len()].block)
|
||||
}
|
||||
fn is_suffocating(
|
||||
&mut self,
|
||||
chunk: ChunkPos,
|
||||
block: CollisionBlock,
|
||||
p: BlockPos,
|
||||
) -> io::Result<bool> {
|
||||
assert_eq!(chunk, p.chunk());
|
||||
self.query(&format!(
|
||||
"suffocating {} {} {} {}",
|
||||
p.x, p.y, p.z, block.state.0
|
||||
))?;
|
||||
Ok(self.palette[block.state.0 as usize].suffocating)
|
||||
}
|
||||
fn context_shape(
|
||||
&mut self,
|
||||
block: CollisionBlock,
|
||||
p: BlockPos,
|
||||
_: &CollisionContext<'_>,
|
||||
) -> io::Result<VoxelShape> {
|
||||
self.query(&format!("shape {} {} {} {}", p.x, p.y, p.z, block.state.0))?;
|
||||
Ok(self.palette[block.state.0 as usize].shape.clone())
|
||||
}
|
||||
}
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let arg = std::env::args().nth(1).expect("private fixture directory");
|
||||
let dir = Path::new(&arg);
|
||||
let out = Rc::new(RefCell::new(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 palette = f["palette"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| Entry {
|
||||
block: CollisionBlock {
|
||||
state: BlockStateId(i as u32),
|
||||
large_collision_shape: v[1].as_bool().unwrap(),
|
||||
moving_piston: v[2].as_bool().unwrap(),
|
||||
},
|
||||
shape: shape(v[0].as_u64().unwrap()),
|
||||
suffocating: v[3].as_bool().unwrap(),
|
||||
})
|
||||
.collect();
|
||||
let mut world = World {
|
||||
out: out.clone(),
|
||||
calls: 0,
|
||||
fail: f["fail"].as_i64().unwrap() as i32,
|
||||
missing: f["missing"].as_i64().unwrap() as i32,
|
||||
seed: f["seed"].as_i64().unwrap() as i32,
|
||||
palette,
|
||||
};
|
||||
let v = &f["box"];
|
||||
let bounds = Aabb::new(
|
||||
Vec3::new(number(&v[0]), number(&v[1]), number(&v[2])),
|
||||
Vec3::new(number(&v[3]), number(&v[4]), number(&v[5])),
|
||||
);
|
||||
let mut hits = 0;
|
||||
{
|
||||
let mut scan = BlockCollisionScan::new(
|
||||
&mut world,
|
||||
CollisionContext::empty(false),
|
||||
bounds,
|
||||
f["suffocating"].as_bool().unwrap(),
|
||||
1_000_000,
|
||||
)?;
|
||||
for _ in 0..f["limit"].as_u64().unwrap() {
|
||||
match scan.next() {
|
||||
None => break,
|
||||
Some(Ok(hit)) => {
|
||||
let p = hit.position;
|
||||
writeln!(out.borrow_mut(), "hit {} {} {}", p.x, p.y, p.z)?;
|
||||
emit(&mut *out.borrow_mut(), &hit.shape)?;
|
||||
hits += 1;
|
||||
}
|
||||
Some(Err(_)) => {
|
||||
writeln!(out.borrow_mut(), "error")?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
writeln!(out.borrow_mut(), "done {hits} {}", world.calls)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
//! Lazy block collision selection in vanilla cursor/query order. Providers own
|
||||
//! chunk availability, state metadata, suffocation predicates and context dispatch.
|
||||
use crate::{collision_context::CollisionContext, registry::BlockStateId};
|
||||
use horizon_core::{
|
||||
geometry::{Aabb, ShapeError, ShapeOp, Vec3, VoxelShape},
|
||||
position::{BlockPos, ChunkPos},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct CollisionBlock {
|
||||
pub state: BlockStateId,
|
||||
pub large_collision_shape: bool,
|
||||
pub moving_piston: bool,
|
||||
}
|
||||
|
||||
pub trait BlockCollisionWorld {
|
||||
type Error;
|
||||
type Chunk: Copy;
|
||||
/// None is a missing collision chunk; native iteration retries missing chunks.
|
||||
fn collision_chunk(&mut self, position: ChunkPos) -> Result<Option<Self::Chunk>, Self::Error>;
|
||||
fn collision_block(
|
||||
&mut self,
|
||||
chunk: Self::Chunk,
|
||||
position: BlockPos,
|
||||
) -> Result<CollisionBlock, Self::Error>;
|
||||
fn is_suffocating(
|
||||
&mut self,
|
||||
chunk: Self::Chunk,
|
||||
block: CollisionBlock,
|
||||
position: BlockPos,
|
||||
) -> Result<bool, Self::Error>;
|
||||
/// Query against the global collision world, not the cached chunk provider.
|
||||
/// Shapes must preserve canonical block identity (including imported shapes).
|
||||
fn context_shape(
|
||||
&mut self,
|
||||
block: CollisionBlock,
|
||||
position: BlockPos,
|
||||
context: &CollisionContext<'_>,
|
||||
) -> Result<VoxelShape, Self::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CollisionScanError<E> {
|
||||
InvalidBounds,
|
||||
TooLarge,
|
||||
VisitBudget,
|
||||
World(E),
|
||||
Shape(ShapeError),
|
||||
}
|
||||
impl<E: std::fmt::Display> std::fmt::Display for CollisionScanError<E> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InvalidBounds => f.write_str("collision scan bounds must be finite"),
|
||||
Self::TooLarge => {
|
||||
f.write_str("collision scan exceeds the positive Java-int cursor domain")
|
||||
}
|
||||
Self::VisitBudget => f.write_str("collision scan candidate budget exhausted"),
|
||||
Self::World(error) => error.fmt(f),
|
||||
Self::Shape(error) => error.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<E: std::error::Error + 'static> std::error::Error for CollisionScanError<E> {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlockCollisionHit {
|
||||
pub position: BlockPos,
|
||||
pub shape: VoxelShape,
|
||||
}
|
||||
|
||||
pub struct BlockCollisionScan<'w, 'c, W: BlockCollisionWorld> {
|
||||
world: &'w mut W,
|
||||
context: CollisionContext<'c>,
|
||||
bounds: Aabb,
|
||||
entity_shape: VoxelShape,
|
||||
only_suffocating: bool,
|
||||
start: BlockPos,
|
||||
sizes: [usize; 3],
|
||||
index: usize,
|
||||
count: usize,
|
||||
budget: usize,
|
||||
chunk: Option<(ChunkPos, W::Chunk)>,
|
||||
failed: bool,
|
||||
}
|
||||
impl<'w, 'c, W: BlockCollisionWorld> BlockCollisionScan<'w, 'c, W> {
|
||||
/// Finite bounds and a positive-Java-int candidate volume are supported.
|
||||
/// Budget counts every cursor cell, including skipped corners. After an error
|
||||
/// iteration terminates; already performed queries are not rolled back.
|
||||
pub fn new(
|
||||
world: &'w mut W,
|
||||
context: CollisionContext<'c>,
|
||||
bounds: Aabb,
|
||||
only_suffocating: bool,
|
||||
candidate_budget: usize,
|
||||
) -> Result<Self, CollisionScanError<W::Error>> {
|
||||
let min = bounds.min_position();
|
||||
let max = bounds.max_position();
|
||||
if !min.is_finite() || !max.is_finite() {
|
||||
return Err(CollisionScanError::InvalidBounds);
|
||||
}
|
||||
let start = BlockPos::containing(Vec3::new(min.x - 1.0e-7, min.y - 1.0e-7, min.z - 1.0e-7))
|
||||
.offset(-1, -1, -1);
|
||||
let end = BlockPos::containing(Vec3::new(max.x + 1.0e-7, max.y + 1.0e-7, max.z + 1.0e-7))
|
||||
.offset(1, 1, 1);
|
||||
let sizes = [
|
||||
end.x.wrapping_sub(start.x).wrapping_add(1),
|
||||
end.y.wrapping_sub(start.y).wrapping_add(1),
|
||||
end.z.wrapping_sub(start.z).wrapping_add(1),
|
||||
];
|
||||
if sizes.iter().any(|size| *size <= 0) {
|
||||
return Err(CollisionScanError::TooLarge);
|
||||
}
|
||||
let count = sizes
|
||||
.into_iter()
|
||||
.try_fold(1u64, |n, size| {
|
||||
n.checked_mul(size as u64).filter(|n| *n <= i32::MAX as u64)
|
||||
})
|
||||
.ok_or(CollisionScanError::TooLarge)? as usize;
|
||||
Ok(Self {
|
||||
world,
|
||||
context,
|
||||
bounds,
|
||||
entity_shape: VoxelShape::from_box(bounds).map_err(CollisionScanError::Shape)?,
|
||||
only_suffocating,
|
||||
start,
|
||||
sizes: sizes.map(|s| s as usize),
|
||||
index: 0,
|
||||
count,
|
||||
budget: candidate_budget,
|
||||
chunk: None,
|
||||
failed: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn find_next(&mut self) -> Result<Option<BlockCollisionHit>, CollisionScanError<W::Error>> {
|
||||
while self.index < self.count {
|
||||
if self.index >= self.budget {
|
||||
return Err(CollisionScanError::VisitBudget);
|
||||
}
|
||||
let [width, height, _] = self.sizes;
|
||||
let relative = [
|
||||
self.index % width,
|
||||
self.index / width % height,
|
||||
self.index / width / height,
|
||||
];
|
||||
self.index += 1;
|
||||
let kind = relative
|
||||
.into_iter()
|
||||
.zip(self.sizes)
|
||||
.filter(|(p, size)| *p == 0 || *p == size - 1)
|
||||
.count();
|
||||
if kind == 3 {
|
||||
continue;
|
||||
}
|
||||
let p = self
|
||||
.start
|
||||
.offset(relative[0] as i32, relative[1] as i32, relative[2] as i32);
|
||||
let chunk_position = p.chunk();
|
||||
let chunk = match self.chunk {
|
||||
Some((at, chunk)) if at == chunk_position => Some(chunk),
|
||||
_ => {
|
||||
let chunk = self
|
||||
.world
|
||||
.collision_chunk(chunk_position)
|
||||
.map_err(CollisionScanError::World)?;
|
||||
self.chunk = chunk.map(|chunk| (chunk_position, chunk));
|
||||
chunk
|
||||
}
|
||||
};
|
||||
let Some(chunk) = chunk else {
|
||||
continue;
|
||||
};
|
||||
let block = self
|
||||
.world
|
||||
.collision_block(chunk, p)
|
||||
.map_err(CollisionScanError::World)?;
|
||||
if self.only_suffocating
|
||||
&& !self
|
||||
.world
|
||||
.is_suffocating(chunk, block, p)
|
||||
.map_err(CollisionScanError::World)?
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if kind == 1 && !block.large_collision_shape || kind == 2 && !block.moving_piston {
|
||||
continue;
|
||||
}
|
||||
let shape = self
|
||||
.world
|
||||
.context_shape(block, p, &self.context)
|
||||
.map_err(CollisionScanError::World)?;
|
||||
let offset = Vec3::new(f64::from(p.x), f64::from(p.y), f64::from(p.z));
|
||||
let moved = if shape.same_identity(&VoxelShape::block()) {
|
||||
// Native adds one in floating point, including at i32::MAX.
|
||||
let unit = Aabb::new(
|
||||
offset,
|
||||
Vec3::new(offset.x + 1.0, offset.y + 1.0, offset.z + 1.0),
|
||||
);
|
||||
if !self.bounds.intersects(unit) {
|
||||
continue;
|
||||
}
|
||||
shape.moved(offset)
|
||||
} else {
|
||||
let moved = shape.moved(offset);
|
||||
if moved.is_empty()
|
||||
|| !moved
|
||||
.join_is_not_empty(&self.entity_shape, ShapeOp::AND)
|
||||
.map_err(CollisionScanError::Shape)?
|
||||
{
|
||||
continue;
|
||||
}
|
||||
moved
|
||||
};
|
||||
return Ok(Some(BlockCollisionHit {
|
||||
position: p,
|
||||
shape: moved,
|
||||
}));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
impl<W: BlockCollisionWorld> Iterator for BlockCollisionScan<'_, '_, W> {
|
||||
type Item = Result<BlockCollisionHit, CollisionScanError<W::Error>>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.failed {
|
||||
return None;
|
||||
}
|
||||
match self.find_next() {
|
||||
Ok(hit) => hit.map(Ok),
|
||||
Err(error) => {
|
||||
self.failed = true;
|
||||
Some(Err(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<W: BlockCollisionWorld> std::iter::FusedIterator for BlockCollisionScan<'_, '_, W> {}
|
||||
@@ -2,6 +2,7 @@
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod block_collision;
|
||||
pub mod block_collision_scan;
|
||||
pub mod block_entities;
|
||||
pub mod block_placement;
|
||||
pub mod block_properties;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
use horizon_core::{
|
||||
geometry::{Aabb, Vec3, VoxelShape},
|
||||
position::{BlockPos, ChunkPos},
|
||||
};
|
||||
use horizon_world::{
|
||||
block_collision_scan::{
|
||||
BlockCollisionScan, BlockCollisionWorld, CollisionBlock, CollisionScanError,
|
||||
},
|
||||
collision_context::CollisionContext,
|
||||
};
|
||||
use std::io;
|
||||
|
||||
struct FailedChunk {
|
||||
calls: usize,
|
||||
}
|
||||
impl BlockCollisionWorld for FailedChunk {
|
||||
type Error = io::Error;
|
||||
type Chunk = ();
|
||||
fn collision_chunk(&mut self, _: ChunkPos) -> io::Result<Option<()>> {
|
||||
self.calls += 1;
|
||||
Err(io::Error::other("missing test provider"))
|
||||
}
|
||||
fn collision_block(&mut self, _: (), _: BlockPos) -> io::Result<CollisionBlock> {
|
||||
unreachable!()
|
||||
}
|
||||
fn is_suffocating(&mut self, _: (), _: CollisionBlock, _: BlockPos) -> io::Result<bool> {
|
||||
unreachable!()
|
||||
}
|
||||
fn context_shape(
|
||||
&mut self,
|
||||
_: CollisionBlock,
|
||||
_: BlockPos,
|
||||
_: &CollisionContext<'_>,
|
||||
) -> io::Result<VoxelShape> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
fn bounds() -> Aabb {
|
||||
Aabb::new(Vec3::ZERO, Vec3::new(1.0, 1.0, 1.0))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn budgets_include_skipped_corners_and_errors_fuse_iteration() {
|
||||
for budget in [0, 1] {
|
||||
let mut world = FailedChunk { calls: 0 };
|
||||
let mut scan = BlockCollisionScan::new(
|
||||
&mut world,
|
||||
CollisionContext::empty(false),
|
||||
bounds(),
|
||||
false,
|
||||
budget,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
scan.next(),
|
||||
Some(Err(CollisionScanError::VisitBudget))
|
||||
));
|
||||
assert!(scan.next().is_none());
|
||||
drop(scan);
|
||||
assert_eq!(world.calls, 0);
|
||||
}
|
||||
let mut world = FailedChunk { calls: 0 };
|
||||
let mut scan = BlockCollisionScan::new(
|
||||
&mut world,
|
||||
CollisionContext::empty(false),
|
||||
bounds(),
|
||||
false,
|
||||
1000,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
scan.next(),
|
||||
Some(Err(CollisionScanError::World(_)))
|
||||
));
|
||||
assert!(scan.next().is_none());
|
||||
drop(scan);
|
||||
assert_eq!(world.calls, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_or_excessive_domains_fail_before_world_queries() {
|
||||
let mut world = FailedChunk { calls: 0 };
|
||||
for coordinate in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
|
||||
let bounds = Aabb::new(Vec3::ZERO, Vec3::new(coordinate, 1.0, 1.0));
|
||||
assert!(matches!(
|
||||
BlockCollisionScan::new(
|
||||
&mut world,
|
||||
CollisionContext::empty(false),
|
||||
bounds,
|
||||
false,
|
||||
1000
|
||||
),
|
||||
Err(CollisionScanError::InvalidBounds)
|
||||
));
|
||||
}
|
||||
let bounds = Aabb::new(Vec3::ZERO, Vec3::new(100000.0, 100000.0, 100000.0));
|
||||
assert!(matches!(
|
||||
BlockCollisionScan::new(
|
||||
&mut world,
|
||||
CollisionContext::empty(false),
|
||||
bounds,
|
||||
false,
|
||||
1000
|
||||
),
|
||||
Err(CollisionScanError::TooLarge)
|
||||
));
|
||||
assert_eq!(world.calls, 0);
|
||||
}
|
||||
@@ -392,3 +392,24 @@ with **2,391,334 lines per JAR** in its
|
||||
[regression report](../benchmarks/rust-canonical-collision-2026-10-06/contextual-regression.json).
|
||||
Five import tests cover legacy data, equal-but-distinct grids, canonical restoration
|
||||
and malformed identity metadata. Workspace Clippy passes without warnings.
|
||||
|
||||
|
||||
`BlockCollisionScan` now implements lazy cursor selection around entity bounds.
|
||||
It retains the native epsilon-expanded cursor, X/Y/Z visit order, skipped corners,
|
||||
large-shape face filtering, moving-piston edge filtering and suffocation-before-
|
||||
shape query order. Only successful chunk lookups are reused; absent chunks are
|
||||
queried again. Shape selection uses the global collision world, while suffocation
|
||||
uses the selected chunk. Canonical full blocks use native AABB intersection;
|
||||
other shapes use moved voxel intersection. Returned positions are independent
|
||||
values. Providers supply current block metadata and contextual shape selection.
|
||||
|
||||
`python3 tools/test_block_collision_scan_parity.py` compares **4,176 fixtures**
|
||||
and **517,820 matching lines per JAR** in the
|
||||
[collision-scan report](../benchmarks/rust-block-collision-scan-2026-10-06/scoped-parity.json).
|
||||
The native iterator runs over controlled metadata, shapes and chunk availability;
|
||||
traces cover early termination, missing chunks, query failures, thin/zero-width
|
||||
bounds, integer-coordinate wrapping and equal shapes with different canonical
|
||||
identities. Two Rust API tests cover finite/bounded input requirements, cursor
|
||||
visit budgets and termination after errors. Unsupported cursor volumes return
|
||||
errors; Java's overflowing iteration counts are outside this bounded API.
|
||||
Registry/world integration and live movement still need implementation.
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package dev.horizonlab.parity;
|
||||
import com.google.gson.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.file.*;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.block.*;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.*;
|
||||
import net.minecraft.world.phys.shapes.*;
|
||||
/** Runs native BlockCollisions with controlled block metadata and traced providers. */
|
||||
public final class VanillaBlockCollisionScanOracle {
|
||||
static final class Stop extends RuntimeException {}
|
||||
static final class Trace {
|
||||
PrintWriter out;int calls,fail;CollisionGetter global;
|
||||
void query(String value){out.println(value);if(calls++==fail)throw new Stop();}
|
||||
}
|
||||
public static class State extends BlockState {
|
||||
int id;boolean large,moving,suffocating;VoxelShape shape;Trace trace;BlockGetter readFrom;
|
||||
public State(){super(null,null,null);}
|
||||
@Override public Block getBlock(){return moving?Blocks.MOVING_PISTON:Blocks.STONE;}
|
||||
@Override public boolean hasLargeCollisionShape(){return large;}
|
||||
@Override public boolean isSuffocating(BlockGetter world,BlockPos p){if(world!=readFrom||world==trace.global)throw new AssertionError("wrong suffocation world");trace.query("suffocating "+p.getX()+" "+p.getY()+" "+p.getZ()+" "+id);return suffocating;}
|
||||
}
|
||||
static VoxelShape shape(int index){return switch(index){
|
||||
case 0->Shapes.empty();case 1->Shapes.block();case 2->Shapes.block().move(0,0,0);
|
||||
case 3->Shapes.box(0,0,0,1,0.5,1);case 4->Shapes.box(-0.25,-0.5,-0.25,1.25,1.5,1.25);
|
||||
case 5->Shapes.box(0,0,0,1e-8,1,1);
|
||||
case 6->Shapes.or(Shapes.box(0,0,0,0.25,1,0.25),Shapes.box(0.75,0,0.75,1,1,1));
|
||||
default->throw new AssertionError(index);
|
||||
};}
|
||||
static double number(JsonElement value){return Double.longBitsToDouble(Long.parseUnsignedLong(value.getAsString(),16));}
|
||||
public static void main(String[] args)throws Exception {
|
||||
net.minecraft.SharedConstants.tryDetectVersion();net.minecraft.server.Bootstrap.bootStrap();
|
||||
var allocator=Class.forName("sun.misc.Unsafe");var access=allocator.getDeclaredField("theUnsafe");access.setAccessible(true);var unsafe=access.get(null);var allocate=allocator.getMethod("allocateInstance",Class.class);
|
||||
var emit=VanillaFaceSupportOracle.class.getDeclaredMethod("emit",PrintWriter.class,VoxelShape.class);emit.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 trace=new Trace();trace.out=out;trace.fail=f.get("fail").getAsInt();
|
||||
var palette=f.getAsJsonArray("palette");var states=new State[palette.size()];
|
||||
for(int i=0;i<states.length;i++){var v=palette.get(i).getAsJsonArray();var state=(State)allocate.invoke(unsafe,State.class);state.id=i;state.shape=shape(v.get(0).getAsInt());state.large=v.get(1).getAsBoolean();state.moving=v.get(2).getAsBoolean();state.suffocating=v.get(3).getAsBoolean();state.trace=trace;states[i]=state;}
|
||||
int seed=f.get("seed").getAsInt(),missing=f.get("missing").getAsInt();
|
||||
var world=(CollisionGetter)Proxy.newProxyInstance(CollisionGetter.class.getClassLoader(),new Class<?>[]{CollisionGetter.class},(proxy,method,values)->{
|
||||
if(!method.getName().equals("getChunkForCollisions"))throw new AssertionError(method);
|
||||
int cx=(int)values[0],cz=(int)values[1];trace.query("chunk "+cx+" "+cz);
|
||||
if(missing==1||missing==2&&((cx^cz)&1)!=0)return null;
|
||||
return Proxy.newProxyInstance(BlockGetter.class.getClassLoader(),new Class<?>[]{BlockGetter.class},(chunk,m,a)->{
|
||||
if(!m.getName().equals("getBlockState"))throw new AssertionError(m);
|
||||
var p=(BlockPos)a[0];trace.query("block "+p.getX()+" "+p.getY()+" "+p.getZ());
|
||||
var state=states[((p.getX()*3+p.getY()*5+p.getZ()*7+seed)&Integer.MAX_VALUE)%states.length];state.readFrom=(BlockGetter)chunk;return state;
|
||||
});
|
||||
});trace.global=world;
|
||||
var context=new CollisionContext(){
|
||||
public boolean isDescending(){throw new AssertionError();}
|
||||
public boolean isAbove(VoxelShape s,BlockPos p,boolean d){throw new AssertionError();}
|
||||
public boolean isHoldingItem(Item i){throw new AssertionError();}
|
||||
public boolean alwaysCollideWithFluid(){throw new AssertionError();}
|
||||
public boolean canStandOnFluid(FluidState a,FluidState b){throw new AssertionError();}
|
||||
public VoxelShape getCollisionShape(BlockState state,CollisionGetter collision,BlockPos p){if(collision!=world)throw new AssertionError("wrong collision world");var s=(State)state;trace.query("shape "+p.getX()+" "+p.getY()+" "+p.getZ()+" "+s.id);return s.shape;}
|
||||
};
|
||||
var v=f.getAsJsonArray("box");var box=new AABB(number(v.get(0)),number(v.get(1)),number(v.get(2)),number(v.get(3)),number(v.get(4)),number(v.get(5)));
|
||||
var scan=new BlockCollisions<VoxelShape>(world,context,box,f.get("suffocating").getAsBoolean(),(p,s)->{out.println("hit "+p.getX()+" "+p.getY()+" "+p.getZ());return s;});
|
||||
int hits=0,limit=f.get("limit").getAsInt();
|
||||
try{while(hits<limit&&scan.hasNext()){emit.invoke(null,out,scan.next());hits++;}}catch(Stop error){out.println("error");}
|
||||
out.println("done "+hits+" "+trace.calls);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compare lazy block collision scanning and query ordering with pinned vanilla."""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import platform
|
||||
import subprocess
|
||||
import random
|
||||
import struct
|
||||
try:
|
||||
from . import lab, test_rust_parity as base
|
||||
except ImportError:
|
||||
import lab
|
||||
import test_rust_parity as base
|
||||
|
||||
|
||||
def corpus():
|
||||
def box(values):return [struct.pack('>d',float(v)).hex() for v in values]
|
||||
boxes=[
|
||||
[0.2,0.2,0.2,0.8,0.8,0.8],[-0.3,0,0.3,0.3,1.8,0.9],[0,0,0,1,1,1],
|
||||
[0.5,0.2,0.2,0.5,0.8,0.8],[0.5,0.2,0.2,0.5+1e-8,0.8,0.8],
|
||||
[0.5,0.2,0.2,0.5+2e-7,0.8,0.8],[1-1e-8,0.2,0.2,1+1e-8,0.8,0.8],
|
||||
[15.8,63.2,-0.3,16.2,64.8,0.3],[-16.2,-64.3,-16.2,-15.8,-62.5,-15.8],
|
||||
[0.5,0.5,0.5,0.5,0.5,0.5],[1e-7,1e-7,1e-7,1-1e-7,1-1e-7,1-1e-7],
|
||||
[2,2,2,-1,-1,-1],[-20.2,0.2,0.2,20.2,0.8,0.8],
|
||||
[2147483647.2,0.2,0.2,2147483647.8,0.8,0.8],
|
||||
[-2147483648.8,-0.5,-0.5,-2147483648.2,0.5,0.5],
|
||||
[0.2,2147483647.2,0.2,0.8,2147483647.8,0.8],
|
||||
[-0.0,-0.0,-0.0,1e-8,1e-8,1e-8],[-1e-8,-1e-8,-1e-8,0,0,0],
|
||||
]
|
||||
palettes=[[shape,large,moving,suffocating] for shape in range(7) for large in [False,True] for moving in [False,True] for suffocating in [False,True]]
|
||||
def row(bounds,palette,suffocating=False,missing=0,fail=-1,limit=100000,seed=0):
|
||||
return {'box':box(bounds),'palette':palette,'suffocating':suffocating,'missing':missing,'fail':fail,'limit':limit,'seed':seed}
|
||||
for entry in palettes:
|
||||
for bounds in boxes:
|
||||
for suffocating in [False,True]:yield row(bounds,[entry],suffocating)
|
||||
for fail in [0,1,2,5,15,50]:
|
||||
for suffocating in [False,True]:yield row(boxes[7],[entry],suffocating,fail=fail)
|
||||
for missing in [1,2]:
|
||||
for bounds in boxes:
|
||||
for suffocating in [False,True]:
|
||||
for limit in [0,1,4,100000]:yield row(bounds,palettes,suffocating,missing,limit=limit)
|
||||
rng=random.Random(0x434f4c4c4953494f4e)
|
||||
for index in range(1200):
|
||||
low=[rng.choice([-16,-1,0,15,16])+rng.random() for _ in range(3)]
|
||||
high=[v+rng.choice([0,1e-8,2e-7,0.25,0.6,1.8,2.5]) for v in low]
|
||||
palette=rng.sample(palettes,rng.randrange(1,13))
|
||||
yield row([*low,*high],palette,bool(index%2),rng.randrange(3),rng.choice([-1,-1,-1,0,3,10,50]),rng.choice([0,1,3,100000]),rng.randrange(-2147483648,2147483648))
|
||||
|
||||
|
||||
def main():
|
||||
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--prepare',action='store_true');args=parser.parse_args()
|
||||
build=lab.LOCAL/'rust-block-collision-scan-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/VanillaBlockCollisionScanOracle.java'
|
||||
helpers=[oracle.with_name('VanillaFaceSupportOracle.java')]
|
||||
sources=[oracle,*helpers,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/block_collision_scan_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,*helpers],'compile-java')
|
||||
def java(side,mode,path):
|
||||
run(['java','-Xmx512M','-cp',os.pathsep.join([str(classes),str(jars[side]),dependency_path]),'dev.horizonlab.parity.VanillaBlockCollisionScanOracle',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','block_collision_scan_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'/('block_collision_scan_fixture.exe' if os.name=='nt' else 'block_collision_scan_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:,} block-collision-scan 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 BlockCollisions cursor and selection algorithm over controlled block metadata, chunk providers and context shapes. Compares ordered chunk/state/suffocation/shape calls, missing-chunk retries, cached chunk reuse, face/edge/corner filtering, canonical full-block versus equal noncanonical shape behavior, exact emitted shape data, early consumer termination and injected provider failures. Finite bounded scans include thin/zero-size boxes, chunk crossings and wrapped integer positions. Registry-specific metadata/shape dispatch, live chunk loading and entity movement are separate integration work; unsupported cursor volumes and caller budgets use typed Rust errors.'}
|
||||
lab.write_json(report_path,report);print(f'Scoped block collision scan parity passed: {report_path}')
|
||||
|
||||
|
||||
if __name__=='__main__':main()
|
||||
Reference in New Issue
Block a user