Bind resident region fluid states and resolved tag queries

This commit is contained in:
Ludovic Marie
2026-10-06 13:57:32 +02:00
parent 3cea5de769
commit 43d5793f6b
9 changed files with 560 additions and 16 deletions
@@ -0,0 +1,206 @@
{
"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)",
"block_states": 35723,
"direct_state_probes": 35723,
"block_tag_files": 300,
"fixtures": 192,
"worldgen_random_modes": [
false,
true
],
"resident_chunks_per_fixture": 9,
"requested_placements": 2688,
"direct_tick_requests": 14784,
"sources_sha256": {
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaFeatureRegionOracle.java": "a18a9d6184528b40b5fa853fd30208a400d7b749b3138659fdf209c33649d247",
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaHeightmapOracle.java": "145c943637ed177cc4ef8a85f2484da8afd164868e84a8463882feec1653a860",
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaPlacementOracle.java": "12b1c46cc397755ef6827da777faef3e71c008cafa48403669c03ca2bdc3c7cb",
"tools/test_feature_region_parity.py": "9a1d8da1ceaa657d6d70a7697c2761a881b63e1ddf3ba6134d840ed3165d6ec6",
"tools/test_rust_parity.py": "29d3db08005873528894b45ca10dcd6278753650473b3eb574e53e06ede40ec6",
"tools/test_worldgen_parity.py": "b40972ab2ad222aa6d77537cc36b434a217baa1f1b56bbaad945d6e12fe776af",
"tools/lab.py": "d00bf107fa01b6c579734a082c3ca4ade3018f0d6851d46844acf17574f66e64",
"Cargo.toml": "dc370d5fdde37238c3e4820046f11c3201020406a4edfa1308257c13edbdcda4",
"Cargo.lock": "7307d0c887364db36d327685ecf0671b75305e31e5ba5fbdcdbb15eaf156d20e",
"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": "47350edab5791f5074a54563ba98108818c5c6b1c5818a591388eab2ac9f5490",
"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/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": "cec2af81d212d5eed7a2196e4cf0be2daf4cecf53248f78cc68f2190e4d83f9a",
"crates/horizon-world/src/block_placement.rs": "524f4892d50bab77b7d89d19f7b048ffe746996f2ed7f376db2c6ab00ed75c24",
"crates/horizon-world/src/block_properties.rs": "b0bd8a983336c48e488a20caa77dd5c39b1a74bbd14ebc03b3b64556a1c864fc",
"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/collision.rs": "05313e0c1f3089524fe029f9aac3e439cd47f1c9584c8c7e154c9adcfa88c335",
"crates/horizon-world/src/compression.rs": "4db73e6ca9a0d552d415ce60e7e88b89c9cf2b7d060a669ff8328f518316e101",
"crates/horizon-world/src/dynamic_support.rs": "e799b31e5120cfdb04e0b342f2097d610ed98ef8c4be031620ee00368d82df59",
"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": "a8cd85f6223668c1446ff103276d80937b9707d9a7dc619a176b1b1ceed36a4a",
"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/region.rs": "72b642e87fed37ed17f54d4c30f96c3b64d26c14bc0589c31ef40ff1616188fc",
"crates/horizon-world/src/registry/json.rs": "1eae82604d2b3377fd35aaa3a914a67e5af28f93923815a49e895b4d437433cd",
"crates/horizon-world/src/registry.rs": "f2e58b2b4d944ac8fc6226bd3352cefc3d2052d8473e02ccf7dc402b176df435",
"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": "d6389c8d1adf900eb8f0e6c8833feafe43dc92d74e5c7ffa6f3950975529d624",
"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/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/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_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": "98bc93dff1373e3b6f4dcf8c4c2b05b56814acd4f66302834aa5877fe90ec7b9",
"crates/horizon-world/src/worldgen/feature_region.rs": "ae7552027b2efc0db6299dc14ab04c28615e43b876b5d67644855fd7a047e33e",
"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": "b7a59a712d2e376e8f32ec1e1fd901df452c8019e06910c39d469816be63a14f",
"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/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": "b8fb9fb80a66a851d916f07f15df1a40b6cc95b49e71aaec4d4b4107f13d9f9f",
"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.rs": "072d31a3b814eda9cc9bdc1da06a7dab43c38f133824bfd00f55ebb8452d8b88",
"crates/horizon-world/examples/feature_region_fixture.rs": "d29cb51653d7b6f249c2748d4f9df2c4e2358acf4d8fc57a21c8d69cb17be19c"
},
"fixtures_sha256": {
".local/rust-feature-region-parity/inputs.txt": "14e3cc52de74d24351a010e4c7b7ad7aae961a358dff754a3161dd58d050acad",
".local/rust-feature-region-parity/tags.json": "36975358262568f32bf84778d63d9989a36e7394ed4796d70a34809a8f4a64f0",
".local/rust-feature-region-parity/fluid-tags.json": "f1e5eb6d22ea7effbb118a2282709cfdeef1bfae4516b775a55ad7a4df29d7d0",
".local/rust-feature-region-parity/facts-client.json": "1d24883ee807b0b71473f0bbf8ed548ddaf712148caeb3fcc7aa13ab973a97b0",
".local/rust-feature-region-parity/facts-server.json": "1d24883ee807b0b71473f0bbf8ed548ddaf712148caeb3fcc7aa13ab973a97b0"
},
"rust_output_sha256": "33c6e7d07bd985f468d3fd7d8d8040001664316e6551fa753d00e1ec90c9ea90",
"references": [
{
"side": "client",
"jar_sha256": "4508d006323f24fa02876310c192d739af56516eb259000ac50f0909a68c9a2d",
"output_sha256": "33c6e7d07bd985f468d3fd7d8d8040001664316e6551fa753d00e1ec90c9ea90",
"matched_output_lines": 29312766
},
{
"side": "server",
"jar_sha256": "a362163eec5d1612d520772bc16e5b39c09e3b234fdc045f56bf544284ee8ae6",
"output_sha256": "33c6e7d07bd985f468d3fd7d8d8040001664316e6551fa753d00e1ec90c9ea90",
"matched_output_lines": 29312766
}
],
"scope": "Native FeaturePlacer and three basic block-writing features, a composed sequence of four configured fill layers, single-block replacements, scattered ore and water springs share a world proxy backed by nine actual ProtoChunks. Configured water, horizontal logs, air, out-of-height fills and ore/replacement rules test graph-to-region binding. Initial two-layer stone/dirt terrain, both pre-light heightmap groups, count/square/heightmap/layered modifier chains, repeated placements, direct and WorldgenRandom-wrapped random streams, missing-neighbor errors, rejected writes and injected partial failures are compared. Final complete raw sections, heightmap presence and packed words are compared alongside ordered feature writes, update flags, explicit height queries and subsequent random draws. Rust uses resident registry-backed chunks, lazy heightmap priming and a caller-supplied write callback; imported air/fluid facts and bundled block tags bind independently across authenticated JARs. The proxy supplies storage mutation and actual native default scheduleTick/createTick methods routed through WorldGenTickAccess into each ProtoChunk. Separate block/fluid queues, first-request deduplication, nondefault-state block identity, shared tick-order advancement on duplicates and missing-chunk errors, out-of-height requests and wrapped clock values are compared, including saved queue order and priorities. All block states are also written into resident chunks, queried through feature access, cleared and queried again; contained fluid identity/amount/falling/source/full flags, water-tag membership and every bundled block tag plus an absent tag are compared. Negative coordinates, chunk edges, outside-height and absent chunks are covered. Block/fluid query bindings are an immutable registry-checked shared snapshot. Actual WorldGenRegion construction, write-zone policy, POIs, block entities, postprocessing execution, lighting, block/fluid tick execution, complete feature registries and complete world generation remain outside this comparison."
}
@@ -78,6 +78,8 @@ fn fixture(
f: &Value,
registry: &BlockRegistry,
states: &[State],
bindings: &FeatureBlockBindings<'_>,
tags: &[String],
out: &mut impl Write,
) -> Result<(), Box<dyn std::error::Error>> {
let seed = f["seed"].as_i64().unwrap();
@@ -85,19 +87,39 @@ fn fixture(
f["legacy"].as_bool().unwrap(),
f["worldgen"].as_bool().unwrap(),
) {
(true, false) => run(f, registry, states, out, LegacyRandom::new(seed)),
(true, false) => run(
f,
registry,
states,
bindings,
tags,
out,
LegacyRandom::new(seed),
),
(true, true) => run(
f,
registry,
states,
bindings,
tags,
out,
WorldgenRandom::new(LegacyRandom::new(seed)),
),
(false, false) => run(f, registry, states, out, XoroshiroRandom::new(seed)),
(false, false) => run(
f,
registry,
states,
bindings,
tags,
out,
XoroshiroRandom::new(seed),
),
(false, true) => run(
f,
registry,
states,
bindings,
tags,
out,
WorldgenRandom::new(XoroshiroRandom::new(seed)),
),
@@ -107,6 +129,8 @@ fn run(
f: &Value,
registry: &BlockRegistry,
states: &[State],
bindings: &FeatureBlockBindings<'_>,
tags: &[String],
out: &mut impl Write,
mut random: impl RandomSource,
) -> Result<(), Box<dyn std::error::Error>> {
@@ -145,16 +169,14 @@ fn run(
.with_tick_clock(
f["game_time"].as_i64().unwrap(),
f["tick_order"].as_i64().unwrap(),
);
)
.with_block_bindings(bindings)?;
let blocks = FeatureBlocks::from_registry(registry)?;
// These configured fixture states use compact names and an enum property;
// no integer-property parsing is requested by this region corpus.
let bindings = FeatureBlockBindings::new(registry, BTreeSet::new())?;
let features = f["features"]
.as_array()
.unwrap()
.iter()
.map(|v| FeatureDefinition::from_json_with_blocks(&v.to_string(), &bindings))
.map(|v| FeatureDefinition::from_json_with_blocks(&v.to_string(), bindings))
.collect::<Result<Vec<_>, _>>()?;
let modifiers = f["placement"]
.as_array()
@@ -236,6 +258,30 @@ fn run(
)?;
writeln!(out, "tickorder {}", region.tick_clock().1)?;
}
for id in f["probe_states"].as_array().unwrap() {
let id = n(id) as u32;
let p = [[0, -64, 0], [-1, -49, -1], [16, -1, 16], [31, -32, 31]][id as usize % 4];
writeln!(out, "probe {id}")?;
for state in [
BlockStateId(id),
registry.default_state("minecraft:air").unwrap(),
] {
region.set_block_worldgen(p, state)?;
let mut world = TerrainFeatureAccess::new(&mut region, ());
query_state(&mut world, p, tags, out)?;
}
}
for p in [
[0, -65, 0],
[31, 0, 31],
[-1, i32::MIN, -1],
[16, i32::MAX, 16],
[-17, -40, 0],
[32, -40, 0],
[i32::MAX, i32::MIN, 0],
] {
query_state(&mut region, p, tags, out)?;
}
for chunk in region.chunks() {
let p = chunk.position();
writeln!(out, "chunk {} {}", p.x, p.z)?;
@@ -280,6 +326,39 @@ fn run(
writeln!(out, "tail {}", random.next_long())?;
Ok(())
}
fn query_state(
world: &mut impl PlacementContext,
p: [i32; 3],
tags: &[String],
out: &mut impl Write,
) -> io::Result<()> {
writeln!(out, "query {} {} {}", p[0], p[1], p[2])?;
match world.fluid_state(p) {
Ok(fluid) => writeln!(
out,
"fluid {} {} {} {} {}",
fluid.kind().name(),
fluid.amount(),
fluid.falling(),
fluid.is_full(),
fluid.is_source()
)?,
Err(_) => writeln!(out, "fluid error")?,
}
match world.water_at(p) {
Ok(water) => writeln!(out, "water {water}")?,
Err(_) => writeln!(out, "water error")?,
}
let mut bits = String::new();
for tag in tags {
bits.push(match world.block_matches_tag(p, tag) {
Ok(true) => '1',
Ok(false) => '0',
Err(_) => 'E',
});
}
writeln!(out, "tags {bits}")
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let arg = std::env::args().nth(1).expect("private fixture directory");
let dir = Path::new(&arg);
@@ -329,9 +408,33 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
})
.collect();
let fluid_resources: std::collections::BTreeMap<String, String> =
serde_json::from_str(&fs::read_to_string(dir.join("fluid-tags.json"))?)?;
let mut fluid_defs = TagDefinitions::default();
for (name, text) in fluid_resources {
fluid_defs.apply_json(&name, "vanilla", &text)?;
}
let fluid_tags =
fluid_defs.build(|name, _| FluidKind::from_name(name).map(|_| name.to_owned()))?;
assert!(fluid_tags.missing.is_empty());
let bindings = FeatureBlockBindings::with_tags(&registry, BTreeSet::new(), &built.tags)?
.with_fluid_tags(&fluid_tags.tags)?;
let tags: Vec<_> = built
.tags
.keys()
.cloned()
.chain(std::iter::once("horizon:absent".into()))
.collect();
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() {
fixture(&serde_json::from_str(line)?, &registry, &states, &mut out)?;
fixture(
&serde_json::from_str(line)?,
&registry,
&states,
&bindings,
&tags,
&mut out,
)?;
}
out.flush()?;
Ok(())
@@ -24,7 +24,7 @@ pub struct FeatureBlockBindings<'r> {
physical_properties: Option<[BoundBlockProperty; 4]>,
pub(crate) occlusion_faces: Option<crate::block_properties::BoundOcclusionFaces>,
biomes: Option<Arc<super::biome_predicate::BiomePredicateBindings>>,
fluids: super::fluid_predicate::FluidPredicateBindings,
pub(crate) fluids: super::fluid_predicate::FluidPredicateBindings,
pub(crate) codec: BlockStateJsonCodec<'r>,
pub(crate) blocks: BTreeMap<String, Arc<BTreeSet<BlockStateId>>>,
pub(crate) tags: BTreeMap<String, Arc<BTreeSet<BlockStateId>>>,
@@ -21,11 +21,20 @@ use horizon_core::{
WorldGenTickContainers,
},
};
use std::collections::BTreeMap;
use std::{
collections::{BTreeMap, BTreeSet},
sync::Arc,
};
struct RegionBlockQueries {
fluids: super::fluid_predicate::FluidPredicateBindings,
tags: BTreeMap<String, Arc<BTreeSet<BlockStateId>>>,
}
#[derive(Debug)]
pub enum RegionError {
InvalidChunks,
InvalidBindings,
InvalidTickState(BlockStateId),
MissingChunk([i32; 2]),
Terrain(TerrainError),
@@ -56,6 +65,7 @@ pub struct TerrainRegion<'r, B: TerrainBlockStates> {
sea_level: i32,
game_time: i64,
next_tick_order: i64,
block_queries: Option<RegionBlockQueries>,
}
impl<'r, B: TerrainBlockStates> TerrainRegion<'r, B> {
pub fn new(
@@ -84,6 +94,7 @@ impl<'r, B: TerrainBlockStates> TerrainRegion<'r, B> {
sea_level: generator.sea_level,
game_time: 0,
next_tick_order: 0,
block_queries: None,
min_y,
height,
generation: WorldGenerationContext::with_generator(
@@ -95,6 +106,24 @@ impl<'r, B: TerrainBlockStates> TerrainRegion<'r, B> {
),
})
}
/// Bind an immutable snapshot of fluid states and resolved block/fluid tags.
/// Tables are shared with configured features; registry identities must match.
pub fn with_block_bindings(
mut self,
bindings: &super::block_feature::FeatureBlockBindings<'r>,
) -> Result<Self, RegionError> {
if !std::ptr::eq(
self.chunks.first_key_value().unwrap().1.registry(),
bindings.registry(),
) {
return Err(RegionError::InvalidBindings);
}
self.block_queries = Some(RegionBlockQueries {
fluids: bindings.fluids.clone(),
tags: bindings.tags.clone(),
});
Ok(self)
}
/// Supply the owning world's current time and region-local next tick order.
pub fn with_tick_clock(mut self, game_time: i64, next_tick_order: i64) -> Self {
self.game_time = game_time;
@@ -107,6 +136,8 @@ impl<'r, B: TerrainBlockStates> TerrainRegion<'r, B> {
pub fn set_game_time(&mut self, game_time: i64) {
self.game_time = game_time;
}
/// Raw tick identities are default block-state IDs for block ticks and
/// `FluidKind` discriminants for fluid ticks, in separate namespaces.
pub fn schedule_tick(
&mut self,
kind: TickKind,
@@ -217,6 +248,45 @@ impl<B: TerrainBlockStates> WorldGenTickContainers for RegionTickContainers<'_,
}
}
impl<B: TerrainBlockStates> PlacementContext for TerrainRegion<'_, B> {
fn fluid_state(
&mut self,
position: [i32; 3],
) -> Result<crate::fluid::FluidState, PlacementQueryError> {
let queries = self
.block_queries
.as_ref()
.ok_or(PlacementQueryError::Unavailable)?;
let state = self.block(position)?;
queries
.fluids
.state(state)
.ok_or_else(|| PlacementQueryError::Failed("fluid state outside bound registry".into()))
}
fn water_at(&mut self, position: [i32; 3]) -> Result<bool, PlacementQueryError> {
let queries = self
.block_queries
.as_ref()
.ok_or(PlacementQueryError::Unavailable)?;
Ok(queries
.fluids
.state_matches_tag(self.block(position)?, "minecraft:water"))
}
fn block_matches_tag(
&mut self,
position: [i32; 3],
tag: &str,
) -> Result<bool, PlacementQueryError> {
let queries = self
.block_queries
.as_ref()
.ok_or(PlacementQueryError::Unavailable)?;
let state = self.block(position)?;
Ok(queries
.tags
.get(tag)
.is_some_and(|states| states.contains(&state)))
}
fn schedule_block_tick(
&mut self,
position: [i32; 3],
@@ -314,6 +384,23 @@ impl<'a, 'r, B: TerrainBlockStates, F> TerrainFeatureAccess<'a, 'r, B, F> {
}
}
impl<B: TerrainBlockStates, F> PlacementContext for TerrainFeatureAccess<'_, '_, B, F> {
fn fluid_state(
&mut self,
position: [i32; 3],
) -> Result<crate::fluid::FluidState, PlacementQueryError> {
self.region.fluid_state(position)
}
fn water_at(&mut self, position: [i32; 3]) -> Result<bool, PlacementQueryError> {
self.region.water_at(position)
}
fn block_matches_tag(
&mut self,
position: [i32; 3],
tag: &str,
) -> Result<bool, PlacementQueryError> {
self.region.block_matches_tag(position, tag)
}
fn schedule_block_tick(
&mut self,
position: [i32; 3],
@@ -5,6 +5,7 @@ use crate::{
registry::{BlockRegistry, BlockStateId},
};
use std::{collections::BTreeMap, sync::Arc};
#[derive(Clone)]
pub struct FluidPredicateBindings {
table: Arc<FluidStateTable>,
tags: BTreeMap<String, u8>,
@@ -44,6 +45,17 @@ impl FluidPredicateBindings {
self.tags = resolved;
Ok(self)
}
pub fn state(&self, block: BlockStateId) -> Option<crate::fluid::FluidState> {
self.table.get(block)
}
/// Missing tags have no members, as for a native tag-key membership query.
pub fn state_matches_tag(&self, block: BlockStateId, tag: &str) -> bool {
self.table.get(block).is_some_and(|state| {
self.tags
.get(tag)
.is_some_and(|mask| state.kind().mask() & mask != 0)
})
}
pub fn resolve(&self, json: &str) -> Result<BoundFluidSet, DecodeError> {
let mask = if let Ok(name) = serde_json::from_str::<String>(json) {
if let Some(tag) = name.strip_prefix('#') {
+72 -1
View File
@@ -47,6 +47,7 @@ fn registry() -> BlockRegistry {
"minecraft:grass_block",
"minecraft:mycelium",
"minecraft:dirt",
"minecraft:cave_air",
];
BlockRegistry::from_nbt(&Tag::compound([
("DataVersion", Tag::Int(DATA_VERSION)),
@@ -55,7 +56,18 @@ fn registry() -> BlockRegistry {
Tag::List(
names
.iter()
.map(|name| Tag::compound([("id", Tag::String((*name).into()))]))
.map(|name| {
let mut tag = Tag::compound([("id", Tag::String((*name).into()))]);
if *name == "minecraft:water" {
if let Tag::Compound(entries) = &mut tag {
entries.insert(
"properties".into(),
Tag::compound([("level", Tag::String("0".into()))]),
);
}
}
tag
})
.collect(),
),
),
@@ -172,3 +184,62 @@ fn postprocessing_routes_to_resident_chunks_and_preserves_partial_marks() {
&[vec![255, 255], vec![3840]]
);
}
#[test]
fn query_bindings_reject_foreign_registries_and_preserve_resolved_tag_snapshot() {
use horizon_world::{
fluid::FluidKind,
worldgen::{block_feature::FeatureBlockBindings, placement::PlacementQueryError},
};
use std::collections::{BTreeMap, BTreeSet};
let foreign = registry();
let registry = registry();
let chunk = || TerrainChunk::new(ChunkPos::new(-1, 0), 0, 16, &registry, Properties).unwrap();
let context = WorldGenerationContext::new(0, 16, 8);
let bindings = FeatureBlockBindings::new(&foreign, BTreeSet::new()).unwrap();
assert!(matches!(
TerrainRegion::new(vec![chunk()], context)
.unwrap()
.with_block_bindings(&bindings),
Err(RegionError::InvalidBindings)
));
let mut region = TerrainRegion::new(vec![chunk()], context).unwrap();
assert_eq!(
region.fluid_state([-1, 0, 0]),
Err(PlacementQueryError::Unavailable)
);
let tags = BTreeMap::from([("horizon:ground".into(), vec!["minecraft:stone".into()])]);
// Deliberately make the water tag contain EMPTY, not water, to catch a
// hard-coded water-family check instead of resolved tag membership.
let fluids = BTreeMap::from([("minecraft:water".into(), vec!["minecraft:empty".into()])]);
let bindings = FeatureBlockBindings::with_tags(&registry, BTreeSet::new(), &tags)
.unwrap()
.with_fluid_tags(&fluids)
.unwrap();
region = region.with_block_bindings(&bindings).unwrap();
drop(bindings);
region
.set_block_worldgen([-1, 0, 0], BlockStateId(3))
.unwrap();
assert_eq!(
region.fluid_state([-1, 0, 0]).unwrap().kind(),
FluidKind::Water
);
assert!(!region.water_at([-1, 0, 0]).unwrap());
region
.set_block_worldgen([-1, 0, 0], BlockStateId(2))
.unwrap();
assert!(
region
.block_matches_tag([-1, 0, 0], "horizon:ground")
.unwrap()
);
assert!(
!region
.block_matches_tag([-1, 0, 0], "horizon:missing")
.unwrap()
);
assert!(region.water_at([-1, 0, 0]).unwrap());
assert!(region.water_at([-1, 16, 0]).unwrap());
assert!(region.fluid_state([0, 0, 0]).is_err());
}
+18
View File
@@ -694,3 +694,21 @@ fluid identities, missing chunks, out-of-height positions and time/order overflo
Workspace tests and all-target Clippy pass. This connects generation-stage queues;
block/fluid tick execution, complete chunk persistence and full world-generation
effects remain pending.
## Resident block and fluid queries
Feature regions can bind an immutable snapshot of resolved block/fluid tags and
contained fluid states. The snapshot shares compiled tables with configured
features and rejects bindings from a different block registry. Feature access
forwards fluid, water-tag and block-tag queries against current resident storage.
Missing tags have no members; missing chunks remain query errors.
The [resident query comparison](../benchmarks/rust-feature-region-queries-2026-10-06/scoped-parity.json)
matches **29,312,766 lines per reference JAR**, retaining the 192 multi-chunk
feature/tick fixtures and adding insertion/removal probes for **all 35,723 block
states**. Each probe checks fluid identity, amount, falling/source/full flags,
water membership and all 300 bundled block tags plus an absent tag. Negative
coordinates, chunk edges, outside-height reads and missing chunks are included.
Workspace tests and all-target Clippy pass; a separate regression covers foreign
registries, binding lifetime and a custom water tag. These queries do not execute
fluid spreading, block behavior or lighting.
@@ -9,6 +9,7 @@ import java.util.*;
import net.minecraft.core.*;
import net.minecraft.core.registries.*;
import net.minecraft.resources.*;
import net.minecraft.tags.*;
import net.minecraft.world.ticks.*;
import net.minecraft.world.level.material.*;
import net.minecraft.util.RandomSource;
@@ -27,6 +28,30 @@ public final class VanillaFeatureRegionOracle {
private static ProtoChunk chunk(Map<ChunkPos,ProtoChunk> chunks,int x,int z) {
var chunk=chunks.get(new ChunkPos(x>>4,z>>4));if(chunk==null)throw new IllegalArgumentException("missing region chunk");return chunk;
}
private static void bindFluidTags(JsonObject resources) {
var registry=BuiltInRegistries.FLUID;
var loader=new TagLoader<Holder<Fluid>>((id,required)->registry.get(id).map(value->(Holder<Fluid>)value),"tags/fluid");
var definitions=new HashMap<Identifier,List<TagLoader.EntryWithSource>>();
for(var item:resources.entrySet()) {
var file=TagFile.CODEC.parse(JsonOps.INSTANCE,JsonParser.parseString(item.getValue().getAsString())).getOrThrow();
var entries=new ArrayList<TagLoader.EntryWithSource>();
for(var entry:file.entries())entries.add(new TagLoader.EntryWithSource(entry,"vanilla"));
definitions.put(Identifier.parse(item.getKey()),entries);
}
var tags=new HashMap<TagKey<Fluid>,List<Holder<Fluid>>>();
loader.build(definitions).forEach((id,values)->tags.put(TagKey.create(Registries.FLUID,id),List.copyOf(values)));
if(tags.size()!=resources.size())throw new AssertionError("incomplete fluid tags");
registry.prepareTagReload(new TagLoader.LoadResult<>(Registries.FLUID,tags)).apply();
}
private static void queryState(WorldGenLevel world, BlockPos p, List<String> tags, PrintWriter out) {
out.println("query "+p.getX()+" "+p.getY()+" "+p.getZ());
try { var fluid=world.getFluidState(p); boolean falling=fluid.hasProperty(FlowingFluid.FALLING)&&fluid.getValue(FlowingFluid.FALLING); out.println("fluid "+BuiltInRegistries.FLUID.getKey(fluid.getType())+" "+fluid.getAmount()+" "+falling+" "+fluid.isFull()+" "+fluid.isSource()); }
catch(RuntimeException error){out.println("fluid error");}
try {out.println("water "+world.isWaterAt(p));}catch(RuntimeException error){out.println("water error");}
var bits=new StringBuilder();
for(var tag:tags){try{bits.append(world.getBlockState(p).is(TagKey.create(Registries.BLOCK,Identifier.parse(tag)))?'1':'0');}catch(RuntimeException error){bits.append('E');}}
out.println("tags "+bits);
}
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
if(args[0].equals("export")){VanillaHeightmapOracle.main(args);return;}
@@ -36,6 +61,8 @@ public final class VanillaFeatureRegionOracle {
var ids=new IdMapper<Holder<Biome>>();ids.add(biome);
var factory=new PalettedContainerFactory(Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY),Blocks.AIR.defaultBlockState(),null,Strategy.createForBiomes(ids),biome,null);
VanillaHeightmapOracle.bindTags(JsonParser.parseString(Files.readString(dir.resolve("tags.json"))).getAsJsonObject());
bindFluidTags(JsonParser.parseString(Files.readString(dir.resolve("fluid-tags.json"))).getAsJsonObject());
var queryTags=new ArrayList<>(new TreeSet<>(JsonParser.parseString(Files.readString(dir.resolve("tags.json"))).getAsJsonObject().keySet()));queryTags.add("horizon:absent");
var contextMethod=VanillaPlacementOracle.class.getDeclaredMethod("context",JsonObject.class);contextMethod.setAccessible(true);
var bounds=new JsonObject();bounds.add("context",JsonParser.parseString("[-64,64,0]"));
var generator=((PlacementContext)contextMethod.invoke(null,bounds)).generator();
@@ -71,7 +98,7 @@ public final class VanillaFeatureRegionOracle {
case "getFluidTicks"->fluidTicks;
case "getGameTime"->f.get("game_time").getAsLong();
case "nextSubTickCount"->tickOrder[0]++;
case "scheduleTick","createTick","isEmptyBlock"->InvocationHandler.invokeDefault(proxy,method,values);
case "scheduleTick","createTick","isEmptyBlock","isWaterAt"->InvocationHandler.invokeDefault(proxy,method,values);
case "getMinY"->-64;
case "getSeaLevel"->0;
case "getHeight"->{
@@ -79,6 +106,7 @@ public final class VanillaFeatureRegionOracle {
var kind=(Heightmap.Types)values[0];int x=(Integer)values[1],z=(Integer)values[2];yield chunk(chunks,x,z).getHeight(kind,x&15,z&15)+1;
}
case "getMaxY","isInsideBuildHeight","isOutsideBuildHeight","setBlockAndUpdate"->InvocationHandler.invokeDefault(proxy,method,values);
case "getFluidState"->{var p=(BlockPos)values[0];yield chunk(chunks,p.getX(),p.getZ()).getFluidState(p);}
case "getBlockState"->{var p=(BlockPos)values[0];yield chunk(chunks,p.getX(),p.getZ()).getBlockState(p);}
case "setBlock"->{
var p=(BlockPos)values[0];var state=(BlockState)values[1];int flags=(Integer)values[2];
@@ -107,6 +135,15 @@ public final class VanillaFeatureRegionOracle {
try{if(kind.equals("block"))world.scheduleTick(p,Block.stateById(id).getBlock(),delay);else world.scheduleTick(p,fluids[id],delay);out.println("tickresult ok");}catch(RuntimeException error){out.println("tickresult error");}
out.println("tickorder "+tickOrder[0]);
}
for(var value:f.getAsJsonArray("probe_states")) {
int id=value.getAsInt();int[] xyz=new int[][]{{0,-64,0},{-1,-49,-1},{16,-1,16},{31,-32,31}}[id%4];var p=new BlockPos(xyz[0],xyz[1],xyz[2]);
out.println("probe "+id);
for(var state:new BlockState[]{Block.stateById(id),Blocks.AIR.defaultBlockState()}) {
chunk(chunks,p.getX(),p.getZ()).setBlockState(p,state,3);
queryState(world,p,queryTags,out);
}
}
for(int[] xyz:new int[][]{{0,-65,0},{31,0,31},{-1,Integer.MIN_VALUE,-1},{16,Integer.MAX_VALUE,16},{-17,-40,0},{32,-40,0},{Integer.MAX_VALUE,Integer.MIN_VALUE,0}})queryState(world,new BlockPos(xyz[0],xyz[1],xyz[2]),queryTags,out);
for(var entry:chunks.entrySet()) {
var cp=entry.getKey();var chunk=entry.getValue();out.println("chunk "+cp.x()+" "+cp.z());
out.println("blockticks "+chunk.getBlockTicks().count());
+14 -4
View File
@@ -8,6 +8,7 @@ from pathlib import Path
import platform
import random
import subprocess
import zipfile
try:
from . import lab, test_rust_parity as base, test_worldgen_parity as worldgen
@@ -35,6 +36,7 @@ def corpus(facts):
[{'type':'count_on_every_layer','count':1},{'type':'offset','x':0,'y':1,'z':0}],
[{'type':'count','count':2},{'type':'heightmap','heightmap':'WORLD_SURFACE'},{'type':'offset','x':1,'y':0,'z':1}],
]
fixture_index=0
for legacy in [False,True]:
for seed in [0,-1]:
for stage in ['empty','terrain']:
@@ -42,7 +44,8 @@ def corpus(facts):
for reject in [0,3]:
for placement in chains:
for worldgen in [False,True]:
yield {'worldgen':worldgen,'legacy':legacy,'seed':seed,'stage':stage,'fail':fail,'reject':reject,'placement':placement,'features':features,'tick_commands':ticks,'game_time':9223372036854775807 if worldgen else -9223372036854775808,'tick_order':9223372036854775803 if legacy else -9223372036854775808}
yield {'probe_states':list(range(fixture_index,len(facts['states']),192)),'worldgen':worldgen,'legacy':legacy,'seed':seed,'stage':stage,'fail':fail,'reject':reject,'placement':placement,'features':features,'tick_commands':ticks,'game_time':9223372036854775807 if worldgen else -9223372036854775808,'tick_order':9223372036854775803 if legacy else -9223372036854775808}
fixture_index+=1
def main():
@@ -55,6 +58,13 @@ def main():
lock,jars,libraries=base.verify_artifacts()
tags=worldgen.tag_resources(jars["server"])
if not tags or tags!=worldgen.tag_resources(jars["client"]):raise ValueError("client/server block tags differ or are empty")
def fluid_resources(jar):
with zipfile.ZipFile(jar) as archive:
prefix='data/minecraft/tags/fluid/'
return {'minecraft:'+name[len(prefix):-5]:archive.read(name).decode('utf-8') for name in sorted(archive.namelist()) if name.startswith(prefix) and name.endswith('.json')}
fluid_tags=fluid_resources(jars['server'])
if fluid_tags!=fluid_resources(jars['client']):raise ValueError('reference fluid tags differ')
(build/'fluid-tags.json').write_text(json.dumps(fluid_tags,separators=(',',':')))
oracle=lab.ROOT/"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaFeatureRegionOracle.java"
helper=oracle.with_name("VanillaHeightmapOracle.java")
placement_helper=oracle.with_name("VanillaPlacementOracle.java")
@@ -76,7 +86,7 @@ def main():
fixtures=list(corpus(facts));inputs=build/"inputs.txt"
inputs.write_text("".join(json.dumps(value,separators=(",",":"))+"\n" for value in fixtures),encoding="utf-8")
(build/"tags.json").write_text(json.dumps(tags,separators=(",",":")),encoding="utf-8")
fixture_paths=[inputs,build/"tags.json",build/"facts-client.json",build/"facts-server.json"]
fixture_paths=[inputs,build/"tags.json",build/"fluid-tags.json",build/"facts-client.json",build/"facts-server.json"]
tested_fixtures=base.source_hashes(fixture_paths)
run(["cargo","build","--release","-p","horizon-world","--example","feature_region_fixture"],"compile-rust")
metadata=json.loads(subprocess.check_output(["cargo","metadata","--no-deps","--format-version","1"],cwd=lab.ROOT,text=True))
@@ -91,9 +101,9 @@ def main():
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(),
"block_states":len(facts["states"]),"block_tag_files":len(tags),"fixtures":len(fixtures),"worldgen_random_modes":[False,True],"resident_chunks_per_fixture":9,"requested_placements":sum(len(f["features"])*2 for f in fixtures),"direct_tick_requests":sum(len(f["tick_commands"]) for f in fixtures),
"block_states":len(facts["states"]),"direct_state_probes":sum(len(f["probe_states"]) for f in fixtures),"block_tag_files":len(tags),"fixtures":len(fixtures),"worldgen_random_modes":[False,True],"resident_chunks_per_fixture":9,"requested_placements":sum(len(f["features"])*2 for f in fixtures),"direct_tick_requests":sum(len(f["tick_commands"]) for f in fixtures),
"sources_sha256":tested_sources,"fixtures_sha256":tested_fixtures,"rust_output_sha256":lab.digest(build/"rust.txt","sha256"),"references":references,
"scope":"Native FeaturePlacer and three basic block-writing features, a composed sequence of four configured fill layers, single-block replacements, scattered ore and water springs share a world proxy backed by nine actual ProtoChunks. Configured water, horizontal logs, air, out-of-height fills and ore/replacement rules test graph-to-region binding. Initial two-layer stone/dirt terrain, both pre-light heightmap groups, count/square/heightmap/layered modifier chains, repeated placements, direct and WorldgenRandom-wrapped random streams, missing-neighbor errors, rejected writes and injected partial failures are compared. Final complete raw sections, heightmap presence and packed words are compared alongside ordered feature writes, update flags, explicit height queries and subsequent random draws. Rust uses resident registry-backed chunks, lazy heightmap priming and a caller-supplied write callback; imported air/fluid facts and bundled block tags bind independently across authenticated JARs. The proxy supplies storage mutation and actual native default scheduleTick/createTick methods routed through WorldGenTickAccess into each ProtoChunk. Separate block/fluid queues, first-request deduplication, nondefault-state block identity, shared tick-order advancement on duplicates and missing-chunk errors, out-of-height requests and wrapped clock values are compared, including saved queue order and priorities. Actual WorldGenRegion construction, write-zone policy, POIs, block entities, postprocessing execution, lighting, block/fluid tick execution, complete feature registries and complete world generation remain outside this comparison."}
"scope":"Native FeaturePlacer and three basic block-writing features, a composed sequence of four configured fill layers, single-block replacements, scattered ore and water springs share a world proxy backed by nine actual ProtoChunks. Configured water, horizontal logs, air, out-of-height fills and ore/replacement rules test graph-to-region binding. Initial two-layer stone/dirt terrain, both pre-light heightmap groups, count/square/heightmap/layered modifier chains, repeated placements, direct and WorldgenRandom-wrapped random streams, missing-neighbor errors, rejected writes and injected partial failures are compared. Final complete raw sections, heightmap presence and packed words are compared alongside ordered feature writes, update flags, explicit height queries and subsequent random draws. Rust uses resident registry-backed chunks, lazy heightmap priming and a caller-supplied write callback; imported air/fluid facts and bundled block tags bind independently across authenticated JARs. The proxy supplies storage mutation and actual native default scheduleTick/createTick methods routed through WorldGenTickAccess into each ProtoChunk. Separate block/fluid queues, first-request deduplication, nondefault-state block identity, shared tick-order advancement on duplicates and missing-chunk errors, out-of-height requests and wrapped clock values are compared, including saved queue order and priorities. All block states are also written into resident chunks, queried through feature access, cleared and queried again; contained fluid identity/amount/falling/source/full flags, water-tag membership and every bundled block tag plus an absent tag are compared. Negative coordinates, chunk edges, outside-height and absent chunks are covered. Block/fluid query bindings are an immutable registry-checked shared snapshot. Actual WorldGenRegion construction, write-zone policy, POIs, block entities, postprocessing execution, lighting, block/fluid tick execution, complete feature registries and complete world generation remain outside this comparison."}
lab.write_json(report_path,report);print(f"Scoped feature-region parity passed: {report_path}")