Preserve native hash-map order for simulation callback storage

This commit is contained in:
Ludovic Marie
2026-10-07 09:09:41 +02:00
parent 12b61234b1
commit 118e93ea51
7 changed files with 1246 additions and 0 deletions
@@ -0,0 +1,283 @@
{
"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": 1000,
"sources_sha256": {
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaJavaHashMapOracle.java": "d76ec7bc7ceb9a646f79cd4c81b9b35a7a0a83eb2a9d9289ef7b57591f946c9c",
"tools/test_java_hash_map_parity.py": "54d784f085e16d768f55bbdea8e5e7c1b0945261db67f78163516d7cd2208b16",
"tools/test_rust_parity.py": "29d3db08005873528894b45ca10dcd6278753650473b3eb574e53e06ede40ec6",
"tools/lab.py": "d00bf107fa01b6c579734a082c3ca4ade3018f0d6851d46844acf17574f66e64",
"Cargo.toml": "3f93319c1eb70dbd7ba25cd74ef343fbf35c52c7c4752f955605c58699cbff9d",
"Cargo.lock": "6884c7209f007ab9ee742b9c3c73828cfa1c6753d35b5fe25a87cab5955b33f8",
"crates/horizon-core/Cargo.toml": "e21b502c949da93cf67826592459b687a8cbf737ef92fee514e3ed2cc7cd27ad",
"crates/horizon-world/Cargo.toml": "18bbad377a8047e4d4ecd0fc87d83d46d1c0f1ce2b8c47bbe64633e7b4420b57",
"crates/horizon-core/src/bin/density_parity.rs": "e5b1dd33b7d01306c73cf072629b4fb186e9ab87b672a00108999d1a72263fd0",
"crates/horizon-core/src/bin/float_log_parity.rs": "4a655fcf8822ee7668c4bd126bc84d0b118864a6fc7f5a6aeee667d8bf2590b1",
"crates/horizon-core/src/bin/geometry_parity.rs": "27f6c09fe5018ac3de8e70e0f0bbf78f9abb14f5e4783bcaf46e8ca87b9c6f8a",
"crates/horizon-core/src/bin/noise_parity.rs": "c135bfc708d853e7061e81487d2cfe10de64b2f65677d3b4837cbfe0b8341010",
"crates/horizon-core/src/bin/parity.rs": "f35d928c66f958de39fac5e7e836a657eed95f83599e84899f7ea7a5802ba481",
"crates/horizon-core/src/bin/tick_parity.rs": "a54c164fe4814034d369947a887f5273966f5a878ba849204b80d1c729526a8f",
"crates/horizon-core/src/biome/seed_hash.rs": "5afbb4921c750826b395a08bf06f382fc7f01b5759a93de02a2749c523e2a317",
"crates/horizon-core/src/biome.rs": "908efa8cd4aa0a7adf1cb5e1a222e3dfb640eed5e9172e0fe7f0d1287afae7e8",
"crates/horizon-core/src/carving/ellipsoid.rs": "09232a7588610e8a9176fd9c62d40afb1fb89f2ecab6d555536a1d847b142d86",
"crates/horizon-core/src/carving.rs": "0aa3093caa0437868a8c0ed52a6c6e1993bd51c03583c670a2837e749eae5426",
"crates/horizon-core/src/density/arithmetic.rs": "372faec96c923e2cf4aa6c66c1ac398e676853274557823850dbc8933dd15ab1",
"crates/horizon-core/src/density/beardifier.rs": "bb1052e27dae4a01954ca78d7d5babafef85f3b2c704ccaf1920cb85a098cb50",
"crates/horizon-core/src/density/cache.rs": "38d0b6c9dd04ffef979fdad3f29cfebf98d331c8c9d430be5f39aa34f6c30975",
"crates/horizon-core/src/density/end_islands.rs": "168b9384237bd2e41d0ae5a74e944da4dc74e493bdec31fb73184c9a49e3de55",
"crates/horizon-core/src/density/graph/compiler.rs": "ac67deeb16f16d0859aa20e5a165811a29aca0b910037ee6bf5098211f3a6ede",
"crates/horizon-core/src/density/graph/mod.rs": "b776e7da934cb03051a3053d56d461c71e9978e084922fe4194147aa580c07bf",
"crates/horizon-core/src/density/graph/seeded.rs": "6bcdcaa3dffcfa9df673bbbea35120057a16ba3d2b506c52709c36cf8976b74a",
"crates/horizon-core/src/density/graph/tests.rs": "6bfb8cbff462587dd147b0775ea01d370abbd97544b9bd596c792df1b5f7e634",
"crates/horizon-core/src/density/interpolation.rs": "8c890f52b6467f38a94c654986a6a484b8e0b296ab98c398e60a6ce465b5b010",
"crates/horizon-core/src/density/interval.rs": "b42629163baa6b599a233afe8596d1c370cd81d015cc6fc36a9663aa47b98424",
"crates/horizon-core/src/density/mod.rs": "ca0d77d3282e3746ddcbc92bee97dbf640b9a56214e6ac1537f51f9a5b63d6e7",
"crates/horizon-core/src/density/power.rs": "d5b7270a128d4264268cd772109ad16d71a8ec3ff2d3b63b84cb985296d54a91",
"crates/horizon-core/src/density/rounding.rs": "71840c5206ff8d218ac29bf6f66915d5212764ba270c675711a866ba5b55a7a6",
"crates/horizon-core/src/density/selection.rs": "0dd26af2e85004ec5e053039ad11c384c17c56ace9ab45eb3f5cb3503c0b0330",
"crates/horizon-core/src/density/slice.rs": "5d77605573c0deda47778f1f78f7fa3fbf1944d8f5efbcc65cf589181cadf80b",
"crates/horizon-core/src/density/spline.rs": "6bb2e40f940fc6544d6fb09cb0b8cac722be03bc663dbdfb0f61faae207400bc",
"crates/horizon-core/src/density/surface.rs": "159e0e69cda74f870e80ea64fe523c4397e64af4ccb861bb9fd07b2c3cb91b00",
"crates/horizon-core/src/density/terrain_noise.rs": "8d0059d25eb5d248cb97a4c5a2e670d61528928ea151495c004f25adb723fe3e",
"crates/horizon-core/src/density/tests.rs": "7817796ee40d0ae241bfbebec6bca190e0a8e7d5a1caa8ddf858c3eaa58b8858",
"crates/horizon-core/src/density/world_fields.rs": "c1ce305cb8046b384d90c564cafb24af7365d580389637910f3d8b0cc18eb583",
"crates/horizon-core/src/geometry/border.rs": "1386f8080521231d05ba3e84d94a3e1d5218d35ccb3d5e9fe2bbb05a8739e573",
"crates/horizon-core/src/geometry/mod.rs": "c650386f9860e44a96c55f18c8f1428ca715fcb0bc5c2434db5b1caa43df27fe",
"crates/horizon-core/src/geometry/movement.rs": "bcfb452752940ce53ae6dc267a3c4eb29459046a063c1f884684ab4f4bd0068f",
"crates/horizon-core/src/geometry/shape/create.rs": "189812b91d5e0e3ad963afcd1a6e2831b31b8188df91a904ef27061e644806ad",
"crates/horizon-core/src/geometry/shape/face.rs": "f243bce81384040a95ce7984b02b5699206c596c537b2713097e86005b4d3a5c",
"crates/horizon-core/src/geometry/shape/join.rs": "f1b51887b7bf9482557e3ffa99e136f2e5db07ceeb05fdb116adf45e87129075",
"crates/horizon-core/src/geometry/shape.rs": "e8d88a763de1525f77a30b99591641e8a8b80946263acbde035a9bcc356df960",
"crates/horizon-core/src/geometry/sweep.rs": "abd6009c61555161ef2f18b431b2aa384b126c0871cae8b96a62358498a56a1d",
"crates/horizon-core/src/geometry/traversal.rs": "77a3da570a0b85582b669cf4d841cba4b06327006dda26d4a26df4e8ce05bae4",
"crates/horizon-core/src/geometry/trig.rs": "05cef9341a298a474221a0556a11ddf47650393ea7a97b4b2022a4da6628fe37",
"crates/horizon-core/src/lib.rs": "4255e16837fde42a52ba118f60581d197c571bb530b60d635e506184ebf4db0b",
"crates/horizon-core/src/noise/mod.rs": "1dab5a713abf702402e69ace1bf9e476bba544b0ede5a61c3c3afc60af0a03f3",
"crates/horizon-core/src/noise/normal.rs": "e9e7a46472a54a02c98c46da819842090567153b32fe0c84249009ef19af7aad",
"crates/horizon-core/src/noise/perlin.rs": "e73815447432eab7542f67366cb3f1b368d164e33f6c9cdbd045ac8e4db0932a",
"crates/horizon-core/src/noise/simplex.rs": "6c0dbc15b2b7510195dd28fceca01dcaac1847ccc4a84d299c351589c642fe7a",
"crates/horizon-core/src/noise/stack.rs": "7f6ef0e7d920139ef1a6ad3ec5640f92765715f86dcc5ec29f1a149984f45fa3",
"crates/horizon-core/src/noise/volume.rs": "3f05d2b1780acfdfee60037677d309937a5033b45ef428fc2d540942d4b56b43",
"crates/horizon-core/src/position/iter.rs": "32d2d8e74821cc4e49e3354202d35d3120e4415bfdda9375a73f2137ef651129",
"crates/horizon-core/src/position.rs": "e10101088e6902386b9b6d27773d44312f1ff72bebb19e57967a54945dde9dcd",
"crates/horizon-core/src/random/hash.rs": "0f88a127a1ba2705d3d6c0ebd009324d6ba86ffa2d27edf2d2a84765e690e4a3",
"crates/horizon-core/src/random/positional.rs": "35494745e5d4cf89e282c3ae0ee245e9f2640ddbbc03bc0055df742006a9c862",
"crates/horizon-core/src/random/worldgen.rs": "9f07ff33bcc038d34e27aa5465753bb21df18f2975e43cae201f709bc186945a",
"crates/horizon-core/src/random.rs": "ddb95d3a83e28ad605ff1f49f5df270cc543ca5ef1130e37d989dc74c8d861e6",
"crates/horizon-core/src/storage.rs": "f6c32201c64aefde06e57a2c767be46918df613548a322801546b133799cc33d",
"crates/horizon-core/src/text.rs": "e6553ddb5db5039e8dc4614b6a6dc9f35a26dc3d1673b68a04e72e7983b67abb",
"crates/horizon-core/src/ticks/generation.rs": "be1237e790693f633a61714ddae68c6506a777588a8a3ab5efbe53a35774dbd2",
"crates/horizon-core/src/ticks/heap.rs": "bf28afab8af77c3d243aa96cd8a1fb8d934140a4dbd07dbfdbf4e7908bb4b845",
"crates/horizon-core/src/ticks/index.rs": "1f1a6a568c2a30eafecb020ca4d5f5fc414860de85b8b381fc419a2e3e65c24a",
"crates/horizon-core/src/ticks/mod.rs": "01634630668172516b8b79d0907bad47f6e2c543a6d499c2fa4b201823b375cb",
"crates/horizon-world/src/attribute_health.rs": "6135beb1baf9a55745ab95955bcd05e585e4042a6cffda0a14c13f05593e7186",
"crates/horizon-world/src/attributes/entity.rs": "56fb96b1beb9caaa769369bf7cddf522d2f2e84e241c213b51ae8d39d31a9f13",
"crates/horizon-world/src/attributes/mod.rs": "3d05ce2ff10c1b68540e3c87bbd2ac65c56a2e7b7127a7865b60890a2e9a690d",
"crates/horizon-world/src/attributes/operation_map.rs": "fc5bc8921d78ea6721a2eaa915e67483e2a33683927467bdba24f0492356ad97",
"crates/horizon-world/src/bin/worldgen_parity.rs": "3143ceb9b56eecfd7667e5feb5f9f0cd13cfb8754b38d4ea338dbba97f2819da",
"crates/horizon-world/src/block_collision.rs": "39207247f2f6dd3ddc77640229044246f91b32054563f88a435f1bd92ad2092c",
"crates/horizon-world/src/block_collision_scan.rs": "20802862364c110ff85eeaf48606596a8468b83768dda46b412d337958790b41",
"crates/horizon-world/src/block_entities.rs": "a9deae92e6e5a1fcf4f0476c33ea4d170ddad6fd4b3303e1bb66d933973d5e06",
"crates/horizon-world/src/block_entity_push.rs": "12ee91bf604946234b24a0da4333f07d1830ab9743a422d41c8d0afac7d49cfd",
"crates/horizon-world/src/block_landing.rs": "33083fe39266fbefec1b3ea1a19f2afc609791d189da247c895e116ad6eb266a",
"crates/horizon-world/src/block_placement.rs": "524f4892d50bab77b7d89d19f7b048ffe746996f2ed7f376db2c6ab00ed75c24",
"crates/horizon-world/src/block_properties.rs": "b0bd8a983336c48e488a20caa77dd5c39b1a74bbd14ebc03b3b64556a1c864fc",
"crates/horizon-world/src/block_render.rs": "8df52ee11aef406a1571198a64048062a0ef6864e0058d9293a57f64b73c916a",
"crates/horizon-world/src/block_support.rs": "ade4fbd47284b450dabdd682dc86138b2ac05a0fd379525d7110648908245476",
"crates/horizon-world/src/block_survival.rs": "28ce64375e09819a4f13da9cfbe37c08b5ad0daf01b289c1c360b4567e50e811",
"crates/horizon-world/src/blocking_item_damage.rs": "afea3cb5761e8b82ee4d9bb4ef3c6fd10182a324dbaec99e6c9ebfac255dda09",
"crates/horizon-world/src/blocking_rules.rs": "83c5e2105cec56a90182ce582e1c67ade2b189be6de1a34d08035000cc07c492",
"crates/horizon-world/src/bundle_weight.rs": "a0e7b0587ab5d46cd55588f25d55a088b7a4725099c13ba6df146957be36014c",
"crates/horizon-world/src/chunk.rs": "795895284d6e615bcb2082fceacdfe7025c152fb2934bb43f598f17a00ab46f1",
"crates/horizon-world/src/chunk_status.rs": "dbb8583cfa775203c544d24d69e03720385428f15a267a561356c21f5025e9c7",
"crates/horizon-world/src/climbing.rs": "6cd2f919872ff0b726effddaa57eccb805b8eae43f9d01144716010853891879",
"crates/horizon-world/src/collision.rs": "a749794d5c27ccd6c0d964ad02f9dc31d49d9f4fe4b7366cd4bd8155e681b00b",
"crates/horizon-world/src/collision_context.rs": "2176c7034e07f547510a8327cdad9d3b63f26e4754032b76b7d5fe13166c333c",
"crates/horizon-world/src/combat_rules.rs": "01131f70d1acdd96a910e7f96deaa12e51a1e3bb9208085f04e3ec7b657d3cd4",
"crates/horizon-world/src/component_durability.rs": "37a46e184f95bc5027e2b9af72ff52f729ad03601d08e1827f181fca383a35af",
"crates/horizon-world/src/component_patch.rs": "3622244ccdee46e13956c64ffe9be6234e686adf58dbc3a24cece0f1814301a1",
"crates/horizon-world/src/compression.rs": "4db73e6ca9a0d552d415ce60e7e88b89c9cf2b7d060a669ff8328f518316e101",
"crates/horizon-world/src/damage_immunity.rs": "fd39c41124d694e755cf7faadcf93c636df4042c78ec345092a856b5f952dbcf",
"crates/horizon-world/src/damage_reduction.rs": "f5a599ab11e077f526237018aeda803ea3c420c5b35c78ae9d85e32267e23bf3",
"crates/horizon-world/src/damage_source.rs": "24945e397a926d34695652980923609e4723e02fe6b6e56d4aaf673e45d759f7",
"crates/horizon-world/src/dynamic_support.rs": "5996bc1c436fb6215d8fc3d0bb4de5dd9b966d842d432580d624195771697fb8",
"crates/horizon-world/src/edge_backoff.rs": "5259d7aa44e64f88351d1556c44dd0edcad3b400a099c659755792efba7b5773",
"crates/horizon-world/src/entity_collision.rs": "09f2fd7f6cd56fc282f468ecfa765a94506929e9684bd3a5c90123e5b51cd627",
"crates/horizon-world/src/entity_fluid.rs": "02991040ae879a8914f09913128a3506e9e7a1ca33ffc0a22b5729a168346600",
"crates/horizon-world/src/entity_fluid_tick.rs": "4f9e070b88a73c98a4e2e659360ddd6edee636bca29377f1ea9011fd5a556f64",
"crates/horizon-world/src/entity_move.rs": "a40a50d3e841625a75d4cfbb7c2630ab5a62a574456567e7234f401ae8441b32",
"crates/horizon-world/src/entity_obstruction.rs": "a4b28a19bf83b23611c59d94535c488db37e4aee24b22c973c545910894a809f",
"crates/horizon-world/src/fall_damage.rs": "8c28e2933493569fe05dea22332024287d28b0746b514dd465681040b003296b",
"crates/horizon-world/src/fluid.rs": "a0a1f34ba94d8b59dc975becee8952960764d67ae08cf2d6a8bcd40a614b15c4",
"crates/horizon-world/src/fluid_box.rs": "b586af72b1c04a9354fe66205c28dc8b619e205ab9ea19a68232722e4b6e96c1",
"crates/horizon-world/src/fluid_flow.rs": "7c7e486b5c565df3602799648b37b879bcca51414337f607962d6c7951b86d05",
"crates/horizon-world/src/fluid_occupancy.rs": "26037579caeef6c8a5a2bde2c3d142d278558b76d77ebff401cee6e35f2ea961",
"crates/horizon-world/src/fluid_shape.rs": "28bb65a72f5bd074a354ba38a1b1707fcb0947537977a11540bba0adb85995c2",
"crates/horizon-world/src/food.rs": "3cf416fa632a5555a8116bb528a6e80bcb5b6b754b0748b4959ed310102418d3",
"crates/horizon-world/src/food_storage.rs": "58c433801a285efcc973638c11d694a41f85dc96703a3a7ce8d3673f3eb31d52",
"crates/horizon-world/src/free_space.rs": "913536bf4c85ddeeb378d76d1b5110b4175f5688e1a749f32fe6a6d86fbb478e",
"crates/horizon-world/src/ground_support.rs": "3e371d74ecede4d30beef0a7e8a2ee33463584a5b1ed3d852b394efcce1ffbe0",
"crates/horizon-world/src/heightmap.rs": "a5edef082b5af40d814421ea17e129b3b06d70abee6434ed263e4bba58571698",
"crates/horizon-world/src/interaction_shapes.rs": "f321284ddab440a394372b6dedc8b5cc29a653c0745251a9e96c650f21c33dea",
"crates/horizon-world/src/inventory_pickup.rs": "ea830c7916e7f2d95c6db7ef48be1e876e6ebafcb438e47fc72f9a5bd7c37d07",
"crates/horizon-world/src/inventory_tick.rs": "293a3d57a1689337cfd58e5a73dcdbed4cb360f94d98ff5458f0df92de387365",
"crates/horizon-world/src/inventory_use.rs": "6a6c2ecc73c83dda4cd798c0304df12ace6096eb110d899f4f0c7ffd852bf001",
"crates/horizon-world/src/item_blocking.rs": "f6eee0d6d177cc3148960122327ba1b459a2f0e85241c1d9a3e40f0b8c169296",
"crates/horizon-world/src/item_durability.rs": "9fdf835e5c7bd0e1dd63ef2ba0076b770cdd4d6d14cdcd11de27690f0702f94e",
"crates/horizon-world/src/item_stack_refs.rs": "18d3ca85cac0daf59200857513761359e5690f719cb3f7f64ae552f0c4169ea3",
"crates/horizon-world/src/item_stack_storage.rs": "b4dcb83dcaa346848c5484161feb3e2cf08e83f7793d7ed83be25b14b9d12884",
"crates/horizon-world/src/item_template.rs": "d9ab7958a55c695142403195244b14946caa2bf527bcbb4193b1372cd748e9a8",
"crates/horizon-world/src/item_use.rs": "b1c79428986efbf9dd5ede703a39eb387fb6dcc7d9950f0e49243a353a5b8070",
"crates/horizon-world/src/item_use_catalog.rs": "a9b53d2e816583239a75c3c61e78dacc5e3b27dee595be34b1c7fa169f17a571",
"crates/horizon-world/src/item_use_lifecycle.rs": "4639b70440cf811e79de09c48a3e035143fcb6be8a64c2f61b10ae55a2f133b7",
"crates/horizon-world/src/item_use_start.rs": "a84092dfb8b8f0a89d0928bb2f8ac252bd9bfd3f8d74fce1a7f7a5b3c3f4f50b",
"crates/horizon-world/src/java_hash_map.rs": "6bd97d87f0e3eaad440162145a1515b9a0b7cfb85cb0ea337874ed9745f8dd45",
"crates/horizon-world/src/lib.rs": "f4c5eae5d75b431d7d5fc1edc83a804d7405bf8fff0be4a3ad5dfa6bcfac7013",
"crates/horizon-world/src/liquid_collision.rs": "0f0a83b04e5a5bc9d98ed05fde4d6584ba69642e93522e726e4cfc325d6fcb1d",
"crates/horizon-world/src/living_air.rs": "b2de36bb50bed15e2808fe4a874fcef07f9fea0d2c96385b7b5e8ee9560d4442",
"crates/horizon-world/src/living_damage.rs": "2b448209629b9bf2e678d667ad0d6c7fa22146892dd106b169d96b31b0df12bb",
"crates/horizon-world/src/living_fall.rs": "da0f176f4731e1c86e08bfeee8167742fd1b86380ff0e9304c13c1ce3f1c67ab",
"crates/horizon-world/src/living_fluid.rs": "d7cd914cfb2a1f4876ce0ae95e999bf0ff1af732cce3ab4a3aa2d1ab881c7339",
"crates/horizon-world/src/living_health.rs": "221659f85552424e937d503bba6d8003006b106ced042b32d3a6f6cc23e12ed0",
"crates/horizon-world/src/living_hurt.rs": "844239ad7d15c39629bb3cfc06ebae6d1cff20b7627468f26e0ee8dff3abdcb8",
"crates/horizon-world/src/living_landing.rs": "8bca4eb7977abc2b14fb7174be4ea355352106ea1e76ff5f3ad8696969d9eefd",
"crates/horizon-world/src/living_motion.rs": "56f8c84cfbe205a7a69912d5f76b52ef1efca149c1b6801d4684e25fb179aeb9",
"crates/horizon-world/src/living_use_flags.rs": "826f4fdeba7e208368cbbf910fa408db0afbc6442d842d178a70fae53e0d0ea6",
"crates/horizon-world/src/main.rs": "fce57418b8c22a6a0a9044baa89ed3d9c243bc2e8413fea3ff0f32985daba021",
"crates/horizon-world/src/movement_emission.rs": "76e7d6f5b19c94676190f54389f9c4ce12cf89945ccfcb9c750de473223e7753",
"crates/horizon-world/src/movement_properties.rs": "6f01ab920b376a13f5ae12c3718f4dd067e1dff2b829585af00a8b2100f3775d",
"crates/horizon-world/src/movement_restitution.rs": "04b4fe0947e7e52576145bd8ed15920278e8a538afcc74d125eaca513dffa0ef",
"crates/horizon-world/src/movement_support.rs": "02d85cf572847f2e60b5a7f9d60b856888a67b3c1f4df03e81998c66fdf874be",
"crates/horizon-world/src/nbt.rs": "60262c3de8c8f68bc2da0370ccb17393d32b85f5f5022c6358599a7d32119ea6",
"crates/horizon-world/src/piston_movement.rs": "7a3fd2549a582b5f3a5c21aa05d67d944d62ca1105856679e100ac5b44e9a52f",
"crates/horizon-world/src/piston_shape.rs": "399c2337103b8e7e0eb5667227c5aa14f9549d6a467b7be7da3d0717f0263500",
"crates/horizon-world/src/player_equipment.rs": "1fa8c53e67624c4641246249d79a800a28a4858c62482bd880b4e3b866b936ef",
"crates/horizon-world/src/player_food.rs": "f188dc110745bcc7acc15e6c521db943b06b404f69cd251bf74a345516070304",
"crates/horizon-world/src/player_health.rs": "79ecb6b4d7a044dc98e5552c53a5ac2724545b1c1cec4d797eb52576728e3480",
"crates/horizon-world/src/player_hurt.rs": "99c9bbd8587ec2dc287806049897b8034d2f5349ad47fc497b70d54148844a36",
"crates/horizon-world/src/player_inventory.rs": "f4f67d8312793f25930626c4ac06db688fcf2e2292d6675071d105fb1708d952",
"crates/horizon-world/src/player_travel.rs": "6841a677a900495eb6223031ef3ebe8d859bb98908dda0e2209e5f28839dc593",
"crates/horizon-world/src/powder_snow_collision.rs": "7289946a21478d11abfd2bdcdddff3d7f98e25bf6a68564fed45c3cc01ac2a36",
"crates/horizon-world/src/region.rs": "72b642e87fed37ed17f54d4c30f96c3b64d26c14bc0589c31ef40ff1616188fc",
"crates/horizon-world/src/registry/json.rs": "7a683afcd1742c5307756927d7f0aa779c7d7992af87d8d371dd98108728e235",
"crates/horizon-world/src/registry.rs": "f2e58b2b4d944ac8fc6226bd3352cefc3d2052d8473e02ccf7dc402b176df435",
"crates/horizon-world/src/registry_collision_scan.rs": "97cc950a9a4ba387b78e368f36d595f8664ab7730d132900d220ce23b92826ea",
"crates/horizon-world/src/registry_fall_ray.rs": "52935436132df505691144840dcbd858b15d00d8305997284e3a542ecf6bc0dc",
"crates/horizon-world/src/registry_fluid.rs": "b8959c05850cfeaaad1e4de8ca7c7d0d6ac56da9b2c1de3ebefa5871a11ed35e",
"crates/horizon-world/src/retrogen.rs": "6efd36a6293756688c1990a7965bd65609d7c5e2bf2a5f4f01d54932d2b9386b",
"crates/horizon-world/src/server_player_combat.rs": "a9743971581af86d926eeba42004d932caf83382c470dd98bf613cb9c417db58",
"crates/horizon-world/src/server_player_damage.rs": "828a4649fec3e9bda2dfe20aced8c95922c697321de2be4127bd4e5712ecbb7c",
"crates/horizon-world/src/simple_container.rs": "0fedbc7e974b1db79b88bd6aff977654189a5d553cf42852fe8bf0885cf90b30",
"crates/horizon-world/src/suffocation.rs": "bed219dd5bbab6263b98fbe3d0eb512cb96c52ae847210efe49514d05f22f11e",
"crates/horizon-world/src/swimming.rs": "49d2dae13c109b37ff832cde98a857944ff45247b864a527b9c4f03ecca7a7b7",
"crates/horizon-world/src/synced_floats.rs": "0152f2752bafaf68769d56dbc88494a976496a680c6b113d6b48a446158ba072",
"crates/horizon-world/src/synced_values.rs": "adffa15026497d6671ffd12e5e17df9329c93f0e022700cdfebb80ab494382ae",
"crates/horizon-world/src/tick_data.rs": "f8d04a69ea263f4168bce33f92e5b4ee2fe07d7caf50a1621c6b3ef6eb2479f3",
"crates/horizon-world/src/use_remainder.rs": "50f0ac128bfcc5c9b2a43bfbb4f0d46f63693bea3bdcb64b15318a3dec28b9d5",
"crates/horizon-world/src/view_direction.rs": "e18120ae26dc5cf702b29fc4c8487088bab133c8ce5abce01226833fafb0d5a4",
"crates/horizon-world/src/water_splash.rs": "e0461ae1b2e8c851cca6e3251a188334293292201d7f80dc9e7d60fd1815f4d1",
"crates/horizon-world/src/world_movement.rs": "f8fe9e34f2395d2a04c839d1c8ba78e09ce493c26de6f6e4e237b9c19c061da5",
"crates/horizon-world/src/world_ray.rs": "879bdbbe12f56deb705cc183933431489e840b71eade40c33391eed5949c2e61",
"crates/horizon-world/src/worldgen/anchor.rs": "d156b8a0b147a274cdd143409b441f4f43edecde6e8ee14ef9cf0309f743143a",
"crates/horizon-world/src/worldgen/aquifer/config.rs": "fcd2cc3a520c1527c88f095a3b5d38487e7ebb1ccecc5f757f93d04a069add4f",
"crates/horizon-world/src/worldgen/aquifer/noise_based.rs": "74daaa389b5c3dfdc99214dfff256a9e172f83548d2326cbc941d9637cc53fb7",
"crates/horizon-world/src/worldgen/aquifer.rs": "cb4b66d87de3f9f79ae6ffe4badd6f0f44886cd42ad9de2771b8b56c4f1e28c7",
"crates/horizon-world/src/worldgen/bamboo.rs": "d9b47113c99be34256e58308bc6f40072ff25c579d6bf995182aa862c0006102",
"crates/horizon-world/src/worldgen/biome.rs": "3fe316b875aa32683759c337dc71f624910faf0812a2d6d83b8098d6d0bac7a0",
"crates/horizon-world/src/worldgen/biome_chunk.rs": "8fdfe6ebe3ffeca97611fd5991a5bc6b2783ea1c62f4d8ef3b2dd53c04a5dc1d",
"crates/horizon-world/src/worldgen/biome_predicate.rs": "bfc581bc40077cc74ffda43e990a55fe997adc04c7130f98e039c3305ca79aac",
"crates/horizon-world/src/worldgen/biome_source/codec.rs": "2b9e4f5d679eb444cb73174f511e3b9f32e9eb138248ab12cffc6cfd76adf3a8",
"crates/horizon-world/src/worldgen/biome_source/runtime.rs": "f0b02c1521178e4d0377c6ca62694604b6a773f1f234f070ff0cde4685911d45",
"crates/horizon-world/src/worldgen/biome_source.rs": "e181e1736f3e0b75f7091a24c88de3fd116e01b98424d02382aea7a503d1eb54",
"crates/horizon-world/src/worldgen/biome_temperature.rs": "cde4bbab5e260c4065b113376c423b8511ade93c5aa5fd976e245ee8a58b5ad1",
"crates/horizon-world/src/worldgen/biome_weather.rs": "96b1f9494559ed31d06257b83d604d00cc069ccc8c7b68094117e034b4a71bd7",
"crates/horizon-world/src/worldgen/block_blob.rs": "c608c57b3d77279646ecb89e50677dd8e452b0422ffd357ba755536c5589eb89",
"crates/horizon-world/src/worldgen/block_column.rs": "f72c21a9066ee0aa68c2fb79fba436d05afb14c6ef5a2cb012f1ed35fc17cd22",
"crates/horizon-world/src/worldgen/block_feature.rs": "36b4e46ee7f7f73bcb94d8bce8d99013e4b16234c9a03542eeb3186e88dd1c21",
"crates/horizon-world/src/worldgen/block_pile.rs": "623e369b77e0526ed2756485a6c0bb09683cd28ad8876dea907360ca6665b39d",
"crates/horizon-world/src/worldgen/block_predicate.rs": "074c692367e3f2191a1bb28d87b23402430a843c246bd30a4ea838ee3500280e",
"crates/horizon-world/src/worldgen/blue_ice.rs": "eedd77bdaff808330b864166d303378096daa5c7d235e925770b171c05109247",
"crates/horizon-world/src/worldgen/bonus_chest.rs": "05d0f63fbc7412f13ba1fa37a7238114b8f70bfff318beb2dece590482d49cc0",
"crates/horizon-world/src/worldgen/bulk_section.rs": "eecf61532d7793f853884c5a18a7f436a59835c7b13d3ec9075804511553c9ba",
"crates/horizon-world/src/worldgen/carver/canyon.rs": "509c4d5a9d689849e98e894ab14a9fbf82d10707d38e9cc688ded3c4778df3e2",
"crates/horizon-world/src/worldgen/carver/generation.rs": "a4498d0d1457536de3922a08e9c40ccce8d2ef9cc263801c15a412327513c098",
"crates/horizon-world/src/worldgen/carver.rs": "46b251e28225fe1250de38f49dec5dacda4e2c4ba1e556e21e6d1e14e2651fc3",
"crates/horizon-world/src/worldgen/carving.rs": "4e77d4e5c4a0ca55ca3563b9bdf6f379342e0bdf9d019d60f7bc57ce4afb5fbd",
"crates/horizon-world/src/worldgen/chorus_plant.rs": "29224c164ede919e280a65a68f155c873e2c8fd0aa7d7e244d8fa9e468760250",
"crates/horizon-world/src/worldgen/climate/codec.rs": "d567adeb5d837816fca69102db51d790f71aec1b51c09298230d24612e400a14",
"crates/horizon-world/src/worldgen/climate/index.rs": "c5ce61679a5f0e0f2f0af2a373424effa124d0cce8250609eff38b7034650756",
"crates/horizon-world/src/worldgen/climate.rs": "1b9ad44407f40aee4c1cd5357a5c9c443c1b105728f01cf5c644072f99f8357e",
"crates/horizon-world/src/worldgen/decoration.rs": "75a79b20b21e133816e729f16e758be6165d0db18a64bfbd5fd3618325a2adf3",
"crates/horizon-world/src/worldgen/delta.rs": "c2bf49ddf3231d28c109e68871429bc13d76a7bebe14eb33e84aa856bdd66145",
"crates/horizon-world/src/worldgen/density.rs": "65a98c156a290a6b374ef670d28cd5dfbe0aa93171824d1bbd96422536273f84",
"crates/horizon-world/src/worldgen/disk.rs": "6f8f9e059755af44c9bfa1b91eba54a7d13fad811dce31717c5502d7f6df33d7",
"crates/horizon-world/src/worldgen/end_gateway.rs": "f53fde77d6a36a525cd15d890003b2c129d0689a4cbfa2cf443a0c2e3acae040",
"crates/horizon-world/src/worldgen/end_podium.rs": "8f6d0d6d60ff0fde63de5781e867239db321f82cf12639f0537d410a3731ee1d",
"crates/horizon-world/src/worldgen/feature.rs": "40500af71ee6628dfb27518262d99f08d0383ae6c7b9397452feef0c213eadd9",
"crates/horizon-world/src/worldgen/feature_catalog.rs": "efc7b17b227e71622ef34108be9abd010f5675b68ea0409fcab82581d9aab88a",
"crates/horizon-world/src/worldgen/feature_graph.rs": "da132fca9fdafb0d89a917d5f4b68c60b70fb33cadf948a107da0e35d83dcd91",
"crates/horizon-world/src/worldgen/feature_region.rs": "df0ff142a461cafa9a3b42b949ad3376887f2be8d4ea5cc794a3ed2e977bb499",
"crates/horizon-world/src/worldgen/feature_sort.rs": "3488a093dfe1321aaa29d8a30cfb115d8e666a81bf195514e87b170de626835c",
"crates/horizon-world/src/worldgen/fluid_predicate.rs": "64197c9e63bebf1ce04bc280bfe980bb6c1b9aa887ca5cded904aeb0d9ae6c46",
"crates/horizon-world/src/worldgen/height_provider.rs": "368d4dc119854742a045c4a717679c921456da681fc5f71aa9b37102d6f33b47",
"crates/horizon-world/src/worldgen/material_condition/codec.rs": "09b909bc384472f76d163c8069ec6b507c7d5c6a028a36d5e0e3df20deff7b3b",
"crates/horizon-world/src/worldgen/material_condition/density.rs": "df9d0761e978e5010663ae8b44f2d6c1ecb4907331e333bdb6a2b487c1e107de",
"crates/horizon-world/src/worldgen/material_condition/library.rs": "a55534c5da97575a819af5a7dc0dbec9069993fa8b2619c6c9d5576946e683fa",
"crates/horizon-world/src/worldgen/material_condition/noise.rs": "ffb59cc6be2275d7a5621bf7d768527e74a8326ed7ad78618746711540921675",
"crates/horizon-world/src/worldgen/material_condition/rule.rs": "fed643352efbcb1f68f29b6241896617db889fc7c577a6247564e01922fec1fe",
"crates/horizon-world/src/worldgen/material_condition.rs": "d638dcb8cbcb5da20b3cb29602b0ae6a86c4fdf9d8c0fb725de8ec5fc108717e",
"crates/horizon-world/src/worldgen/material_extensions.rs": "ab806eb679d5116e1aebb64fca70e1499ae71f83c9507a8cb4c3201c2b1bf037",
"crates/horizon-world/src/worldgen/material_stage.rs": "698cbc786eff13c246e2bc2ea062401918cd4265899fbc3d53abc87e45a8e7a1",
"crates/horizon-world/src/worldgen/material_surface.rs": "5d37b90099df3d6da0845dab164e71469fb287019c2ee74bc6714f3b9d6d6d5b",
"crates/horizon-world/src/worldgen/ore_feature.rs": "83b89fd3be691c5412c0215b6abefdcaa44119a05aa41217e061970eb7e12ebd",
"crates/horizon-world/src/worldgen/placement/chain.rs": "9218399b4d3757f7bbc550d7729a7201f32a1c83a7030865e0c12aab8a80d116",
"crates/horizon-world/src/worldgen/placement/context.rs": "a278304795136677ad4b4933ea50c972b9729a1c671c03fa309c193e224b1fd6",
"crates/horizon-world/src/worldgen/placement/layer.rs": "a0f5ca776f33f9d4f72b8fdcd163426152e5e43cb4a7572fc1d4fc57bf965de1",
"crates/horizon-world/src/worldgen/placement.rs": "b0397e5818fae84358546193a95f84bcb0b5bffafce909e6fcb3386179ee8023",
"crates/horizon-world/src/worldgen/replace_blobs.rs": "bf3377d86d2570cd15288ba69dde64a2cf67c5bcbb9a31d0c23421964af74afa",
"crates/horizon-world/src/worldgen/router.rs": "2cee7cf15a0d2ada12be6b39d83e78177fd3033922e4f4cce87a64073cec2847",
"crates/horizon-world/src/worldgen/rule_test.rs": "d1662ec492489ebaa4b87e20f9a8c809dcf3a223a151211bd65ec241a63692fc",
"crates/horizon-world/src/worldgen/settings.rs": "a8fe87752e1982ef11cb67f8d80d8e3428b2c27db178044cb425ba803e689e59",
"crates/horizon-world/src/worldgen/simple_block.rs": "9ba1a88d5db4925f8c37366557887f776c805f9a6444781615b5dbaff52e92a4",
"crates/horizon-world/src/worldgen/snow_freeze.rs": "9040be3d5c7f8f0fd812d2df45e154bf8a9eeef038530b83fa4159d246eac35f",
"crates/horizon-world/src/worldgen/speleothem.rs": "c71651c1c97818a8a85863e14414d6139ea3bdeb897fa422043bcc1499d99aae",
"crates/horizon-world/src/worldgen/spike.rs": "eacf0d9d3d2bc3d4bcf62bc87555f90031138236a5bfef0eb5270204f7c2a4fc",
"crates/horizon-world/src/worldgen/spring.rs": "830849e9b89fcdf09e9b06fbefdcdebe3c8c3f82804f60b8bd5de04ba303cb62",
"crates/horizon-world/src/worldgen/state_provider/catalog.rs": "c8687e15a4887a9200c8d365857d801efaa8f90e669eee3e600a1db4905119eb",
"crates/horizon-world/src/worldgen/state_provider/noise.rs": "7ee369c2a032e5620cb9bdf9ee7adad1f70870fb0a27efb7b7c514d92f83491f",
"crates/horizon-world/src/worldgen/state_provider/properties.rs": "9909139aaca1dc4f743957257fadaa9d423d21fa401fa9abc050505f79365139",
"crates/horizon-world/src/worldgen/state_provider.rs": "be29ada818826a90afe01ab60916360fdfc4cbde5af15c9359cd56b1f1f7b156",
"crates/horizon-world/src/worldgen/tags.rs": "74e4110fb19c4c4047192fd65c38015b8afc7f9fc50404d75380b5063808148c",
"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/java_hash_map_fixture.rs": "ae5752e4556dcec72e1c83cce8342b638584ae33a102d31d48269db4e12e5778"
},
"fixtures_sha256": {
".local/rust-java-hash-map-parity/inputs.txt": "8b434acb30d982e9b5a92b71f5567685523aaf7212725d8978caf6ff32d423f2"
},
"rust_output_sha256": "6590c67cbf4e779bec60f612bad48431537fc5854483fc3ee6b25dbe03c67d5a",
"references": [
{
"side": "client",
"jar_sha256": "4508d006323f24fa02876310c192d739af56516eb259000ac50f0909a68c9a2d",
"output_sha256": "6590c67cbf4e779bec60f612bad48431537fc5854483fc3ee6b25dbe03c67d5a",
"matched_output_lines": 601084
},
{
"side": "server",
"jar_sha256": "a362163eec5d1612d520772bc16e5b39c09e3b234fdc045f56bf544284ee8ae6",
"output_sha256": "6590c67cbf4e779bec60f612bad48431537fc5854483fc3ee6b25dbe03c67d5a",
"matched_output_lines": 601084
}
],
"scope": "JDK 25 java.util.HashMap default-constructor storage used by vanilla ItemCooldowns, with non-null Comparable keys whose ordering agrees with equality. Direct put/get/remove/clear, linked bucket iteration, collision tree creation/insertion/deletion/splitting, iterator removal and concurrent modification prefixes are compared. Both pinned game classpaths use the same installed JDK implementation; this is a JDK collection comparison, not a gameplay parity test. Null/non-comparable keys, alternate constructors and other Map methods are outside this storage API. Concrete cooldowns, packets and gameplay integration remain pending."
}
@@ -0,0 +1,105 @@
use horizon_world::java_hash_map::{CursorError, JavaHashMap, JavaKey};
use serde_json::Value;
use std::{
cmp::Ordering,
fs,
io::{self, Write},
path::Path,
};
#[derive(Clone, Eq, PartialEq)]
struct Key {
id: usize,
hash: i32,
}
impl Ord for Key {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl PartialOrd for Key {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl JavaKey for Key {
fn java_hash(&self) -> i32 {
self.hash
}
}
fn opt(v: Option<i32>) -> String {
v.map_or("none".into(), |v| v.to_string())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let arg = std::env::args().nth(1).unwrap();
let dir = Path::new(&arg);
let mut out = io::BufWriter::new(fs::File::create(dir.join("rust.txt"))?);
for line in fs::read_to_string(dir.join("inputs.txt"))?.lines() {
let f: Value = serde_json::from_str(line)?;
let keys: Vec<_> = f["hashes"]
.as_array()
.unwrap()
.iter()
.enumerate()
.map(|(id, v)| Key {
id,
hash: v.as_i64().unwrap() as i32,
})
.collect();
let mut map = JavaHashMap::default();
let mut cursor = map.cursor();
for op in f["ops"].as_array().unwrap() {
let k = op[1].as_u64().unwrap() as usize;
let result: Result<String, CursorError> = match op[0].as_str().unwrap() {
"put" => Ok(format!(
"old {}",
opt(map.put(keys[k].clone(), op[2].as_i64().unwrap() as i32))
)),
"remove" => Ok(format!("old {}", opt(map.remove(&keys[k])))),
"get" => Ok(format!("get {}", opt(map.get(&keys[k]).copied()))),
"clear" => {
map.clear();
Ok("clear".into())
}
"cursor" => {
cursor = map.cursor();
Ok("cursor".into())
}
"next" | "force-next" => {
if cursor.has_next() || op[0] == "force-next" {
map.next_entry(&mut cursor).map(|e| {
e.map_or("next none".into(), |(k, v)| format!("next {}={v}", k.id))
})
} else {
Ok("next none".into())
}
}
"delete" => map.remove_current(&mut cursor).map(|()| "delete".into()),
_ => panic!(),
};
writeln!(
out,
"{}",
match result {
Ok(s) => s,
Err(CursorError::ConcurrentModification) => "error modified".into(),
Err(CursorError::NoCurrentEntry) => "error current".into(),
Err(e) => panic!("{e:?}"),
}
)?;
let entries = map
.entries()
.map(|(k, v)| format!("{}={v}", k.id))
.collect::<Vec<_>>()
.join(",");
writeln!(
out,
"map {} {} {} | {}",
map.len(),
map.is_empty(),
cursor.has_next(),
entries
)?;
}
}
Ok(())
}
+731
View File
@@ -0,0 +1,731 @@
//! Default-capacity Java HashMap traversal for non-null, consistently ordered
//! keys (such as Identifier). Tree bins preserve native linked iteration order.
//! This is the storage/iterator subset needed by simulation callback lifecycles.
use std::{cmp::Ordering, sync::Arc};
pub trait JavaKey: Ord {
fn java_hash(&self) -> i32;
}
type Link = Option<usize>;
struct Node<K, V> {
key: K,
value: V,
hash: i32,
next: Link,
prev: Link,
parent: Link,
left: Link,
right: Link,
red: bool,
tree: bool,
}
pub struct JavaHashMap<K, V> {
table: Vec<Link>,
nodes: Vec<Option<Node<K, V>>>,
free: Vec<usize>,
size: usize,
threshold: usize,
modification: u32,
owner: Arc<()>,
}
pub struct Cursor {
next: Link,
current: Link,
bucket: usize,
expected: u32,
owner: Arc<()>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CursorError {
ConcurrentModification,
NoCurrentEntry,
WrongMap,
}
impl Cursor {
pub fn has_next(&self) -> bool {
self.next.is_some()
}
}
impl<K: JavaKey, V> Default for JavaHashMap<K, V> {
fn default() -> Self {
Self {
table: Vec::new(),
nodes: Vec::new(),
free: Vec::new(),
size: 0,
threshold: 0,
modification: 0,
owner: Arc::new(()),
}
}
}
impl<K: JavaKey, V> JavaHashMap<K, V> {
fn node(&self, i: usize) -> &Node<K, V> {
self.nodes[i].as_ref().unwrap()
}
fn node_mut(&mut self, i: usize) -> &mut Node<K, V> {
self.nodes[i].as_mut().unwrap()
}
fn parent(&self, i: Link) -> Link {
i.and_then(|i| self.node(i).parent)
}
fn left(&self, i: Link) -> Link {
i.and_then(|i| self.node(i).left)
}
fn right(&self, i: Link) -> Link {
i.and_then(|i| self.node(i).right)
}
fn red(&self, i: Link) -> bool {
i.is_some_and(|i| self.node(i).red)
}
fn color(&mut self, i: Link, red: bool) {
if let Some(i) = i {
self.node_mut(i).red = red;
}
}
fn hash(key: &K) -> i32 {
let h = key.java_hash() as u32;
(h ^ (h >> 16)) as i32
}
fn allocate(&mut self, key: K, value: V, hash: i32) -> usize {
let node = Some(Node {
key,
value,
hash,
next: None,
prev: None,
parent: None,
left: None,
right: None,
red: false,
tree: false,
});
if let Some(i) = self.free.pop() {
self.nodes[i] = node;
i
} else {
self.nodes.push(node);
self.nodes.len() - 1
}
}
pub fn len(&self) -> usize {
self.size
}
pub fn is_empty(&self) -> bool {
self.size == 0
}
fn find(&self, key: &K) -> Link {
if self.table.is_empty() {
return None;
}
let h = Self::hash(key);
let mut p = self.table[h as usize & (self.table.len() - 1)];
if let Some(first) = p.filter(|i| self.node(*i).tree) {
p = Some(self.root(first));
while let Some(i) = p {
let node = self.node(i);
match h.cmp(&node.hash).then_with(|| key.cmp(&node.key)) {
Ordering::Equal => return Some(i),
Ordering::Less => p = node.left,
Ordering::Greater => p = node.right,
}
}
return None;
}
while let Some(i) = p {
let n = self.node(i);
if n.hash == h && n.key == *key {
return Some(i);
}
p = n.next;
}
None
}
pub fn get(&self, key: &K) -> Option<&V> {
self.find(key).map(|i| &self.node(i).value)
}
pub fn entries(&self) -> impl Iterator<Item = (&K, &V)> {
self.table
.iter()
.flat_map(|first| std::iter::successors(*first, |i| self.node(*i).next))
.map(|i| {
let n = self.node(i);
(&n.key, &n.value)
})
}
fn root(&self, mut p: usize) -> usize {
while let Some(parent) = self.node(p).parent {
p = parent;
}
p
}
fn compare(&self, a: usize, b: usize) -> Ordering {
self.node(a)
.hash
.cmp(&self.node(b).hash)
.then_with(|| self.node(a).key.cmp(&self.node(b).key))
}
fn rotate_left(&mut self, mut root: usize, p: usize) -> usize {
let Some(r) = self.node(p).right else {
return root;
};
let rl = self.node(r).left;
self.node_mut(p).right = rl;
if let Some(rl) = rl {
self.node_mut(rl).parent = Some(p);
}
let pp = self.node(p).parent;
self.node_mut(r).parent = pp;
if let Some(pp) = pp {
if self.node(pp).left == Some(p) {
self.node_mut(pp).left = Some(r);
} else {
self.node_mut(pp).right = Some(r);
}
} else {
root = r;
self.node_mut(r).red = false;
}
self.node_mut(r).left = Some(p);
self.node_mut(p).parent = Some(r);
root
}
fn rotate_right(&mut self, mut root: usize, p: usize) -> usize {
let Some(l) = self.node(p).left else {
return root;
};
let lr = self.node(l).right;
self.node_mut(p).left = lr;
if let Some(lr) = lr {
self.node_mut(lr).parent = Some(p);
}
let pp = self.node(p).parent;
self.node_mut(l).parent = pp;
if let Some(pp) = pp {
if self.node(pp).right == Some(p) {
self.node_mut(pp).right = Some(l);
} else {
self.node_mut(pp).left = Some(l);
}
} else {
root = l;
self.node_mut(l).red = false;
}
self.node_mut(l).right = Some(p);
self.node_mut(p).parent = Some(l);
root
}
fn balance_insert(&mut self, mut root: usize, mut x: usize) -> usize {
self.node_mut(x).red = true;
loop {
let Some(mut p) = self.node(x).parent else {
self.node_mut(x).red = false;
return x;
};
let Some(mut g) = self.node(p).parent else {
return root;
};
if !self.node(p).red {
return root;
}
let left = self.node(g).left == Some(p);
let uncle = if left {
self.node(g).right
} else {
self.node(g).left
};
if self.red(uncle) {
self.color(uncle, false);
self.node_mut(p).red = false;
self.node_mut(g).red = true;
x = g;
continue;
}
if (if left {
self.node(p).right
} else {
self.node(p).left
}) == Some(x)
{
x = p;
root = if left {
self.rotate_left(root, x)
} else {
self.rotate_right(root, x)
};
p = self.node(x).parent.unwrap();
g = self.node(p).parent.unwrap();
}
self.node_mut(p).red = false;
self.node_mut(g).red = true;
root = if left {
self.rotate_right(root, g)
} else {
self.rotate_left(root, g)
};
}
}
fn front(&mut self, bucket: usize, root: usize) {
let first = self.table[bucket];
if first == Some(root) {
return;
}
let (prev, next) = (self.node(root).prev, self.node(root).next);
if let Some(next) = next {
self.node_mut(next).prev = prev;
}
if let Some(prev) = prev {
self.node_mut(prev).next = next;
}
if let Some(first) = first {
self.node_mut(first).prev = Some(root);
}
self.node_mut(root).next = first;
self.node_mut(root).prev = None;
self.table[bucket] = Some(root);
}
fn treeify(&mut self, bucket: usize) {
let mut current = self.table[bucket];
let mut root = None;
while let Some(x) = current {
current = self.node(x).next;
{
let n = self.node_mut(x);
n.tree = true;
n.left = None;
n.right = None;
n.parent = None;
n.red = false;
}
if let Some(r) = root {
let mut p = r;
loop {
let left = self.compare(x, p) != Ordering::Greater;
let child = if left {
self.node(p).left
} else {
self.node(p).right
};
if let Some(c) = child {
p = c;
} else {
self.node_mut(x).parent = Some(p);
if left {
self.node_mut(p).left = Some(x);
} else {
self.node_mut(p).right = Some(x);
}
root = Some(self.balance_insert(r, x));
break;
}
}
} else {
root = Some(x);
}
}
if let Some(root) = root {
self.front(bucket, root);
}
}
fn untreeify(&mut self, mut p: Link) {
while let Some(i) = p {
let n = self.node_mut(i);
n.tree = false;
n.parent = None;
n.left = None;
n.right = None;
n.red = false;
p = n.next;
}
}
fn resize(&mut self) {
let old_len = self.table.len();
let new_len = if old_len == 0 { 16 } else { old_len * 2 };
let old = std::mem::replace(&mut self.table, vec![None; new_len]);
self.threshold = new_len * 3 / 4;
for (bucket, first) in old.into_iter().enumerate() {
let Some(first) = first else {
continue;
};
let tree = self.node(first).tree;
let mut groups = [Vec::new(), Vec::new()];
let mut p = Some(first);
while let Some(i) = p {
p = self.node(i).next;
groups[usize::from((self.node(i).hash as usize & old_len) != 0)].push(i);
}
for side in 0..2 {
let group = &groups[side];
if group.is_empty() {
continue;
}
let at = bucket + side * old_len;
self.table[at] = Some(group[0]);
for (j, &i) in group.iter().enumerate() {
let n = self.node_mut(i);
n.prev = j.checked_sub(1).map(|j| group[j]);
n.next = group.get(j + 1).copied();
}
if tree {
if group.len() <= 6 {
self.untreeify(Some(group[0]));
} else if !groups[1 - side].is_empty() {
self.treeify(at);
}
}
}
}
}
pub fn put(&mut self, key: K, value: V) -> Option<V> {
if let Some(i) = self.find(&key) {
return Some(std::mem::replace(&mut self.node_mut(i).value, value));
}
if self.table.is_empty() {
self.resize();
}
let hash = Self::hash(&key);
let bucket = hash as usize & (self.table.len() - 1);
let x = self.allocate(key, value, hash);
if let Some(first) = self.table[bucket] {
if self.node(first).tree {
self.node_mut(x).tree = true;
let root = self.root(first);
let mut p = root;
loop {
let left = self.compare(x, p) != Ordering::Greater;
let child = if left {
self.node(p).left
} else {
self.node(p).right
};
if let Some(child) = child {
p = child;
} else {
let next = self.node(p).next;
{
let n = self.node_mut(x);
n.parent = Some(p);
n.prev = Some(p);
n.next = next;
}
if let Some(next) = next {
self.node_mut(next).prev = Some(x);
}
self.node_mut(p).next = Some(x);
if left {
self.node_mut(p).left = Some(x);
} else {
self.node_mut(p).right = Some(x);
}
let root = self.balance_insert(root, x);
self.front(bucket, root);
break;
}
}
} else {
let mut tail = first;
let mut count = 1;
while let Some(next) = self.node(tail).next {
tail = next;
count += 1;
}
self.node_mut(tail).next = Some(x);
self.node_mut(x).prev = Some(tail);
if count >= 8 {
if self.table.len() < 64 {
self.resize();
} else {
self.treeify(bucket);
}
}
}
} else {
self.table[bucket] = Some(x);
}
self.size += 1;
self.modification = self.modification.wrapping_add(1);
if self.size > self.threshold {
self.resize();
}
None
}
fn balance_delete(&mut self, mut root: usize, mut x: Link) -> usize {
loop {
let Some(xi) = x else {
return root;
};
if xi == root {
return root;
}
let Some(p) = self.parent(x) else {
self.color(x, false);
return xi;
};
if self.red(x) {
self.color(x, false);
return root;
}
let left = self.left(Some(p)) == x;
let mut sibling = if left {
self.right(Some(p))
} else {
self.left(Some(p))
};
if self.red(sibling) {
self.color(sibling, false);
self.color(Some(p), true);
root = if left {
self.rotate_left(root, p)
} else {
self.rotate_right(root, p)
};
let parent = self.parent(x);
sibling = if left {
self.right(parent)
} else {
self.left(parent)
};
}
let parent = self.parent(x);
let Some(s) = sibling else {
x = parent;
continue;
};
let near = if left {
self.left(sibling)
} else {
self.right(sibling)
};
let far = if left {
self.right(sibling)
} else {
self.left(sibling)
};
if !self.red(near) && !self.red(far) {
self.color(sibling, true);
x = parent;
continue;
}
if !self.red(far) {
self.color(near, false);
self.color(sibling, true);
root = if left {
self.rotate_right(root, s)
} else {
self.rotate_left(root, s)
};
let parent = self.parent(x);
sibling = if left {
self.right(parent)
} else {
self.left(parent)
};
}
let parent = self.parent(x);
self.color(sibling, self.red(parent));
let far = if left {
self.right(sibling)
} else {
self.left(sibling)
};
self.color(far, false);
self.color(parent, false);
if let Some(parent) = parent {
root = if left {
self.rotate_left(root, parent)
} else {
self.rotate_right(root, parent)
};
}
x = Some(root);
}
}
fn remove_tree(&mut self, bucket: usize, p: usize, movable: bool) {
let first = self.table[bucket].unwrap();
let mut root = self.root(first);
let (prev, next) = (self.node(p).prev, self.node(p).next);
if let Some(prev) = prev {
self.node_mut(prev).next = next;
} else {
self.table[bucket] = next;
}
if let Some(next) = next {
self.node_mut(next).prev = prev;
}
if self.table[bucket].is_none() {
return;
}
if movable && (self.node(root).right.is_none() || self.left(self.node(root).left).is_none())
{
self.untreeify(self.table[bucket]);
return;
}
let (left, right) = (self.node(p).left, self.node(p).right);
let replacement;
if let (Some(left), Some(right)) = (left, right) {
let mut successor = right;
while let Some(l) = self.node(successor).left {
successor = l;
}
let red = self.node(successor).red;
self.node_mut(successor).red = self.node(p).red;
self.node_mut(p).red = red;
let sr = self.node(successor).right;
let pp = self.node(p).parent;
if successor == right {
self.node_mut(p).parent = Some(successor);
self.node_mut(successor).right = Some(p);
} else {
let sp = self.node(successor).parent;
self.node_mut(p).parent = sp;
if let Some(sp) = sp {
if self.node(sp).left == Some(successor) {
self.node_mut(sp).left = Some(p);
} else {
self.node_mut(sp).right = Some(p);
}
}
self.node_mut(successor).right = Some(right);
self.node_mut(right).parent = Some(successor);
}
self.node_mut(p).left = None;
self.node_mut(p).right = sr;
if let Some(sr) = sr {
self.node_mut(sr).parent = Some(p);
}
self.node_mut(successor).left = Some(left);
self.node_mut(left).parent = Some(successor);
self.node_mut(successor).parent = pp;
if let Some(pp) = pp {
if self.node(pp).left == Some(p) {
self.node_mut(pp).left = Some(successor);
} else {
self.node_mut(pp).right = Some(successor);
}
} else {
root = successor;
}
replacement = sr.unwrap_or(p);
} else {
replacement = left.or(right).unwrap_or(p);
}
if replacement != p {
let pp = self.node(p).parent;
self.node_mut(replacement).parent = pp;
if let Some(pp) = pp {
if self.node(pp).left == Some(p) {
self.node_mut(pp).left = Some(replacement);
} else {
self.node_mut(pp).right = Some(replacement);
}
} else {
root = replacement;
self.node_mut(replacement).red = false;
}
let n = self.node_mut(p);
n.left = None;
n.right = None;
n.parent = None;
}
if !self.node(p).red {
root = self.balance_delete(root, Some(replacement));
}
if replacement == p {
if let Some(pp) = self.node(p).parent {
self.node_mut(p).parent = None;
if self.node(pp).left == Some(p) {
self.node_mut(pp).left = None;
} else if self.node(pp).right == Some(p) {
self.node_mut(pp).right = None;
}
}
}
if movable {
self.front(bucket, root);
}
}
fn remove_node(&mut self, i: usize, movable: bool) -> V {
let bucket = self.node(i).hash as usize & (self.table.len() - 1);
if self.node(i).tree {
self.remove_tree(bucket, i, movable);
} else {
let (prev, next) = (self.node(i).prev, self.node(i).next);
if let Some(prev) = prev {
self.node_mut(prev).next = next;
} else {
self.table[bucket] = next;
}
if let Some(next) = next {
self.node_mut(next).prev = prev;
}
}
self.size -= 1;
self.modification = self.modification.wrapping_add(1);
let n = self.nodes[i].take().unwrap();
self.free.push(i);
n.value
}
pub fn remove(&mut self, key: &K) -> Option<V> {
self.find(key).map(|i| self.remove_node(i, true))
}
pub fn clear(&mut self) {
self.modification = self.modification.wrapping_add(1);
if self.size != 0 {
self.table.fill(None);
self.nodes.clear();
self.free.clear();
self.size = 0;
}
}
pub fn cursor(&self) -> Cursor {
let mut c = Cursor {
next: None,
current: None,
bucket: 0,
expected: self.modification,
owner: self.owner.clone(),
};
self.advance_bucket(&mut c);
c
}
fn advance_bucket(&self, c: &mut Cursor) {
while c.next.is_none() && c.bucket < self.table.len() {
c.next = self.table[c.bucket];
c.bucket += 1;
}
}
fn check_cursor(&self, c: &Cursor) -> Result<(), CursorError> {
if !Arc::ptr_eq(&self.owner, &c.owner) {
Err(CursorError::WrongMap)
} else if self.modification != c.expected {
Err(CursorError::ConcurrentModification)
} else {
Ok(())
}
}
/// Call while has_next is true. The returned values reflect replacements made
/// after iterator creation; structural changes are rejected before access.
pub fn next_entry(&self, c: &mut Cursor) -> Result<Option<(&K, &V)>, CursorError> {
self.check_cursor(c)?;
let Some(i) = c.next else {
return Ok(None);
};
c.current = Some(i);
c.next = self.node(i).next;
self.advance_bucket(c);
let n = self.node(i);
Ok(Some((&n.key, &n.value)))
}
pub fn remove_current(&mut self, c: &mut Cursor) -> Result<(), CursorError> {
if !Arc::ptr_eq(&self.owner, &c.owner) {
return Err(CursorError::WrongMap);
}
let Some(i) = c.current else {
return Err(CursorError::NoCurrentEntry);
};
self.check_cursor(c)?;
c.current = None;
self.remove_node(i, false);
c.expected = self.modification;
Ok(())
}
}
+1
View File
@@ -55,6 +55,7 @@ pub mod item_use;
pub mod item_use_catalog;
pub mod item_use_lifecycle;
pub mod item_use_start;
pub mod java_hash_map;
pub mod liquid_collision;
pub mod living_air;
pub mod living_damage;
+18
View File
@@ -1864,3 +1864,21 @@ counts, changed prototypes, cached errors, nested bundles, bee presence, empty
component visibility and validation order. Targeted Clippy passes. Typed schema
adapters remain fixture-local; complete bundle inventory operations, codecs,
item-use integration and full gameplay integration remain pending.
`java_hash_map` supplies default-capacity storage for non-null keys with native
hash codes and a total comparable ordering consistent with equality. It retains
linked bucket traversal, tree-bin root movement, red/black insertion/deletion,
resize splits, iterator removal and structural-modification checks. Tree lookup
uses the ordered tree; removed arena slots are reused.
`python3 tools/test_java_hash_map_parity.py` compares this API with the actual
JDK 25 HashMap used by vanilla cooldown storage. The
[map report](../benchmarks/rust-java-hash-map-2026-10-07/scoped-parity.json) records
**601,084 matching lines** for each pinned-game classpath run, including all-key
collisions, tree/list transitions, varied removal orders, iterator mutations
and clear-on-empty behavior. Both runs use the same installed JDK; this is a
collection comparison, not a gameplay parity claim. Targeted Clippy passes.
Null/non-comparable keys, alternate map constructors and unexposed Map methods
are outside this storage API. Concrete cooldown and gameplay integration remain
pending.
@@ -0,0 +1,19 @@
package dev.horizonlab.parity;
import com.google.gson.*;import java.io.*;import java.nio.file.*;import java.util.*;
/** The actual JDK HashMap used by vanilla cooldown storage, with ordered keys. */
public final class VanillaJavaHashMapOracle {
record Key(int id,int hash) implements Comparable<Key>{@Override public int hashCode(){return hash;}@Override public int compareTo(Key other){return Integer.compare(id,other.id);}}
static String opt(Integer value){return value==null?"none":value.toString();}
public static void main(String[] args)throws Exception{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 keys=new ArrayList<Key>();for(var h:f.getAsJsonArray("hashes"))keys.add(new Key(keys.size(),h.getAsInt()));var map=new HashMap<Key,Integer>();Iterator<Map.Entry<Key,Integer>> cursor=map.entrySet().iterator();for(var ov:f.getAsJsonArray("ops")){var op=ov.getAsJsonArray();int k=op.get(1).getAsInt();try{switch(op.get(0).getAsString()){
case "put":out.println("old "+opt(map.put(keys.get(k),op.get(2).getAsInt())));break;
case "remove":out.println("old "+opt(map.remove(keys.get(k))));break;
case "get":out.println("get "+opt(map.get(keys.get(k))));break;
case "clear":map.clear();out.println("clear");break;
case "cursor":cursor=map.entrySet().iterator();out.println("cursor");break;
case "next":if(cursor.hasNext()){var e=cursor.next();out.println("next "+e.getKey().id()+"="+e.getValue());}else out.println("next none");break;
case "force-next":{var e=cursor.next();out.println("next "+e.getKey().id()+"="+e.getValue());break;}
case "delete":cursor.remove();out.println("delete");break;
default:throw new AssertionError();}}catch(ConcurrentModificationException e){out.println("error modified");}catch(IllegalStateException e){out.println("error current");}catch(NoSuchElementException e){out.println("next none");}
var entries=new StringJoiner(",");for(var e:map.entrySet())entries.add(e.getKey().id()+"="+e.getValue());out.println("map "+map.size()+" "+map.isEmpty()+" "+cursor.hasNext()+" | "+entries);
}}}}
}
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""Compare native Java HashMaps and strict scalar stack validation."""
import argparse
import json
import os
from pathlib import Path
import platform
import subprocess
import random
import struct
import math
try:
from . import lab, test_rust_parity as base
except ImportError:
import lab
import test_rust_parity as base
def corpus():
rng=random.Random(0x4a415641484d4150)
def op(kind,k=0,v=0):return [kind,k,v]
def hashes(mode,n):
spread=[0,1,-1,64,128,192,256,512,1024,-2147483648,2147483647]
def unspread(h):
h&=0xffffffff;h^=h>>16;return h if h<0x80000000 else h-0x100000000
if mode==0:return [0]*n
if mode==1:return list(range(n))
if mode==2:return [unspread((i%8)*64) for i in range(n)]
if mode==3:return [unspread(rng.choice(spread)) for _ in range(n)]
return [rng.randrange(-2147483648,2147483648) for _ in range(n)]
for mode in range(5):
for n in [1,7,8,9,10,11,12,13,24,25,48,49,64,97,128]:
for order in range(6):
h=hashes(mode,n);ids=list(range(n))
if order==1:ids.reverse()
elif order>1:rng.shuffle(ids)
ops=[op('put',i,i) for i in ids]+[op('cursor')]
for i in range(n):
ops.append(op('next'))
if i%2==0:ops.append(op('delete'))
ops.extend([op('force-next'),op('delete')])
for i in reversed(ids):ops.extend([op('get',i),op('remove',i),op('put',i,-i)])
rng.shuffle(ids)
ops.extend(op('remove',i) for i in ids)
ops.extend([op('cursor'),op('clear'),op('next'),op('force-next'),op('delete')])
yield dict(hashes=h,ops=ops)
kinds=['put','put','remove','get','cursor','next','force-next','delete','clear']
for _ in range(550):
n=rng.choice([16,32,64,128]);h=hashes(rng.randrange(5),n);ids=list(range(n));rng.shuffle(ids)
ops=[op('put',i,i) for i in ids]
for __ in range(300):
k=rng.choice(kinds)
if k=='clear' and rng.randrange(20):k='remove'
ops.append(op(k,rng.randrange(n),rng.randrange(-2147483648,2147483648)))
yield dict(hashes=h,ops=ops)
def main():
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--prepare',action='store_true');args=parser.parse_args()
build=lab.LOCAL/'rust-java-hash-map-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/VanillaJavaHashMapOracle.java'
sources=[oracle,Path(__file__),lab.ROOT/'tools/test_rust_parity.py',lab.ROOT/'tools/lab.py',lab.ROOT/'Cargo.toml',lab.ROOT/'Cargo.lock',lab.ROOT/'crates/horizon-core/Cargo.toml',lab.ROOT/'crates/horizon-world/Cargo.toml',*sorted((lab.ROOT/'crates/horizon-core/src').rglob('*.rs')),*sorted((lab.ROOT/'crates/horizon-world/src').rglob('*.rs')),lab.ROOT/'crates/horizon-world/examples/java_hash_map_fixture.rs']
tested_sources=base.source_hashes(sources)
classes=build/'classes';classes.mkdir(exist_ok=True)
def run(command,name):
with (build/(name+'.log')).open('w',encoding='utf-8') as log:base.run(list(map(str,command)),stdout=log,stderr=subprocess.STDOUT)
dependency_path=os.pathsep.join(map(str,libraries))
run(['javac','--release',lock['minecraft']['java_major'],'-proc:none','-cp',str(jars['server'])+os.pathsep+dependency_path,'-d',classes,oracle],'compile-java')
def java(side,mode,path):
run(['java','-Xmx512M','-cp',os.pathsep.join([str(classes),str(jars[side]),dependency_path]),'dev.horizonlab.parity.VanillaJavaHashMapOracle',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','java_hash_map_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'/('java_hash_map_fixture.exe' if os.name=='nt' else 'java_hash_map_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:,} Java HashMap 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':'JDK 25 java.util.HashMap default-constructor storage used by vanilla ItemCooldowns, with non-null Comparable keys whose ordering agrees with equality. Direct put/get/remove/clear, linked bucket iteration, collision tree creation/insertion/deletion/splitting, iterator removal and concurrent modification prefixes are compared. Both pinned game classpaths use the same installed JDK implementation; this is a JDK collection comparison, not a gameplay parity test. Null/non-comparable keys, alternate constructors and other Map methods are outside this storage API. Concrete cooldowns, packets and gameplay integration remain pending.'}
lab.write_json(report_path,report);print(f'Scoped Java HashMap parity passed: {report_path}')
if __name__=='__main__':main()