Implement item templates and strict scalar stack validation

This commit is contained in:
Ludovic Marie committed 2026-10-07 08:50:15 +02:00
1 parent 1ff987590c
commit 0a582b56d6
7 files changed
+837

No files matched your search

@@ -0,0 +1,280 @@
{
"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": 3744,
"sources_sha256": {
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaItemTemplateOracle.java": "1d40c19f17ee8d666d40737af2301a5e57945626e93bf464682e7218767d34fa",
"tools/test_item_template_parity.py": "945e94f9562e63fdd7d560acf74bf6ada7f6a8ecf35dddb6b12f1bcc39f4e6a5",
"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/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/lib.rs": "32e4ab1773ffacd063ffacf10bd148d43e69fefaed7109b39bbff475417528e6",
"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/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/item_template_fixture.rs": "75350137e055a30ebc10c6fd09e9c53dfbbddb3acf7c440baeac752f1d3bb6af"
},
"fixtures_sha256": {
".local/rust-item-template-parity/inputs.txt": "0b58f234b8f8e705797d678c6b481b411064b9207af9b3b14bfeded8c28444b2"
},
"rust_output_sha256": "cd281b5adda0e521e767773b365f46c4a79a590c315c03629cee85a8ca94cb7b",
"references": [
{
"side": "client",
"jar_sha256": "4508d006323f24fa02876310c192d739af56516eb259000ac50f0909a68c9a2d",
"output_sha256": "cd281b5adda0e521e767773b365f46c4a79a590c315c03629cee85a8ca94cb7b",
"matched_output_lines": 518556
},
{
"side": "server",
"jar_sha256": "a362163eec5d1612d520772bc16e5b39c09e3b234fdc045f56bf544284ee8ae6",
"output_sha256": "cd281b5adda0e521e767773b365f46c4a79a590c315c03629cee85a8ca94cb7b",
"matched_output_lines": 518556
}
],
"scope": "Actual ItemStackTemplate constructors, fromStack/fromNonEmptyStack, withCount identity, current-prototype component queries, create/apply patch precedence, canonical EMPTY on failed strict validation, and ItemStack.applyComponentsAndValidate rollback. Real max-stack-size/max-damage/damage scalar components include redundant and removed patches and invalid counts. Contained component validation is a required Rust schema service and is not exercised by this scalar corpus. Component codecs, containers/bundle weight, use-remainder integration and complete gameplay integration remain pending."
}
@@ -0,0 +1,237 @@
use horizon_world::{
component_patch::{Patch, Prototype},
item_stack_refs::{ItemStacks, StackRef},
item_stack_storage::ItemStackData,
item_template::{self, ItemTemplate, ValidationRules},
};
use serde_json::Value;
use std::{
fs,
io::{self, Write},
path::Path,
};
type Stack = StackRef<u8, usize, i32>;
type Template = ItemTemplate<u8, usize, i32>;
struct Rules;
impl ValidationRules<u8, usize, i32> for Rules {
type ContentsError = std::convert::Infallible;
fn has_max_damage(&self, s: &ItemStackData<u8, usize, i32>) -> bool {
s.component(&1).is_some()
}
fn max_stack_size(&self, s: &ItemStackData<u8, usize, i32>) -> i32 {
s.component(&0).copied().unwrap_or(1)
}
fn validate_contents(
&self,
_: &ItemStackData<u8, usize, i32>,
) -> Result<(), Self::ContentsError> {
Ok(())
}
}
fn opt(v: Option<i32>) -> String {
v.map_or("none".into(), |v| v.to_string())
}
fn patch(v: &Value) -> Patch<usize, i32> {
Patch::new(v.as_array().unwrap().iter().map(|v| {
(
v[0].as_u64().unwrap() as usize,
v[1].as_i64().map(|n| n as i32),
)
}))
}
fn proto(v: &Value) -> Prototype<usize, i32> {
Prototype::new(v.as_array().unwrap().iter().map(|v| {
(
v[0].as_u64().unwrap() as usize,
v[1].as_i64().unwrap() as i32,
)
}))
}
fn patch_text(p: &Patch<usize, i32>) -> String {
p.entries()
.iter()
.map(|(k, v)| format!("{k}={}", opt(*v)))
.collect::<Vec<_>>()
.join(",")
}
fn all(
out: &mut dyn Write,
stacks: &[Stack],
templates: &[Option<Template>],
prototypes: &[Prototype<usize, i32>],
store: &ItemStacks<u8, usize, i32>,
) -> io::Result<()> {
for (i, s) in stacks.iter().enumerate() {
let data = s.read();
let values = (0..3)
.map(|k| opt(data.component(&k).copied()))
.collect::<Vec<_>>()
.join(",");
writeln!(
out,
"stack {i} {} {} {} {} {} {} {} | {} | {}",
s.same_reference(&store.empty()),
data.item(),
data.count,
data.count(),
data.pop_time,
data.is_empty(),
item_template::validate_strict(&data, &Rules).is_ok(),
values,
patch_text(&data.components.as_patch())
)?;
}
for (i, t) in templates.iter().enumerate() {
if let Some(t) = t {
let values = (0..3)
.map(|k| opt(t.component(&prototypes[t.item() as usize], &k).copied()))
.collect::<Vec<_>>()
.join(",");
writeln!(
out,
"template {i} {} {} | {} | {}",
t.item(),
t.count(),
values,
patch_text(t.patch())
)?;
} else {
writeln!(out, "template {i} none")?;
}
}
for a in 0..3 {
for b in a + 1..3 {
let same = match (&templates[a], &templates[b]) {
(None, None) => true,
(Some(a), Some(b)) => a.same_reference(b),
_ => false,
};
writeln!(
out,
"same {a} {b} {} {same}",
stacks[a].same_reference(&stacks[b])
)?;
}
}
Ok(())
}
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 store = ItemStacks::new(0);
let mut prototypes: Vec<_> = f["prototypes"]
.as_array()
.unwrap()
.iter()
.map(proto)
.collect();
let mut stacks: Vec<_> = f["stacks"]
.as_array()
.unwrap()
.iter()
.map(|v| {
let id = v["item"].as_i64().unwrap();
if id < 0 {
store.empty()
} else {
let s = store.create(
id as u8,
v["count"].as_i64().unwrap() as i32,
prototypes[id as usize].clone(),
);
s.write().pop_time = 5;
s.write().components.restore_patch(&patch(&v["patch"]));
s
}
})
.collect();
let mut templates: Vec<Option<Template>> = vec![None, None, None];
all(&mut out, &stacks, &templates, &prototypes, &store)?;
for op in f["ops"].as_array().unwrap() {
let a = op["a"].as_u64().unwrap() as usize;
let b = op["b"].as_u64().unwrap() as usize;
let n = op["count"].as_i64().unwrap() as i32;
let result: Result<(), ()> = (|| {
match op["kind"].as_str().unwrap() {
"new" => {
templates[b] = Some(
Template::new(
op["item"].as_u64().unwrap() as u8,
0,
n,
patch(&op["patch"]),
)
.map_err(|_| ())?,
)
}
"from" => {
templates[b] =
Some(Template::from_stack(&stacks[a].read(), 0).map_err(|_| ())?)
}
"from-nonempty" => {
templates[b] = Some(
Template::from_non_empty_stack(&stacks[a].read(), 0).map_err(|_| ())?,
)
}
"from-count" => {
templates[b] = Some(
Template::from_non_empty_stack_with_count(&stacks[a].read(), 0, n)
.map_err(|_| ())?,
)
}
"with" => {
templates[b] = Some(
templates[a]
.as_ref()
.ok_or(())?
.with_count(n)
.map_err(|_| ())?,
)
}
"create" => {
let t = templates[a].as_ref().ok_or(())?;
stacks[b] = t
.create(&store, prototypes[t.item() as usize].clone(), &Rules)
.0;
}
"apply" | "apply-count" => {
let t = templates[a].as_ref().ok_or(())?;
let count = if op["kind"] == "apply" { t.count() } else { n };
stacks[b] = t
.apply(
&store,
prototypes[t.item() as usize].clone(),
count,
&patch(&op["patch"]),
&Rules,
)
.0;
}
"validate-patch" => {
let _ = item_template::apply_validated(
&mut stacks[a].write(),
&patch(&op["patch"]),
&Rules,
);
}
"count" => stacks[a].write().count = n,
"prototype" => {
prototypes[op["item"].as_u64().unwrap() as usize] = proto(&op["prototype"])
}
_ => panic!(),
}
Ok(())
})();
writeln!(
out,
"result {}",
if result.is_ok() { "ok" } else { "error" }
)?;
all(&mut out, &stacks, &templates, &prototypes, &store)?;
}
}
Ok(())
}
+188
View File
@@ -0,0 +1,188 @@
//! Immutable item templates and strict stack validation. Template component
//! patches are interpreted against the current item prototype when used.
//! Component schemas supply typed size queries and contained-item validation.
use crate::{
component_patch::{Patch, Prototype},
item_stack_refs::{ItemStacks, StackRef},
item_stack_storage::ItemStackData,
};
use std::{fmt, rc::Rc};
pub trait ValidationRules<I, K, V> {
type ContentsError;
fn has_max_damage(&self, stack: &ItemStackData<I, K, V>) -> bool;
/// The component default is one, including on an empty stack.
fn max_stack_size(&self, stack: &ItemStackData<I, K, V>) -> i32;
/// Validate container sizes, then bundle sizes and weight, then charged
/// projectile sizes. Only the immediate contained sizes are checked.
fn validate_contents(&self, stack: &ItemStackData<I, K, V>) -> Result<(), Self::ContentsError>;
}
pub type Creation<I, K, V, E> = (StackRef<I, K, V>, Option<ValidationError<E>>);
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ValidationError<E> {
StackableDamageable,
Contents(E),
TooManyItems { count: i32, maximum: i32 },
}
pub fn validate_strict<
I: Copy + Eq,
K: Clone + Eq,
V: Clone + PartialEq,
R: ValidationRules<I, K, V>,
>(
stack: &ItemStackData<I, K, V>,
rules: &R,
) -> Result<(), ValidationError<R::ContentsError>> {
if rules.has_max_damage(stack) && rules.max_stack_size(stack) > 1 {
return Err(ValidationError::StackableDamageable);
}
rules
.validate_contents(stack)
.map_err(ValidationError::Contents)?;
let count = stack.count();
let maximum = rules.max_stack_size(stack);
if count > maximum {
return Err(ValidationError::TooManyItems { count, maximum });
}
Ok(())
}
/// A rejected patch restores the original raw patch, including redundant entries.
/// The error is returned for the caller's diagnostic logger.
pub fn apply_validated<
I: Copy + Eq,
K: Clone + Eq,
V: Clone + PartialEq,
R: ValidationRules<I, K, V>,
>(
stack: &mut ItemStackData<I, K, V>,
patch: &Patch<K, V>,
rules: &R,
) -> Result<(), ValidationError<R::ContentsError>> {
let previous = stack.components.as_patch();
stack.components.apply_patch(patch);
let result = validate_strict(stack, rules);
if result.is_err() {
stack.components.restore_patch(&previous);
}
result
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TemplateError {
EmptyItem,
EmptyStack,
}
impl fmt::Display for TemplateError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::EmptyItem => "Item must be non-empty",
Self::EmptyStack => "Stack must be non-empty",
})
}
}
impl std::error::Error for TemplateError {}
#[derive(Debug)]
struct Data<I, K, V> {
item: I,
air: I,
count: i32,
patch: Patch<K, V>,
}
#[derive(Debug)]
pub struct ItemTemplate<I, K, V>(Rc<Data<I, K, V>>);
impl<I, K, V> Clone for ItemTemplate<I, K, V> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<I: Copy + Eq, K: Clone + Eq, V: Clone + PartialEq> ItemTemplate<I, K, V> {
/// The native constructor rejects zero, but permits negative counts.
pub fn new(item: I, air: I, count: i32, patch: Patch<K, V>) -> Result<Self, TemplateError> {
if item == air || count == 0 {
return Err(TemplateError::EmptyItem);
}
Ok(Self(Rc::new(Data {
item,
air,
count,
patch,
})))
}
pub fn from_stack(stack: &ItemStackData<I, K, V>, air: I) -> Result<Self, TemplateError> {
Self::new(stack.item(), air, stack.count(), stack.visible_patch())
}
pub fn from_non_empty_stack(
stack: &ItemStackData<I, K, V>,
air: I,
) -> Result<Self, TemplateError> {
if stack.is_empty() {
return Err(TemplateError::EmptyStack);
}
Self::from_stack(stack, air)
}
pub fn from_non_empty_stack_with_count(
stack: &ItemStackData<I, K, V>,
air: I,
count: i32,
) -> Result<Self, TemplateError> {
if stack.is_empty() || count <= 0 {
return Err(TemplateError::EmptyStack);
}
Self::new(stack.item(), air, count, stack.visible_patch())
}
pub fn same_reference(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
pub fn item(&self) -> I {
self.0.item
}
pub fn count(&self) -> i32 {
self.0.count
}
pub fn patch(&self) -> &Patch<K, V> {
&self.0.patch
}
pub fn with_count(&self, count: i32) -> Result<Self, TemplateError> {
if count == self.count() {
return Ok(self.clone());
}
Self::new(self.item(), self.0.air, count, self.0.patch.clone())
}
pub fn component<'a>(&'a self, prototype: &'a Prototype<K, V>, key: &K) -> Option<&'a V> {
match self.0.patch.entries().iter().find(|(k, _)| k == key) {
Some((_, value)) => value.as_ref(),
None => prototype.get(key),
}
}
/// Invalid creations return the store's canonical EMPTY. The optional error
/// lets the caller log the rejected template without changing game behavior.
pub fn create<R: ValidationRules<I, K, V>>(
&self,
stacks: &ItemStacks<I, K, V>,
prototype: Prototype<K, V>,
rules: &R,
) -> Creation<I, K, V, R::ContentsError> {
self.apply(stacks, prototype, self.count(), &Patch::new([]), rules)
}
/// The supplied patch is the base; this template's patch takes precedence.
pub fn apply<R: ValidationRules<I, K, V>>(
&self,
stacks: &ItemStacks<I, K, V>,
prototype: Prototype<K, V>,
count: i32,
base: &Patch<K, V>,
rules: &R,
) -> Creation<I, K, V, R::ContentsError> {
let stack = stacks.create(self.item(), count, prototype);
{
let mut data = stack.write();
data.components.apply_patch(base);
data.components.apply_patch(self.patch());
}
let error = validate_strict(&stack.read(), rules).err();
if error.is_some() {
(stacks.empty(), error)
} else {
(stack, None)
}
}
}
+1
View File
@@ -49,6 +49,7 @@ pub mod interaction_shapes;
pub mod item_blocking;
pub mod item_durability;
pub mod item_stack_storage;
pub mod item_template;
pub mod item_use;
pub mod item_use_catalog;
pub mod item_use_lifecycle;
+18
View File
@@ -1814,3 +1814,21 @@ equipment packet construction, observer reactions, callback mutations/failures
and clearing a populated kinetic-enemy map. Targeted Clippy passes. Packet
encoding/delivery, the full kinetic-enemy map and combat, complete item/equip
effects and full gameplay integration remain pending.
`item_template` implements immutable template construction, conversion from
stacks, count replacement with native reference identity, current-prototype
component lookup, creation and patch precedence. Strict validation checks
damageable/stackable incompatibility before contained components and top-level
size. A required component-schema service handles contained validation. Rejected
creations return canonical EMPTY; rejected applied patches restore the exact
previous raw patch, including redundant entries.
`python3 tools/test_item_template_parity.py` compares actual ItemStackTemplate
and ItemStack validation with scalar max-stack-size/max-damage/damage components.
The [template report](../benchmarks/rust-item-template-2026-10-07/scoped-parity.json)
records **518,556 matching lines per JAR**, covering zero/negative/overflow-edge
counts, changed prototypes, component removals, aliasing and validation rollback.
Targeted Clippy passes. Contained components and bundle-weight validation are
not exercised by this corpus; their schema implementation, codecs, use-remainder
integration and complete gameplay integration remain pending.
@@ -0,0 +1,39 @@
package dev.horizonlab.parity;
import com.google.gson.*;import java.io.*;import java.lang.reflect.*;import java.nio.file.*;import java.util.*;
import net.minecraft.core.component.*;import net.minecraft.world.item.*;
/** Native template construction, patch precedence, validation and rollback. */
public final class VanillaItemTemplateOracle {
static DataComponentType<Integer>[] keys;
static Item[] items;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 String opt(Object o){return o==null||o==removed?"none":o.toString();}
static int kind(Item i){for(int k=0;k<items.length;k++)if(items[k]==i)return k;throw new AssertionError();}
static int key(Object k){for(int i=0;i<keys.length;i++)if(keys[i]==k)return i;throw new AssertionError();}
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();if(p.get(1).isJsonNull())b.remove(keys[p.get(0).getAsInt()]);else b.set(keys[p.get(0).getAsInt()],p.get(1).getAsInt());}return b.build();}
static String patchText(DataComponentPatch p)throws Exception{var j=new StringJoiner(",");for(var e:((Map<?,?>)patchMap.get(p)).entrySet())j.add(key(e.getKey())+"="+opt(e.getValue()));return j.toString();}
static void all(PrintWriter out,ItemStack[] stacks,ItemStackTemplate[] templates)throws Exception{
for(int i=0;i<3;i++){var s=stacks[i];var v=new StringJoiner(",");for(var k:keys)v.add(opt(s.get(k)));out.println("stack "+i+" "+(s==ItemStack.EMPTY)+" "+kind(s.getItem())+" "+count.getInt(s)+" "+s.getCount()+" "+s.getPopTime()+" "+s.isEmpty()+" "+ItemStack.validateStrict(s).isSuccess()+" | "+v+" | "+patchText(((PatchedDataComponentMap)components.get(s)).asPatch()));}
for(int i=0;i<3;i++){var t=templates[i];if(t==null){out.println("template "+i+" none");continue;}var v=new StringJoiner(",");for(var k:keys)v.add(opt(t.get(k)));out.println("template "+i+" "+kind(t.item().value())+" "+t.count()+" | "+v+" | "+patchText(t.components()));}
for(int a=0;a<3;a++)for(int b=a+1;b<3;b++)out.println("same "+a+" "+b+" "+(stacks[a]==stacks[b])+" "+(templates[a]==templates[b]));
}
public static void main(String[] args)throws Exception{
net.minecraft.SharedConstants.tryDetectVersion();net.minecraft.server.Bootstrap.bootStrap();keys=new DataComponentType[]{DataComponents.MAX_STACK_SIZE,DataComponents.MAX_DAMAGE,DataComponents.DAMAGE};items=new Item[]{Items.AIR,Items.STICK,Items.SHIELD};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 stacks=new ItemStack[3];var templates=new ItemStackTemplate[3];for(int i=0;i<3;i++){var v=f.getAsJsonArray("stacks").get(i).getAsJsonObject();int id=v.get("item").getAsInt();stacks[i]=id<0?ItemStack.EMPTY:new ItemStack(items[id],v.get("count").getAsInt());if(id>=0){stacks[i].setPopTime(5);((PatchedDataComponentMap)components.get(stacks[i])).restorePatch(patch(v.getAsJsonArray("patch")));}}all(out,stacks,templates);
for(var ov:f.getAsJsonArray("ops")){var op=ov.getAsJsonObject();int a=op.get("a").getAsInt(),b=op.get("b").getAsInt(),n=op.get("count").getAsInt();try{switch(op.get("kind").getAsString()){
case "new":templates[b]=new ItemStackTemplate(items[op.get("item").getAsInt()].builtInRegistryHolder(),n,patch(op.getAsJsonArray("patch")));break;
case "from":templates[b]=ItemStackTemplate.fromStack(stacks[a]);break;
case "from-nonempty":templates[b]=ItemStackTemplate.fromNonEmptyStack(stacks[a]);break;
case "from-count":templates[b]=ItemStackTemplate.fromNonEmptyStack(stacks[a],n);break;
case "with":templates[b]=templates[a].withCount(n);break;
case "create":stacks[b]=templates[a].create();break;
case "apply":stacks[b]=templates[a].apply(patch(op.getAsJsonArray("patch")));break;
case "apply-count":stacks[b]=templates[a].apply(n,patch(op.getAsJsonArray("patch")));break;
case "validate-patch":stacks[a].applyComponentsAndValidate(patch(op.getAsJsonArray("patch")));break;
case "count":stacks[a].setCount(n);break;
case "prototype":items[op.get("item").getAsInt()].builtInRegistryHolder().bindComponents(prototype(op.getAsJsonArray("prototype")));break;
default:throw new AssertionError();}out.println("result ok");}catch(IllegalStateException|NullPointerException e){out.println("result error");}all(out,stacks,templates);
}
}}
}
}
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env python3
"""Compare native item templates 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():
edges=[-2147483648,-1,0,1,2,64,99,2147483647]
def op(kind,**kw):
v=dict(kind=kind,a=0,b=1,count=1,item=1,patch=[],prototype=[]);v.update(kw);return v
def row(count=1,patch=None,ops=None):
return dict(prototypes=[[],[[0,64]],[[0,1],[1,10],[2,0]]],stacks=[dict(item=1,count=count,patch=patch or []),dict(item=2,count=1,patch=[]),dict(item=-1,count=0,patch=[])],ops=ops or [])
for count in edges:
for amount in edges:
for item in range(3):
for patch in [[],[[0,1],[1,0]],[[0,None]],[[0,64]],[[0,0]],[[1,10],[2,-1]]]:
yield row(count,patch,[op('new',item=item,count=count,patch=patch,b=0),op('with',count=amount),op('create',b=2),op('apply-count',count=amount,patch=[[0,99],[1,None]]),op('validate-patch',a=1,patch=[[0,1]])])
for kind in ['from','from-nonempty','from-count']:
for count in edges:
for amount in edges:
yield row(count,[[0,64],[1,None]],[op(kind,count=amount,b=0),op('prototype',prototype=[[0,2],[1,1]]),op('create',b=1),op('apply',b=2,patch=[[2,7]])])
rng=random.Random(0x54454d504c415445)
kinds=['new','from','from-nonempty','from-count','with','create','apply','apply-count','validate-patch','count','prototype']
def entries():return [[rng.randrange(3),rng.choice([None,*edges])] for _ in range(rng.randrange(6))]
for _ in range(2400):
f=row(rng.choice(edges),entries())
f['ops']=[op(rng.choice(kinds),a=rng.randrange(3),b=rng.randrange(3),count=rng.choice(edges),item=rng.randrange(3),patch=entries(),prototype=[[k,rng.choice(edges)] for k in rng.sample(range(3),rng.randrange(4))]) for _ in range(rng.randrange(10,26))]
yield f
def main():
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--prepare',action='store_true');args=parser.parse_args()
build=lab.LOCAL/'rust-item-template-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/VanillaItemTemplateOracle.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/item_template_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.VanillaItemTemplateOracle',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','item_template_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'/('item_template_fixture.exe' if os.name=='nt' else 'item_template_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:,} item template 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 ItemStackTemplate constructors, fromStack/fromNonEmptyStack, withCount identity, current-prototype component queries, create/apply patch precedence, canonical EMPTY on failed strict validation, and ItemStack.applyComponentsAndValidate rollback. Real max-stack-size/max-damage/damage scalar components include redundant and removed patches and invalid counts. Contained component validation is a required Rust schema service and is not exercised by this scalar corpus. Component codecs, containers/bundle weight, use-remainder integration and complete gameplay integration remain pending.'}
lab.write_json(report_path,report);print(f'Scoped item template parity passed: {report_path}')
if __name__=='__main__':main()