Implement native fluid-state JSON decoding and encoding
This commit is contained in:
@@ -7,13 +7,14 @@
|
||||
"rustc": "rustc 1.99.0 (b940084d7 2026-09-28)",
|
||||
"block_states": 35723,
|
||||
"fluid_kinds": 5,
|
||||
"codec_fixtures": 2432,
|
||||
"fixtures": 40344,
|
||||
"requested_height_queries": 80688,
|
||||
"sources_sha256": {
|
||||
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaFluidOracle.java": "616e256245f1a95069745b7cde26ade08ae16dadd7e9224fa54abf16cef9fee9",
|
||||
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaFluidOracle.java": "bae87f5d7626cbb09132dc8c4e5b221a307cc377cc25b1141819d55220806e0d",
|
||||
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaBlockStateCodecOracle.java": "5c217a8cb72094020082bd4846ed675a6399b9fa371be95a221bd92d227b2e09",
|
||||
"tools/test_fluid_parity.py": "3728655b2e524a01bfaac137dd9351bf3f4e7b4053037ec72049e6f549d38ba2",
|
||||
"tools/test_rust_parity.py": "7efa699a38c5820424f5fc8992ee601dbfe26d6482da9d2dab2c17c41fe8f12a",
|
||||
"tools/test_fluid_parity.py": "d5fffccdc93b58a7775ea9504f1529820d984de052a4ad536d05cb0ed32cbe29",
|
||||
"tools/test_rust_parity.py": "29d3db08005873528894b45ca10dcd6278753650473b3eb574e53e06ede40ec6",
|
||||
"tools/lab.py": "d00bf107fa01b6c579734a082c3ca4ade3018f0d6851d46844acf17574f66e64",
|
||||
"Cargo.toml": "dc370d5fdde37238c3e4820046f11c3201020406a4edfa1308257c13edbdcda4",
|
||||
"Cargo.lock": "7307d0c887364db36d327685ecf0671b75305e31e5ba5fbdcdbb15eaf156d20e",
|
||||
@@ -52,8 +53,9 @@
|
||||
"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": "de22acd7430df3f69ef3632d427c57dffe57f3bdb78950bc75eac7e179ccf9df",
|
||||
"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",
|
||||
@@ -75,30 +77,42 @@
|
||||
"crates/horizon-core/src/ticks/index.rs": "1f1a6a568c2a30eafecb020ca4d5f5fc414860de85b8b381fc419a2e3e65c24a",
|
||||
"crates/horizon-core/src/ticks/mod.rs": "84852599dde78687d782f115a5b4b3ef6856c1f9cc92917255167e89c72ab01e",
|
||||
"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": "b3caf26bd3afc9d10cdcca3f7e794c30abf5ba09afa1fe80ba8f44713acdb274",
|
||||
"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": "6c40ab491efd0332bd4e65a1a112f3598f9eb0ea2f32f9c8cc7e81278d003251",
|
||||
"crates/horizon-world/src/collision.rs": "05313e0c1f3089524fe029f9aac3e439cd47f1c9584c8c7e154c9adcfa88c335",
|
||||
"crates/horizon-world/src/compression.rs": "4db73e6ca9a0d552d415ce60e7e88b89c9cf2b7d060a669ff8328f518316e101",
|
||||
"crates/horizon-world/src/fluid.rs": "8a2834a9347ee2c2db7cf1c86a064907ec06e9ac16ba9cc3936e315fc4ad49ca",
|
||||
"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": "06aa7b44e1229b3cf50abcf3827f2cacd7ae54321865873bdba0f371cb458b3f",
|
||||
"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": "40974e8ddbca79f4a4f866f91f1241a7ac7289874527d4729483995dcf9b4f7e",
|
||||
"crates/horizon-world/src/registry.rs": "566d7ef6a0d0d7e492d73b7f963ff0158544560a86ba33e179ef4d17e1274706",
|
||||
"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/biome.rs": "b3b73091aa5ec989d916206567c5e4b0e997b007a5bb9c0ca5c53ada9d5fe81f",
|
||||
"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/block_feature.rs": "f8c2ef2de1cfe9a8689a7375d4bf0cc00431484e06f6d4b2b95aabac8fdfffb0",
|
||||
"crates/horizon-world/src/worldgen/block_predicate.rs": "8513e9d96c8626594b5ee078bf20ccf3de90fc9f9d7123780d1cab5eefb6b5c2",
|
||||
"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": "2ea6d26fe88c633ad3efe7bdb6fc49f54961cbdf93b82919d79cf7d37a5c3c7d",
|
||||
"crates/horizon-world/src/worldgen/block_pile.rs": "623e369b77e0526ed2756485a6c0bb09683cd28ad8876dea907360ca6665b39d",
|
||||
"crates/horizon-world/src/worldgen/block_predicate.rs": "074c692367e3f2191a1bb28d87b23402430a843c246bd30a4ea838ee3500280e",
|
||||
"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",
|
||||
@@ -107,12 +121,13 @@
|
||||
"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": "297524aefeb4567c5f5c0c1678013e44002eb91ca16ee63b51ffacf93f31a095",
|
||||
"crates/horizon-world/src/worldgen/decoration.rs": "75a79b20b21e133816e729f16e758be6165d0db18a64bfbd5fd3618325a2adf3",
|
||||
"crates/horizon-world/src/worldgen/density.rs": "65a98c156a290a6b374ef670d28cd5dfbe0aa93171824d1bbd96422536273f84",
|
||||
"crates/horizon-world/src/worldgen/disk.rs": "6f8f9e059755af44c9bfa1b91eba54a7d13fad811dce31717c5502d7f6df33d7",
|
||||
"crates/horizon-world/src/worldgen/feature.rs": "40500af71ee6628dfb27518262d99f08d0383ae6c7b9397452feef0c213eadd9",
|
||||
"crates/horizon-world/src/worldgen/feature_catalog.rs": "486fe9d8588eb09e0ee5707a0541b0df167b63b0b56c90a2709bfa09a0a3ad19",
|
||||
"crates/horizon-world/src/worldgen/feature_graph.rs": "fe61a5e43179a7588737a71782ea246811fe2c8721e74793e1ac018c8eb93c34",
|
||||
"crates/horizon-world/src/worldgen/feature_region.rs": "2c78e5f1bdb08307f8d982f231f1abbc3306cd54348d9023b86ee6ed3516fd33",
|
||||
"crates/horizon-world/src/worldgen/feature_catalog.rs": "efc7b17b227e71622ef34108be9abd010f5675b68ea0409fcab82581d9aab88a",
|
||||
"crates/horizon-world/src/worldgen/feature_graph.rs": "b78927059c43b0860f5e29640720b85ab4099e2e620993baa70feaf8e61b79bf",
|
||||
"crates/horizon-world/src/worldgen/feature_region.rs": "3b893ceafbdd1d7b4264f4022dbdb6a7142dfc7001a5cf5c304f5ca7695dfaa0",
|
||||
"crates/horizon-world/src/worldgen/feature_sort.rs": "3488a093dfe1321aaa29d8a30cfb115d8e666a81bf195514e87b170de626835c",
|
||||
"crates/horizon-world/src/worldgen/fluid_predicate.rs": "e682d13a21f90605215b79f5d254bf2e524d35e89eab2e3b46384709af80b847",
|
||||
"crates/horizon-world/src/worldgen/height_provider.rs": "368d4dc119854742a045c4a717679c921456da681fc5f71aa9b37102d6f33b47",
|
||||
@@ -126,43 +141,45 @@
|
||||
"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": "08ee8697f589e96b69653b395238eecd144d51cfec30017214275f9b338d82af",
|
||||
"crates/horizon-world/src/worldgen/placement/context.rs": "c916b30177e283e8eedfa342dc5282b42c898a2873668b44f59c83501ff866bd",
|
||||
"crates/horizon-world/src/worldgen/placement/chain.rs": "9218399b4d3757f7bbc550d7729a7201f32a1c83a7030865e0c12aab8a80d116",
|
||||
"crates/horizon-world/src/worldgen/placement/context.rs": "b967b71867dac7f83f6dba0eb063ad9c581aa2f29087c2128052a4eb02f199c2",
|
||||
"crates/horizon-world/src/worldgen/placement/layer.rs": "a0f5ca776f33f9d4f72b8fdcd163426152e5e43cb4a7572fc1d4fc57bf965de1",
|
||||
"crates/horizon-world/src/worldgen/placement.rs": "b0397e5818fae84358546193a95f84bcb0b5bffafce909e6fcb3386179ee8023",
|
||||
"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/state_provider/catalog.rs": "fa0616353f07460975ab323357ab280b7f35e7bfe2de6edc08d304316766ed26",
|
||||
"crates/horizon-world/src/worldgen/simple_block.rs": "9ba1a88d5db4925f8c37366557887f776c805f9a6444781615b5dbaff52e92a4",
|
||||
"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": "d1097d91b43e30cec38b09365d3ed58f15522b829feb584e255718447e4c68b4",
|
||||
"crates/horizon-world/src/worldgen/state_provider.rs": "be29ada818826a90afe01ab60916360fdfc4cbde5af15c9359cd56b1f1f7b156",
|
||||
"crates/horizon-world/src/worldgen/tags.rs": "d35ded93fe6e95ea045cadcf4925e656dc34ef832b742179b9ad0cc49f902f31",
|
||||
"crates/horizon-world/src/worldgen/terrain.rs": "7fb7130111654563f7217f7b84563adde0b11c3ebd6a499a514dc98ebef7c733",
|
||||
"crates/horizon-world/src/worldgen/value_provider.rs": "3358b563db8cb0bc8a9cfbbe2b8b3e70941cd2d37a0b519fbb6545f8d0dcbb69",
|
||||
"crates/horizon-world/src/worldgen/weighted.rs": "839840aae25302933bbd97a81a2336330e2d03a0ad1684e1e16ac769ed408e6b",
|
||||
"crates/horizon-world/src/worldgen.rs": "b08f074f54f451c24795d5dda68968165b84b8d762d244f0444a8d62de61820e",
|
||||
"crates/horizon-world/examples/fluid_fixture.rs": "4603e462ce92f60426bb6025cd42b08410d0d4e81293e08861636a5664dfe0b1"
|
||||
"crates/horizon-world/src/worldgen.rs": "97dcb2d79f285daab0bbbe2d2ca673edc0376b23c5cd4519e0f8818593e0a4ee",
|
||||
"crates/horizon-world/examples/fluid_fixture.rs": "dfd419b3a62d371f3068441590fe5b045cc135b0a2cd435bd30d36a47d845e0e"
|
||||
},
|
||||
"fixtures_sha256": {
|
||||
".local/rust-fluid-parity/inputs.txt": "532b6e5965ce43b01989e7ee11c104d6bb498e52bcad0a79b14c5865068d287d",
|
||||
".local/rust-fluid-parity/codec-inputs.txt": "c279696131c2f644413b5e68eb340ef69ed085d8b3af3beb88523b14522704a5",
|
||||
".local/rust-fluid-parity/facts-client.json": "5e89a805514cabfe46e082d651db406b9479781e1d97b65faa2ab9f6f871309b",
|
||||
".local/rust-fluid-parity/facts-server.json": "5e89a805514cabfe46e082d651db406b9479781e1d97b65faa2ab9f6f871309b"
|
||||
},
|
||||
"rust_output_sha256": "b25ed573e8c2177c68a5f48ff62665144cf687aee3b948e8de696ab43e16fad1",
|
||||
"rust_output_sha256": "4f575eff3ad878286ef466b8a8b809e0e4e9a0bccc9d301f8639273bc9838b54",
|
||||
"references": [
|
||||
{
|
||||
"side": "client",
|
||||
"jar_sha256": "4508d006323f24fa02876310c192d739af56516eb259000ac50f0909a68c9a2d",
|
||||
"output_sha256": "b25ed573e8c2177c68a5f48ff62665144cf687aee3b948e8de696ab43e16fad1",
|
||||
"matched_output_lines": 239190
|
||||
"output_sha256": "4f575eff3ad878286ef466b8a8b809e0e4e9a0bccc9d301f8639273bc9838b54",
|
||||
"matched_output_lines": 243331
|
||||
},
|
||||
{
|
||||
"side": "server",
|
||||
"jar_sha256": "a362163eec5d1612d520772bc16e5b39c09e3b234fdc045f56bf544284ee8ae6",
|
||||
"output_sha256": "b25ed573e8c2177c68a5f48ff62665144cf687aee3b948e8de696ab43e16fad1",
|
||||
"matched_output_lines": 239190
|
||||
"output_sha256": "4f575eff3ad878286ef466b8a8b809e0e4e9a0bccc9d301f8639273bc9838b54",
|
||||
"matched_output_lines": 243331
|
||||
}
|
||||
],
|
||||
"scope": "Native fluid identity, amount, falling/source/full flags, own-height bits and legacy block conversion for every pinned block state; all fluid-family identity pairs. Surface and camera height query order, above-fluid family checks, source-only downward-face support checks, coordinate wrapping and injected query failures are compared. The fixture supplies stone/air support states; general block support shapes, fluid spreading/ticks, entities and rendering remain outside this comparison."
|
||||
"scope": "FluidState.CODEC decoding and encoding include all 37 states, object-only identifiers, lenient missing/invalid properties, Unicode integer levels and native defaults. Legacy conversion is checked for codec-derived fluid states as well. Native fluid identity, amount, falling/source/full flags, own-height bits and legacy block conversion for every pinned block state; all fluid-family identity pairs. Surface and camera height query order, above-fluid family checks, source-only downward-face support checks, coordinate wrapping and injected query failures are compared. The fixture supplies stone/air support states; general block support shapes, fluid spreading/ticks, entities and rendering remain outside this comparison."
|
||||
}
|
||||
|
||||
@@ -88,6 +88,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
blocks.block(fluid).0
|
||||
)?;
|
||||
}
|
||||
for line in fs::read_to_string(dir.join("codec-inputs.txt"))?.lines() {
|
||||
match FluidState::from_json(line) {
|
||||
Err(_) => writeln!(out, "codec error")?,
|
||||
Ok(state) => {
|
||||
writeln!(
|
||||
out,
|
||||
"codec {} {} {} {} {}",
|
||||
state.kind().name(),
|
||||
state.amount(),
|
||||
state.falling(),
|
||||
state.is_source(),
|
||||
blocks.block(state).0
|
||||
)?;
|
||||
writeln!(out, "encoded {}", state.to_json()?)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
for line in fs::read_to_string(dir.join("inputs.txt"))?.lines() {
|
||||
let f: Value = serde_json::from_str(line)?;
|
||||
let fluid = fluids
|
||||
|
||||
@@ -61,6 +61,72 @@ pub struct FluidState {
|
||||
falling: bool,
|
||||
}
|
||||
impl FluidState {
|
||||
/// Native fluid states require an object; properties decode leniently.
|
||||
pub fn from_json(json: &str) -> io::Result<Self> {
|
||||
let value: serde_json::Value =
|
||||
serde_json::from_str(json).map_err(|e| invalid(e.to_string()))?;
|
||||
let name = value
|
||||
.get("id")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.ok_or_else(|| invalid("missing fluid identifier"))?;
|
||||
let (namespace, path) = name.split_once(':').unwrap_or(("minecraft", name));
|
||||
let name = format!(
|
||||
"{}:{path}",
|
||||
if namespace.is_empty() {
|
||||
"minecraft"
|
||||
} else {
|
||||
namespace
|
||||
}
|
||||
);
|
||||
let kind =
|
||||
FluidKind::from_name(&name).ok_or_else(|| invalid("unknown fluid identifier"))?;
|
||||
if kind == FluidKind::Empty {
|
||||
return Ok(Self::EMPTY);
|
||||
}
|
||||
let flowing = matches!(kind, FluidKind::FlowingWater | FluidKind::FlowingLava);
|
||||
let mut state = Self {
|
||||
kind,
|
||||
amount: if flowing { 1 } else { 8 },
|
||||
falling: true,
|
||||
};
|
||||
if let Some(properties) = value
|
||||
.get("properties")
|
||||
.and_then(serde_json::Value::as_object)
|
||||
{
|
||||
if let Some(value) = properties
|
||||
.get("falling")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
{
|
||||
match value {
|
||||
"true" => state.falling = true,
|
||||
"false" => state.falling = false,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if flowing {
|
||||
if let Some(value) = properties
|
||||
.get("level")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.and_then(crate::registry::java_integer)
|
||||
.filter(|v| (1..=8).contains(v))
|
||||
{
|
||||
state.amount = value as u8;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(state)
|
||||
}
|
||||
pub fn to_json(self) -> io::Result<String> {
|
||||
let mut value = serde_json::json!({"id": self.kind.name()});
|
||||
if self.kind != FluidKind::Empty {
|
||||
let mut properties = serde_json::json!({"falling": self.falling.to_string()});
|
||||
if !self.is_source() {
|
||||
properties["level"] = self.amount.to_string().into();
|
||||
}
|
||||
value["properties"] = properties;
|
||||
}
|
||||
serde_json::to_string(&value).map_err(|e| invalid(e.to_string()))
|
||||
}
|
||||
pub const EMPTY: Self = Self {
|
||||
kind: FluidKind::Empty,
|
||||
amount: 0,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
mod json;
|
||||
use crate::{DATA_VERSION, chunk::BlockState, compression::invalid, nbt::Tag};
|
||||
pub use json::BlockStateJsonCodec;
|
||||
pub(crate) use json::java_integer;
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
io,
|
||||
|
||||
@@ -103,7 +103,7 @@ impl<'a> BlockStateJsonCodec<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn java_integer(text: &str) -> Option<i32> {
|
||||
pub(crate) fn java_integer(text: &str) -> Option<i32> {
|
||||
let (negative, text) = if let Some(text) = text.strip_prefix('-') {
|
||||
(true, text)
|
||||
} else {
|
||||
|
||||
@@ -458,3 +458,16 @@ every candidate/supporting state, repeated calls, early returns, failed queries,
|
||||
rejected writes, partial failures and overlay/modifier composition. Workspace
|
||||
tests and all-target Clippy pass. Rust bounds pathological traversal work;
|
||||
resident-world update callbacks and full gameplay remain pending.
|
||||
|
||||
## Fluid-state JSON codecs
|
||||
|
||||
Fluid states now decode and encode native object-form identifiers and properties.
|
||||
Missing properties retain the pinned defaults (`falling=true`, flowing level 1);
|
||||
invalid property values are ignored, while unknown fluid identifiers fail.
|
||||
Integer levels share the Java-compatible decimal parser with block properties.
|
||||
|
||||
The expanded [fluid comparison](../benchmarks/rust-fluid-2026-10-06/scoped-parity.json)
|
||||
matches **243,331 lines per reference JAR**, including all 37 fluid states,
|
||||
2,432 codec fixtures, encoding, legacy block conversion, and the existing
|
||||
contained-fluid/height tests. Workspace tests and all-target Clippy pass.
|
||||
Fluid spreading, tick execution and entity interaction remain pending.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package dev.horizonlab.parity;
|
||||
import com.google.gson.*;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.file.*;
|
||||
@@ -23,6 +25,16 @@ public final class VanillaFluidOracle {
|
||||
var state=block.getFluidState();boolean falling=state.hasProperty(FlowingFluid.FALLING)&&state.getValue(FlowingFluid.FALLING);
|
||||
out.println("state "+Block.getId(block)+" "+BuiltInRegistries.FLUID.getKey(state.getType())+" "+state.getAmount()+" "+falling+" "+state.isFull()+" "+state.isSource()+" "+Integer.toUnsignedString(Float.floatToRawIntBits(state.getOwnHeight()))+" "+Block.getId(state.createLegacyBlock()));
|
||||
}
|
||||
for(var line:Files.readAllLines(dir.resolve("codec-inputs.txt"))) {
|
||||
var decoded=FluidState.CODEC.parse(JsonOps.INSTANCE,JsonParser.parseString(line)).result();
|
||||
if(decoded.isEmpty()){out.println("codec error");continue;}
|
||||
var state=decoded.get();boolean falling=state.hasProperty(FlowingFluid.FALLING)&&state.getValue(FlowingFluid.FALLING);
|
||||
out.println("codec "+BuiltInRegistries.FLUID.getKey(state.getType())+" "+state.getAmount()+" "+falling+" "+state.isSource()+" "+Block.getId(state.createLegacyBlock()));
|
||||
var raw=FluidState.CODEC.encodeStart(JsonOps.INSTANCE,state).getOrThrow().getAsJsonObject();
|
||||
var canonical=new JsonObject();canonical.add("id",raw.get("id"));
|
||||
if(raw.has("properties")){var properties=new JsonObject();new java.util.TreeMap<>(raw.getAsJsonObject("properties").asMap()).forEach(properties::add);canonical.add("properties",properties);}
|
||||
out.println("encoded "+canonical);
|
||||
}
|
||||
for(var line:(Iterable<String>)inputs::iterator) {
|
||||
var f=JsonParser.parseString(line).getAsJsonObject();var state=Block.stateById(f.get("state").getAsInt()).getFluidState();
|
||||
var above=Block.stateById(f.get("above").getAsInt()).getFluidState();int[] calls={0};int fail=f.get("fail").getAsInt();
|
||||
|
||||
@@ -23,6 +23,21 @@ def corpus(facts):
|
||||
yield {'state':state,'above':above,'position':position,'sturdy':sturdy,'fail':fail}
|
||||
|
||||
|
||||
|
||||
def codec_corpus():
|
||||
import itertools
|
||||
for name in ['empty','water','flowing_water','lava','flowing_lava','missing','minecraft:water',':water','MINECRAFT:water','']:
|
||||
for definition in [name,{'id':name},{'id':name,'properties':None},{'id':name,'properties':[]},{'id':name,'properties':{'unknown':'x'}}]:
|
||||
yield definition
|
||||
for falling,level in itertools.product([None,True,False,0,1,'true','false','TRUE','False',{},[]],
|
||||
[None,True,False,0,1,8,9,'0','1','8','9','-1','+2','003','٢','3','2147483648','1.0',' 1',{},[]]):
|
||||
yield {'id':name,'properties':{'falling':falling,'level':level}}
|
||||
for definition in [None,True,0,[],{}, {'id':None}, {'id':3}, {'Name':'minecraft:water'}]:yield definition
|
||||
for name in ['water','flowing_water','lava','flowing_lava']:
|
||||
for falling in ['true','false']:
|
||||
for level in range(1,9):yield {'id':name,'properties':{'falling':falling,'level':str(level)}}
|
||||
|
||||
|
||||
def main():
|
||||
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--prepare',action='store_true');args=parser.parse_args()
|
||||
build=lab.LOCAL/'rust-fluid-parity';build.mkdir(parents=True,exist_ok=True)
|
||||
@@ -45,7 +60,8 @@ def main():
|
||||
if facts!=json.loads((build/'facts-client.json').read_text()):raise ValueError('reference block-state registries differ')
|
||||
if len(facts['states'])!=35723:raise ValueError('incomplete pinned block-state registry')
|
||||
fixtures=list(corpus(facts));inputs=build/'inputs.txt';inputs.write_text(''.join(json.dumps(value,separators=(',',':'))+'\n' for value in fixtures),encoding='utf-8')
|
||||
fixture_paths=[inputs,build/'facts-client.json',build/'facts-server.json'];tested_fixtures=base.source_hashes(fixture_paths)
|
||||
codec_inputs=build/'codec-inputs.txt';codec_fixtures=list(codec_corpus());codec_inputs.write_text(''.join(json.dumps(v,separators=(',',':'))+'\n' for v in codec_fixtures),encoding='utf-8')
|
||||
fixture_paths=[inputs,codec_inputs,build/'facts-client.json',build/'facts-server.json'];tested_fixtures=base.source_hashes(fixture_paths)
|
||||
run(['cargo','build','--release','-p','horizon-world','--example','fluid_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'/('fluid_fixture.exe' if os.name=='nt' else 'fluid_fixture')
|
||||
@@ -55,7 +71,7 @@ def main():
|
||||
references.append({'side':side,'jar_sha256':lab.digest(jar,'sha256'),'output_sha256':lab.digest(reference,'sha256'),'matched_output_lines':matched})
|
||||
print(f'{side}: {matched:,} fluid 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(),'block_states':len(facts['states']),'fluid_kinds':5,'fixtures':len(fixtures),'requested_height_queries':len(fixtures)*2,'sources_sha256':tested_sources,'fixtures_sha256':tested_fixtures,'rust_output_sha256':lab.digest(build/'rust.txt','sha256'),'references':references,'scope':'Native fluid identity, amount, falling/source/full flags, own-height bits and legacy block conversion for every pinned block state; all fluid-family identity pairs. Surface and camera height query order, above-fluid family checks, source-only downward-face support checks, coordinate wrapping and injected query failures are compared. The fixture supplies stone/air support states; general block support shapes, fluid spreading/ticks, entities and rendering remain outside this comparison.'}
|
||||
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']),'fluid_kinds':5,'codec_fixtures':len(codec_fixtures),'fixtures':len(fixtures),'requested_height_queries':len(fixtures)*2,'sources_sha256':tested_sources,'fixtures_sha256':tested_fixtures,'rust_output_sha256':lab.digest(build/'rust.txt','sha256'),'references':references,'scope':'FluidState.CODEC decoding and encoding include all 37 states, object-only identifiers, lenient missing/invalid properties, Unicode integer levels and native defaults. Legacy conversion is checked for codec-derived fluid states as well. Native fluid identity, amount, falling/source/full flags, own-height bits and legacy block conversion for every pinned block state; all fluid-family identity pairs. Surface and camera height query order, above-fluid family checks, source-only downward-face support checks, coordinate wrapping and injected query failures are compared. The fixture supplies stone/air support states; general block support shapes, fluid spreading/ticks, entities and rendering remain outside this comparison.'}
|
||||
lab.write_json(report_path,report);print(f'Scoped fluid parity passed: {report_path}')
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user