Add shared item references and native container transfer behavior

This commit is contained in:
Ludovic Marie committed 2026-10-07 07:41:29 +02:00
1 parent cda5895cab
commit 202dad8192
8 files changed
+944

No files matched your search

@@ -0,0 +1,272 @@
{
"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": 6273,
"sources_sha256": {
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaSimpleContainerOracle.java": "9757a90d83941614d94a089a60cc7309db617991e1d99a22d9f6b73c3b06a572",
"tools/test_simple_container_parity.py": "53e810759ea1e12025f419e2c89133e8eed2fb1f841388a753be14e4b2d304a1",
"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/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/item_blocking.rs": "f6eee0d6d177cc3148960122327ba1b459a2f0e85241c1d9a3e40f0b8c169296",
"crates/horizon-world/src/item_durability.rs": "9fdf835e5c7bd0e1dd63ef2ba0076b770cdd4d6d14cdcd11de27690f0702f94e",
"crates/horizon-world/src/item_stack_refs.rs": "1a83604c256a51898b59b0087c2378282bcebe7883add2c4634dc7f9183d6e49",
"crates/horizon-world/src/item_stack_storage.rs": "b4dcb83dcaa346848c5484161feb3e2cf08e83f7793d7ed83be25b14b9d12884",
"crates/horizon-world/src/item_use.rs": "1d0a3afa61b60d356e81a063da79ec6cd38730315976640a591325fc4c8ab98c",
"crates/horizon-world/src/item_use_catalog.rs": "a9b53d2e816583239a75c3c61e78dacc5e3b27dee595be34b1c7fa169f17a571",
"crates/horizon-world/src/item_use_lifecycle.rs": "f9b29f42a528493d0d2521110d4f6e0bc89af8f579d539648cb7c3a9e68e31cd",
"crates/horizon-world/src/item_use_start.rs": "9996a9b90c313925cd90e78c02880f2a1d2ae65aef53f4ce081578a9dcd10c62",
"crates/horizon-world/src/lib.rs": "2145c37c7daadf735451a1e3f8e39fff005243861d1d8261cdb557dea7b8c466",
"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/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_food.rs": "f188dc110745bcc7acc15e6c521db943b06b404f69cd251bf74a345516070304",
"crates/horizon-world/src/player_health.rs": "79ecb6b4d7a044dc98e5552c53a5ac2724545b1c1cec4d797eb52576728e3480",
"crates/horizon-world/src/player_hurt.rs": "99c9bbd8587ec2dc287806049897b8034d2f5349ad47fc497b70d54148844a36",
"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": "f417aab280331ddd6f0ca265a12c0130c78b9924f407c7e07f198140501e6010",
"crates/horizon-world/src/tick_data.rs": "f8d04a69ea263f4168bce33f92e5b4ee2fe07d7caf50a1621c6b3ef6eb2479f3",
"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/simple_container_fixture.rs": "72eeb6dd9ae37b35643d9231047785dae0307d396ec2850e865f18a554580928"
},
"fixtures_sha256": {
".local/rust-simple-container-parity/inputs.txt": "4335da72561507dd19276c020cd198aa0d91d9034839f83707fcf75b4cc3df6b"
},
"rust_output_sha256": "d8d71155d43f9cd6874344c27da2b0a07eaca7803592dfe53d98347c0dff12a5",
"references": [
{
"side": "client",
"jar_sha256": "4508d006323f24fa02876310c192d739af56516eb259000ac50f0909a68c9a2d",
"output_sha256": "d8d71155d43f9cd6874344c27da2b0a07eaca7803592dfe53d98347c0dff12a5",
"matched_output_lines": 590402
},
{
"side": "server",
"jar_sha256": "a362163eec5d1612d520772bc16e5b39c09e3b234fdc045f56bf544284ee8ae6",
"output_sha256": "d8d71155d43f9cd6874344c27da2b0a07eaca7803592dfe53d98347c0dff12a5",
"matched_output_lines": 590402
}
],
"scope": "Actual SimpleContainer get/set/add/removal, reverse remove-by-type, clear/remove-all, can-add and count queries over real shared ItemStack storage. Small native prototypes expose component equality and copy isolation; alias identities and raw/visible state are traced. Native size/change callbacks cover mutations and failures before/after storage writes. Rust uses production reference-counted stack storage and container methods. Persistence, recipe accounting, arbitrary getItem/setItem overrides, player inventory/menu transactions, full component values and complete gameplay integration remain pending."
}
@@ -0,0 +1,253 @@
use horizon_world::{
component_patch::{Patch, Prototype},
item_stack_refs::{ItemStacks, StackRef},
simple_container::{ContainerHooks, SimpleContainer},
};
use serde_json::Value;
use std::{
fs,
io::{self, Write},
path::Path,
};
type Stack = StackRef<u8, usize, i32>;
type Container = SimpleContainer<u8, usize, i32>;
fn integer(v: &Value, k: &str) -> i32 {
v[k].as_i64().unwrap() as i32
}
fn opt(v: Option<i32>) -> String {
v.map_or("none".into(), |v| v.to_string())
}
fn max(s: &Stack) -> i32 {
s.read().component(&0).copied().unwrap_or(1)
}
struct World {
out: io::BufWriter<fs::File>,
refs: Vec<Stack>,
ids: Vec<Stack>,
empty: Stack,
op: Value,
calls: i32,
}
impl World {
fn snapshot(&mut self, s: &Stack) -> String {
let id = self
.ids
.iter()
.position(|v| v.same_reference(s))
.unwrap_or_else(|| {
self.ids.push(s.clone());
self.ids.len() - 1
});
let s = s.read();
let patch = s.components.as_patch();
format!(
"{} {} {} {} {} {} {} | {} | {}",
id,
s.item(),
s.count,
s.count(),
s.pop_time,
s.is_empty(),
s.component(&0).copied().unwrap_or(1),
(0..3)
.map(|k| opt(s.component(&k).copied()))
.collect::<Vec<_>>()
.join(","),
patch
.entries()
.iter()
.map(|(k, v)| format!("{k}={}", opt(*v)))
.collect::<Vec<_>>()
.join(",")
)
}
fn all(&mut self, c: &Container) {
for i in 0..self.refs.len() {
let s = self.snapshot(&self.refs[i].clone());
writeln!(self.out, "ref {i} {s}").unwrap();
}
for (i, s) in c.items().iter().enumerate() {
let s = self.snapshot(s);
writeln!(self.out, "slot {i} {s}").unwrap();
}
let s = self.snapshot(&self.empty.clone());
writeln!(self.out, "empty {s}").unwrap();
writeln!(
self.out,
"container {} {} {} {} {}",
c.size(),
c.is_empty(),
c.count_item(0),
c.count_item(1),
c.count_item(2)
)
.unwrap();
}
fn event(&mut self, c: &mut Container, name: &str) -> Result<(), ()> {
self.calls += 1;
writeln!(self.out, "event {name} {}", self.calls).unwrap();
self.all(c);
if self.calls == integer(&self.op, "fail_at") {
return Err(());
}
if self.calls == integer(&self.op, "mutate_at") {
let i = integer(&self.op, "mutate_ref") as usize;
let mut s = self.refs[i].write();
s.count = integer(&self.op, "after_count");
s.components
.set(0, Some(integer(&self.op, "after_max")))
.map_err(|_| ())?;
drop(s);
let slot = integer(&self.op, "mutate_slot");
if slot >= 0 && (slot as usize) < c.size() {
c.items_mut()[slot as usize] =
self.refs[integer(&self.op, "replace_ref") as usize].clone();
}
}
Ok(())
}
}
impl ContainerHooks<u8, usize, i32> for World {
type Error = ();
fn max_stack_size(&mut self, c: &mut Container) -> Result<i32, ()> {
self.event(c, "max")?;
Ok(integer(&self.op, "max"))
}
fn item_max_stack_size(&self, s: &Stack) -> i32 {
max(s)
}
fn changed(&mut self, c: &mut Container) -> Result<(), ()> {
self.event(c, "changed")
}
}
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 prototypes: Vec<_> = f["prototypes"]
.as_array()
.unwrap()
.iter()
.map(|p| {
Prototype::new(p.as_array().unwrap().iter().map(|v| {
(
v[0].as_u64().unwrap() as usize,
v[1].as_i64().unwrap() as i32,
)
}))
})
.collect();
let stacks = ItemStacks::new(0);
let empty = stacks.empty();
let refs: Vec<_> = f["stacks"]
.as_array()
.unwrap()
.iter()
.map(|v| {
let item = integer(v, "item");
if item < 0 {
empty.clone()
} else {
let s = stacks.create(
item as u8,
integer(v, "count"),
prototypes[item as usize].clone(),
);
s.write().pop_time = integer(v, "pop");
s.write().components.restore_patch(&Patch::new(
v["patch"].as_array().unwrap().iter().map(|v| {
(
v[0].as_u64().unwrap() as usize,
v[1].as_i64().map(|n| n as i32),
)
}),
));
s
}
})
.collect();
let mut c = Container::from_items(
f["slots"]
.as_array()
.unwrap()
.iter()
.map(|i| refs[i.as_u64().unwrap() as usize].clone())
.collect(),
stacks.clone(),
);
let mut w = World {
out,
refs,
ids: vec![empty.clone()],
empty,
op: Value::Null,
calls: 0,
};
w.all(&c);
for op in f["ops"].as_array().unwrap() {
w.op = op.clone();
w.calls = 0;
let a = integer(op, "a") as usize;
let b = integer(op, "b") as usize;
let slot = integer(op, "slot");
let amount = integer(op, "amount");
let result = (|| -> Result<(), ()> {
match op["kind"].as_str().unwrap() {
"set" => c.set(slot, w.refs[a].clone(), &mut w).map_err(|_| ())?,
"add" => {
let input = w.refs[a].clone();
w.refs[b] = c.add(&input, &mut w).map_err(|_| ())?;
}
"remove" => w.refs[b] = c.remove(slot, amount, &mut w).map_err(|_| ())?,
"remove-type" => {
let i = integer(op, "item") as usize;
w.refs[b] = c
.remove_type(i as u8, prototypes[i].clone(), amount, &mut w)
.map_err(|_| ())?;
}
"no-update" => w.refs[b] = c.remove_no_update::<()>(slot).map_err(|_| ())?,
"clear" => c.clear(&mut w).map_err(|_| ())?,
"all" => {
let result = c.remove_all(&mut w).map_err(|_| ())?;
writeln!(w.out, "all-size {}", result.len()).unwrap();
for s in result {
let s = w.snapshot(&s);
writeln!(w.out, "removed {s}").unwrap();
}
}
"can-add" => {
let v = c.can_add(&w.refs[a], &w);
writeln!(w.out, "can-add {v}").unwrap();
}
"get" => w.refs[b] = c.get(slot),
"alias" => w.refs[b] = w.refs[a].clone(),
"copy" => w.refs[b] = stacks.copy(&w.refs[a]),
"count" => w.refs[a].write().count = amount,
"component" => {
w.refs[a]
.write()
.components
.set(
integer(op, "key") as usize,
op["value"].as_i64().map(|n| n as i32),
)
.map_err(|_| ())?;
}
_ => panic!("operation"),
}
Ok(())
})();
writeln!(
w.out,
"result {} {}",
if result.is_ok() { "ok" } else { "error" },
w.calls
)?;
w.all(&c);
}
out = w.out;
}
Ok(())
}
@@ -0,0 +1,64 @@
//! Shared stack identity for inventories. Cloning a reference retains the same
//! stack; `ItemStacks::copy` copies its value with copy-on-write components.
//! These references belong to the simulation thread and release unreachable
//! stacks automatically. No borrow is held across a container callback.
use crate::{
component_patch::Prototype,
item_stack_storage::{CopyResult, ItemStackData},
};
use std::{
cell::{Ref, RefCell, RefMut},
rc::Rc,
};
#[derive(Debug)]
pub struct StackRef<I, K, V>(Rc<RefCell<ItemStackData<I, K, V>>>);
impl<I, K, V> Clone for StackRef<I, K, V> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<I, K, V> StackRef<I, K, V> {
pub fn new(data: ItemStackData<I, K, V>) -> Self {
Self(Rc::new(RefCell::new(data)))
}
pub fn read(&self) -> Ref<'_, ItemStackData<I, K, V>> {
self.0.borrow()
}
pub fn write(&self) -> RefMut<'_, ItemStackData<I, K, V>> {
self.0.borrow_mut()
}
pub fn same_reference(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}
#[derive(Clone, Debug)]
pub struct ItemStacks<I, K, V> {
air: I,
empty: StackRef<I, K, V>,
}
impl<I: Copy + Eq, K: Clone + Eq, V: Clone + PartialEq> ItemStacks<I, K, V> {
pub fn new(air: I) -> Self {
Self {
air,
empty: StackRef::new(ItemStackData::new(air, air, 0, Prototype::new([]))),
}
}
pub fn empty(&self) -> StackRef<I, K, V> {
self.empty.clone()
}
pub fn create(&self, item: I, count: i32, prototype: Prototype<K, V>) -> StackRef<I, K, V> {
StackRef::new(ItemStackData::new(item, self.air, count, prototype))
}
pub fn resolve(&self, copy: CopyResult<ItemStackData<I, K, V>>) -> StackRef<I, K, V> {
match copy {
CopyResult::Empty => self.empty(),
CopyResult::Stack(data) => StackRef::new(data),
}
}
pub fn copy(&self, stack: &StackRef<I, K, V>) -> StackRef<I, K, V> {
self.resolve(stack.read().copy())
}
pub fn split(&self, stack: &StackRef<I, K, V>, amount: i32) -> StackRef<I, K, V> {
self.resolve(stack.write().split(amount))
}
}
+3
View File
@@ -93,3 +93,6 @@ pub mod world_ray;
pub mod worldgen;
pub const DATA_VERSION: i32 = 5023;
pub mod item_stack_refs;
pub mod simple_container;
@@ -0,0 +1,220 @@
//! SimpleContainer storage and transfers using shared stack references.
//! Item component semantics and the virtual size/change hooks are supplied by
//! the caller. Menu transactions, persistence and recipe accounting are separate.
use crate::{
component_patch::Prototype,
item_stack_refs::{ItemStacks, StackRef},
};
#[derive(Debug)]
pub enum ContainerError<E> {
Index,
Callback(E),
}
pub type ContainerResult<T, E> = Result<T, ContainerError<E>>;
#[derive(Debug)]
pub struct SimpleContainer<I, K, V> {
items: Vec<StackRef<I, K, V>>,
stacks: ItemStacks<I, K, V>,
}
pub trait ContainerHooks<I, K, V> {
type Error;
/// Native getMaxStackSize(), normally 99; called before the item's limit.
fn max_stack_size(
&mut self,
container: &mut SimpleContainer<I, K, V>,
) -> Result<i32, Self::Error>;
fn item_max_stack_size(&self, stack: &StackRef<I, K, V>) -> i32;
fn changed(&mut self, container: &mut SimpleContainer<I, K, V>) -> Result<(), Self::Error>;
}
impl<I: Copy + Eq, K: Clone + Eq, V: Clone + PartialEq> SimpleContainer<I, K, V> {
pub fn new(size: usize, stacks: ItemStacks<I, K, V>) -> Self {
Self {
items: vec![stacks.empty(); size],
stacks,
}
}
/// Like the native varargs constructor, this retains aliases without limits.
pub fn from_items(items: Vec<StackRef<I, K, V>>, stacks: ItemStacks<I, K, V>) -> Self {
Self { items, stacks }
}
pub fn items(&self) -> &[StackRef<I, K, V>] {
&self.items
}
pub fn items_mut(&mut self) -> &mut [StackRef<I, K, V>] {
&mut self.items
}
pub fn size(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.iter().all(|s| s.read().is_empty())
}
pub fn get(&self, index: i32) -> StackRef<I, K, V> {
usize::try_from(index)
.ok()
.and_then(|i| self.items.get(i))
.cloned()
.unwrap_or_else(|| self.stacks.empty())
}
pub fn count_item(&self, item: I) -> i32 {
self.items.iter().fold(0_i32, |total, s| {
let s = s.read();
if s.item() == item {
total.wrapping_add(s.count())
} else {
total
}
})
}
pub fn can_add<H: ContainerHooks<I, K, V>>(
&self,
stack: &StackRef<I, K, V>,
hooks: &H,
) -> bool {
self.items.iter().any(|s| {
s.read().is_empty()
|| (s.read().same_item_components(&stack.read())
&& s.read().count() < hooks.item_max_stack_size(s))
})
}
fn limit<H: ContainerHooks<I, K, V>>(
&mut self,
stack: &StackRef<I, K, V>,
hooks: &mut H,
) -> Result<i32, ContainerError<H::Error>> {
let container = hooks
.max_stack_size(self)
.map_err(ContainerError::Callback)?;
Ok(container.min(hooks.item_max_stack_size(stack)))
}
pub fn set<H: ContainerHooks<I, K, V>>(
&mut self,
index: i32,
stack: StackRef<I, K, V>,
hooks: &mut H,
) -> Result<(), ContainerError<H::Error>> {
let slot = usize::try_from(index)
.ok()
.and_then(|i| self.items.get_mut(i))
.ok_or(ContainerError::Index)?;
*slot = stack.clone();
let limit = self.limit(&stack, hooks)?;
stack.write().limit_size(limit);
hooks.changed(self).map_err(ContainerError::Callback)
}
pub fn remove<H: ContainerHooks<I, K, V>>(
&mut self,
index: i32,
amount: i32,
hooks: &mut H,
) -> Result<StackRef<I, K, V>, ContainerError<H::Error>> {
let s = self.get(index);
let result = if amount > 0 && !s.read().is_empty() {
self.stacks.split(&s, amount)
} else {
self.stacks.empty()
};
if !result.read().is_empty() {
hooks.changed(self).map_err(ContainerError::Callback)?;
}
Ok(result)
}
pub fn remove_no_update<E>(
&mut self,
index: i32,
) -> Result<StackRef<I, K, V>, ContainerError<E>> {
let slot = usize::try_from(index)
.ok()
.and_then(|i| self.items.get_mut(i))
.ok_or(ContainerError::Index)?;
if slot.read().is_empty() {
Ok(self.stacks.empty())
} else {
Ok(std::mem::replace(slot, self.stacks.empty()))
}
}
pub fn remove_type<H: ContainerHooks<I, K, V>>(
&mut self,
item: I,
prototype: Prototype<K, V>,
amount: i32,
hooks: &mut H,
) -> Result<StackRef<I, K, V>, ContainerError<H::Error>> {
let result = self.stacks.create(item, 0, prototype);
for index in (0..self.size()).rev() {
let s = self.items[index].clone();
if s.read().item() == item {
let wanted = amount.wrapping_sub(result.read().count());
let removed = self.stacks.split(&s, wanted);
result.write().grow(removed.read().count());
if result.read().count() == amount {
break;
}
}
}
if !result.read().is_empty() {
hooks.changed(self).map_err(ContainerError::Callback)?;
}
Ok(result)
}
pub fn clear<H: ContainerHooks<I, K, V>>(
&mut self,
hooks: &mut H,
) -> Result<(), ContainerError<H::Error>> {
self.items.fill(self.stacks.empty());
hooks.changed(self).map_err(ContainerError::Callback)
}
pub fn remove_all<H: ContainerHooks<I, K, V>>(
&mut self,
hooks: &mut H,
) -> ContainerResult<Vec<StackRef<I, K, V>>, H::Error> {
let result = self
.items
.iter()
.filter(|s| !s.read().is_empty())
.cloned()
.collect();
self.clear(hooks)?;
Ok(result)
}
pub fn add<H: ContainerHooks<I, K, V>>(
&mut self,
stack: &StackRef<I, K, V>,
hooks: &mut H,
) -> Result<StackRef<I, K, V>, ContainerError<H::Error>> {
if stack.read().is_empty() {
return Ok(self.stacks.empty());
}
let remainder = self.stacks.copy(stack);
for index in 0..self.size() {
let target = self.items[index].clone();
if target.read().same_item_components(&remainder.read()) {
let limit = self.limit(&target, hooks)?;
let amount = remainder
.read()
.count()
.min(limit.wrapping_sub(target.read().count()));
if amount > 0 {
target.write().grow(amount);
remainder.write().shrink(amount);
hooks.changed(self).map_err(ContainerError::Callback)?;
}
if remainder.read().is_empty() {
return Ok(self.stacks.empty());
}
}
}
for index in 0..self.size() {
if self.items[index].read().is_empty() {
let moved = self.stacks.resolve(remainder.write().copy_and_clear());
self.set(index as i32, moved, hooks)?;
break;
}
}
if remainder.read().is_empty() {
Ok(self.stacks.empty())
} else {
Ok(remainder)
}
}
}
+18
View File
@@ -1646,3 +1646,21 @@ state, component patch order, stack identity and item/component/count equality.
Targeted Clippy passes. The fixture arena preserves canonical EMPTY aliases;
a production inventory, full component values/codecs and complete item-use,
equipment and game-tick integration remain pending.
`item_stack_refs` adds shared stack identity with automatic reference-counted
lifetime management on the simulation thread. `simple_container` uses these
references for get/set, merging, removals, reverse removal by type, clearing,
capacity checks and item counts. Copies retain independent component patches;
container slots and callers can deliberately share the same stack.
`python3 tools/test_simple_container_parity.py` compares actual native container
and stack methods, including changes and failures in virtual size/change hooks.
The [container report](../benchmarks/rust-simple-container-2026-10-07/scoped-parity.json)
records **590,402 matching lines per JAR**. It checks alias identity, raw/visible
counts, empty-stack references, component-sensitive merging, overflow, invalid
indices and mutation prefixes on failure. In particular, native insertion into
the first empty slot clears the remainder before limiting the inserted copy.
Targeted Clippy passes. Player inventory, menus, crafting accounting, persistence,
arbitrary getItem/setItem overrides and complete gameplay integration remain
pending. Reference counting here has not been benchmarked as a performance gain.
@@ -0,0 +1,28 @@
package dev.horizonlab.parity;
import com.google.gson.*;import com.mojang.serialization.Codec;import java.io.*;import java.lang.reflect.*;import java.nio.file.*;import java.util.*;
import net.minecraft.core.component.*;import net.minecraft.world.item.*;import net.minecraft.world.SimpleContainer;
/** Actual SimpleContainer methods over aliased ItemStack objects and bound prototypes. */
public final class VanillaSimpleContainerOracle {
static final class Stop extends RuntimeException {}
static Item[] items;static DataComponentType<Integer>[] keys;static Field components,count,patchMap;static Object removed;
static Field field(Class<?> c,String n)throws Exception{var f=c.getDeclaredField(n);f.setAccessible(true);return f;}
static int integer(JsonObject o,String k){return o.get(k).getAsInt();}
static int key(Object k){for(int i=0;i<keys.length;i++)if(keys[i]==k)return i;throw new AssertionError();}
static int item(Item i){for(int k=0;k<items.length;k++)if(items[k]==i)return k;throw new AssertionError();}
static String opt(Object v){return v==null||v==removed?"none":v.toString();}
static DataComponentMap prototype(JsonArray a){var b=DataComponentMap.builder();for(var e:a){var p=e.getAsJsonArray();b.set(keys[p.get(0).getAsInt()],p.get(1).getAsInt());}return b.build();}
static DataComponentPatch patch(JsonArray a){var b=DataComponentPatch.builder();for(var e:a){var p=e.getAsJsonArray();int k=p.get(0).getAsInt();if(p.get(1).isJsonNull())b.remove(keys[k]);else b.set(keys[k],p.get(1).getAsInt());}return b.build();}
static final class Data {
PrintWriter out;ItemStack[] refs;C c;JsonObject op;int calls;IdentityHashMap<ItemStack,Integer> identities=new IdentityHashMap<>();
int id(ItemStack s){return identities.computeIfAbsent(s,k->identities.size());}
String snapshot(ItemStack s){try{var raw=(PatchedDataComponentMap)components.get(s);var p=new StringJoiner(",");for(var e:((Map<?,?>)patchMap.get(raw.asPatch())).entrySet())p.add(key(e.getKey())+"="+opt(e.getValue()));var v=new StringJoiner(",");for(var k:keys)v.add(opt(s.get(k)));return id(s)+" "+item(s.getItem())+" "+count.getInt(s)+" "+s.getCount()+" "+s.getPopTime()+" "+s.isEmpty()+" "+s.getMaxStackSize()+" | "+v+" | "+p;}catch(Exception e){throw new AssertionError(e);}}
void all(){for(int i=0;i<refs.length;i++)out.println("ref "+i+" "+snapshot(refs[i]));for(int i=0;i<c.getContainerSize();i++)out.println("slot "+i+" "+snapshot(c.getItems().get(i)));out.println("empty "+snapshot(ItemStack.EMPTY));out.println("container "+c.getContainerSize()+" "+c.isEmpty()+" "+c.countItem(items[0])+" "+c.countItem(items[1])+" "+c.countItem(items[2]));}
void event(String name){calls++;out.println("event "+name+" "+calls);all();if(calls==integer(op,"fail_at"))throw new Stop();if(calls==integer(op,"mutate_at")){refs[integer(op,"mutate_ref")].setCount(integer(op,"after_count"));refs[integer(op,"mutate_ref")].set(DataComponents.MAX_STACK_SIZE,integer(op,"after_max"));int slot=integer(op,"mutate_slot");if(slot>=0&&slot<c.getContainerSize())c.getItems().set(slot,refs[integer(op,"replace_ref")]);}}
}
static final class C extends SimpleContainer {Data d;C(ItemStack[] slots){super(slots);}@Override public void setChanged(){d.event("changed");}@Override public int getMaxStackSize(){d.event("max");return integer(d.op,"max");}}
@SuppressWarnings("unchecked")public static void main(String[] args)throws Exception {
net.minecraft.SharedConstants.tryDetectVersion();net.minecraft.server.Bootstrap.bootStrap();items=new Item[]{Items.AIR,Items.STICK,Items.SHIELD};keys=new DataComponentType[]{DataComponents.MAX_STACK_SIZE,DataComponents.DAMAGE,DataComponentType.<Integer>builder().persistent(Codec.INT).build()};components=field(ItemStack.class,"components");count=field(ItemStack.class,"count");patchMap=field(DataComponentPatch.class,"map");removed=field(Class.forName("net.minecraft.core.component.Removed"),"INSTANCE").get(null);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();for(int i=0;i<3;i++)items[i].builtInRegistryHolder().bindComponents(prototype(f.getAsJsonArray("prototypes").get(i).getAsJsonArray()));ItemStack.EMPTY.setCount(0);ItemStack.EMPTY.setPopTime(0);((PatchedDataComponentMap)components.get(ItemStack.EMPTY)).clearPatch();var d=new Data();d.out=out;d.identities.put(ItemStack.EMPTY,0);d.refs=new ItemStack[f.getAsJsonArray("stacks").size()];for(int i=0;i<d.refs.length;i++){var v=f.getAsJsonArray("stacks").get(i).getAsJsonObject();int type=integer(v,"item");d.refs[i]=type<0?ItemStack.EMPTY:new ItemStack(items[type],integer(v,"count"));if(type>=0){d.refs[i].setPopTime(integer(v,"pop"));((PatchedDataComponentMap)components.get(d.refs[i])).restorePatch(patch(v.getAsJsonArray("patch")));}}var slots=new ItemStack[f.getAsJsonArray("slots").size()];for(int i=0;i<slots.length;i++)slots[i]=d.refs[f.getAsJsonArray("slots").get(i).getAsInt()];d.c=new C(slots);d.c.d=d;d.all();for(var ov:f.getAsJsonArray("ops")){var op=ov.getAsJsonObject();d.op=op;d.calls=0;int a=integer(op,"a"),b=integer(op,"b"),slot=integer(op,"slot"),amount=integer(op,"amount");try{switch(op.get("kind").getAsString()){
case "set":d.c.setItem(slot,d.refs[a]);break;case "add":d.refs[b]=d.c.addItem(d.refs[a]);break;case "remove":d.refs[b]=d.c.removeItem(slot,amount);break;case "remove-type":d.refs[b]=d.c.removeItemType(items[integer(op,"item")],amount);break;case "no-update":d.refs[b]=d.c.removeItemNoUpdate(slot);break;case "clear":d.c.clearContent();break;case "all":var result=d.c.removeAllItems();out.println("all-size "+result.size());for(var s:result)out.println("removed "+d.snapshot(s));break;case "can-add":out.println("can-add "+d.c.canAddItem(d.refs[a]));break;case "get":d.refs[b]=d.c.getItem(slot);break;case "alias":d.refs[b]=d.refs[a];break;case "copy":d.refs[b]=d.refs[a].copy();break;case "count":d.refs[a].setCount(amount);break;case "component":d.refs[a].set(keys[integer(op,"key")],op.get("value").isJsonNull()?null:integer(op,"value"));break;default:throw new AssertionError();}out.println("result ok "+d.calls);}catch(Stop|IndexOutOfBoundsException|NullPointerException e){out.println("result error "+d.calls);}d.all();}}}
}
}
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Compare native SimpleContainer transfers, shared stack identity and change callbacks."""
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():
kinds=['set','add','remove','remove-type','no-update','clear','all','can-add','get','alias','copy','count','component']
edges=[-2147483648,-1,0,1,2,63,64,65,99,100,2147483647]
def op(kind,**kw):
v=dict(kind=kind,a=0,b=3,slot=0,amount=1,item=1,max=99,fail_at=0,mutate_at=0,mutate_ref=0,after_count=2,after_max=8,mutate_slot=1,replace_ref=2,key=0,value=64);v.update(kw);return v
def stack(item,count):return dict(item=item,count=count,pop=7,patch=[])
def row(ops,slots=None,count=5):return dict(prototypes=[[],[[0,64]],[[0,1],[1,0]]],stacks=[stack(1,count),stack(1,60),stack(2,1),stack(-1,0)],slots=[1,3,3] if slots is None else slots,ops=ops)
for kind in kinds:
for count in edges:
for amount in edges:
yield row([op(kind,amount=amount),op('can-add'),op('get',slot=0),op('count',a=3,amount=3)],count=count)
for kind in ['set','add','remove','remove-type','no-update','get']:
for slot in [-2147483648,-1,0,1,2,3,2147483647]:
for slots in [[],[0],[0,0,0],[1,3,3]]:
for fail in range(1,5):
for mutate in [0,1,2]:
yield row([op(kind,slot=slot,fail_at=fail,mutate_at=mutate,amount=99)],slots=slots)
# Transfer limits differ from canAddItem; the first empty slot clears the
# remaining copy before setItem clamps it. Include zero/negative limits.
for limit in edges:
for size in edges:
for slots in [[3,3],[1,3],[1,1],[0,0]]:
v=row([op('can-add'),op('add',max=limit)],slots=slots,count=100)
v['prototypes'][1]=[[0,size]]
yield v
rng=random.Random(0x434f4e5441494e)
def integer():return rng.choice(edges) if rng.randrange(3) else rng.randrange(-2147483648,2147483648)
def patch():return [[rng.randrange(3),rng.choice([None,integer()])] for _ in range(rng.randrange(5))]
for _ in range(2200):
prototypes=[[[k,integer()] for k in rng.sample(range(3),rng.randrange(4))] for __ in range(3)]
stacks=[dict(item=rng.randrange(-1,3),count=integer(),pop=integer(),patch=patch()) for __ in range(4)]
slots=[rng.randrange(4) for __ in range(rng.choice([0,1,3,6]))]
ops=[op(rng.choice(kinds),a=rng.randrange(4),b=rng.randrange(4),slot=rng.randrange(-1,len(slots)+2),amount=integer(),item=rng.randrange(3),max=integer(),fail_at=rng.randrange(5),mutate_at=rng.randrange(4),mutate_ref=rng.randrange(4),after_count=integer(),after_max=integer(),mutate_slot=rng.randrange(-1,len(slots)+1),replace_ref=rng.randrange(4),key=rng.randrange(3),value=rng.choice([None,integer()])) for __ in range(16)]
yield dict(prototypes=prototypes,stacks=stacks,slots=slots,ops=ops)
def main():
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--prepare',action='store_true');args=parser.parse_args()
build=lab.LOCAL/'rust-simple-container-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/VanillaSimpleContainerOracle.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/simple_container_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.VanillaSimpleContainerOracle',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','simple_container_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'/('simple_container_fixture.exe' if os.name=='nt' else 'simple_container_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:,} simple container output lines match Rust',flush=True)
base.ensure_sources_unchanged(sources,tested_sources);base.ensure_sources_unchanged(fixture_paths,tested_fixtures)
report={'schema':1,'minecraft':lock['minecraft']['version'],'manifest_sha1':lock['minecraft']['manifest_sha1'],'platform':platform.platform(),'java':subprocess.check_output(['java','--version'],text=True).splitlines()[0],'rustc':subprocess.check_output(['rustc','--version'],text=True).strip(),'fixtures':len(fixtures),'sources_sha256':tested_sources,'fixtures_sha256':tested_fixtures,'rust_output_sha256':lab.digest(build/'rust.txt','sha256'),'references':references,'scope':'Actual SimpleContainer get/set/add/removal, reverse remove-by-type, clear/remove-all, can-add and count queries over real shared ItemStack storage. Small native prototypes expose component equality and copy isolation; alias identities and raw/visible state are traced. Native size/change callbacks cover mutations and failures before/after storage writes. Rust uses production reference-counted stack storage and container methods. Persistence, recipe accounting, arbitrary getItem/setItem overrides, player inventory/menu transactions, full component values and complete gameplay integration remain pending.'}
lab.write_json(report_path,report);print(f'Scoped simple container parity passed: {report_path}')
if __name__=='__main__':main()