Bind player health and combat to live attribute storage

This commit is contained in:
Ludovic Marie
2026-10-07 16:26:45 +02:00
parent 5eb1d61e3a
commit 7a0d413b44
7 changed files with 481 additions and 91 deletions
@@ -0,0 +1,315 @@
{
"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": 7465,
"sources_sha256": {
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaServerPlayerCombatOracle.java": "1c4fac076598ff3cb6e23059355781a42d5a992ac720fa3c6dc0f26131c30f08",
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaEntityAttributeOracle.java": "2ad3190a9798ab54bd12e88573028d0ca6a204e2f8a92018aae98b22335213bf",
"mods/horizon/src/test/java/dev/horizonlab/parity/VanillaPlayerHealthOracle.java": "5d6dc93c0140e2b2f953fba7290721079d5a607fa81b051e2ac1e4742ab606f2",
"tools/test_server_player_combat_parity.py": "f947183bb0e7bd870a3c9260e5c7d6dd06f1c8f37e338c79b56cfee47ada1fe6",
"tools/test_rust_parity.py": "29d3db08005873528894b45ca10dcd6278753650473b3eb574e53e06ede40ec6",
"tools/test_player_hurt_parity.py": "3164b8644664fcd46903e801ea70d1bb866e07e7112dc94570161831644bc84d",
"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/active_effect_tick.rs": "88f19cfc3532c47a58c646bb3e9d99ff239a900752302b6a444dda3013e95cbf",
"crates/horizon-world/src/active_effects.rs": "daaf352a69511a7d69fb329997f783b86585e486e0379c84ab0a55641771646c",
"crates/horizon-world/src/attribute_health.rs": "1420a80787d10dd2e2954a3ee6193ff313289d00c7c78ca26ece8bafa21f4380",
"crates/horizon-world/src/attribute_map.rs": "3d871cd530f5c035e0753f3ba065c2b9c5b49cdee75d4119f7dd584b22af67e6",
"crates/horizon-world/src/attribute_updates.rs": "4cb322d75a50d222298994607097ba7f7e6674021128fa02a98a74c057ad05f1",
"crates/horizon-world/src/attributes/entity.rs": "64ac99682a3aa06b1fb94b776b47794234c76b1cf70f1f54933d51e545e69279",
"crates/horizon-world/src/attributes/live.rs": "8198c45134f69135d48ef203e71b6e702529568fd1ed9174d0aa843570bbf9e7",
"crates/horizon-world/src/attributes/mod.rs": "5c2fcbbde58c19261874d227ea98332f00336c9fa53446da2e9adb6aa64a5e5a",
"crates/horizon-world/src/attributes/operation_map.rs": "fc5bc8921d78ea6721a2eaa915e67483e2a33683927467bdba24f0492356ad97",
"crates/horizon-world/src/bin/worldgen_parity.rs": "3143ceb9b56eecfd7667e5feb5f9f0cd13cfb8754b38d4ea338dbba97f2819da",
"crates/horizon-world/src/block_collision.rs": "39207247f2f6dd3ddc77640229044246f91b32054563f88a435f1bd92ad2092c",
"crates/horizon-world/src/block_collision_scan.rs": "20802862364c110ff85eeaf48606596a8468b83768dda46b412d337958790b41",
"crates/horizon-world/src/block_entities.rs": "a9deae92e6e5a1fcf4f0476c33ea4d170ddad6fd4b3303e1bb66d933973d5e06",
"crates/horizon-world/src/block_entity_push.rs": "12ee91bf604946234b24a0da4333f07d1830ab9743a422d41c8d0afac7d49cfd",
"crates/horizon-world/src/block_landing.rs": "33083fe39266fbefec1b3ea1a19f2afc609791d189da247c895e116ad6eb266a",
"crates/horizon-world/src/block_placement.rs": "524f4892d50bab77b7d89d19f7b048ffe746996f2ed7f376db2c6ab00ed75c24",
"crates/horizon-world/src/block_properties.rs": "b0bd8a983336c48e488a20caa77dd5c39b1a74bbd14ebc03b3b64556a1c864fc",
"crates/horizon-world/src/block_render.rs": "8df52ee11aef406a1571198a64048062a0ef6864e0058d9293a57f64b73c916a",
"crates/horizon-world/src/block_support.rs": "ade4fbd47284b450dabdd682dc86138b2ac05a0fd379525d7110648908245476",
"crates/horizon-world/src/block_survival.rs": "28ce64375e09819a4f13da9cfbe37c08b5ad0daf01b289c1c360b4567e50e811",
"crates/horizon-world/src/blocking_item_damage.rs": "afea3cb5761e8b82ee4d9bb4ef3c6fd10182a324dbaec99e6c9ebfac255dda09",
"crates/horizon-world/src/blocking_rules.rs": "83c5e2105cec56a90182ce582e1c67ade2b189be6de1a34d08035000cc07c492",
"crates/horizon-world/src/bundle_weight.rs": "a0e7b0587ab5d46cd55588f25d55a088b7a4725099c13ba6df146957be36014c",
"crates/horizon-world/src/chunk.rs": "795895284d6e615bcb2082fceacdfe7025c152fb2934bb43f598f17a00ab46f1",
"crates/horizon-world/src/chunk_status.rs": "dbb8583cfa775203c544d24d69e03720385428f15a267a561356c21f5025e9c7",
"crates/horizon-world/src/climbing.rs": "6cd2f919872ff0b726effddaa57eccb805b8eae43f9d01144716010853891879",
"crates/horizon-world/src/collision.rs": "a749794d5c27ccd6c0d964ad02f9dc31d49d9f4fe4b7366cd4bd8155e681b00b",
"crates/horizon-world/src/collision_context.rs": "2176c7034e07f547510a8327cdad9d3b63f26e4754032b76b7d5fe13166c333c",
"crates/horizon-world/src/combat_rules.rs": "01131f70d1acdd96a910e7f96deaa12e51a1e3bb9208085f04e3ec7b657d3cd4",
"crates/horizon-world/src/component_durability.rs": "37a46e184f95bc5027e2b9af72ff52f729ad03601d08e1827f181fca383a35af",
"crates/horizon-world/src/component_patch.rs": "f6f8992f241dfb25e012a06a7ba3fecab8d958686dddd096595a4806e56f0ab3",
"crates/horizon-world/src/compression.rs": "4db73e6ca9a0d552d415ce60e7e88b89c9cf2b7d060a669ff8328f518316e101",
"crates/horizon-world/src/consumable.rs": "ba3575cb85866cb940f33a1ac86455d71cf0cc6395b848588a8ee1fe33f5c326",
"crates/horizon-world/src/consume_effect.rs": "03f2aac6879ce133347d42f6f6667d62c06d956ff9faac5dc14182a788b6a236",
"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/effect_attribute_modifiers.rs": "0bc7ab63d0f3f34a7133fe20364cae0ec1fdbd3773cba90faa1f08e0d63a5646",
"crates/horizon-world/src/effect_notifications.rs": "ea66bfa010d6d44aee97b9672902f41cd99d0d80239f41c6d4eae5c9a9472d3d",
"crates/horizon-world/src/effect_particles.rs": "a42dc4ec55929dce1db0f22f8816ecf7621fdce1cd2ac0c90f6a57fea4e0afd2",
"crates/horizon-world/src/effect_sync.rs": "1388d4a69b42a14ff4cd474f5e36f0fad5a2874031e64fa2b19b2ea179deed2b",
"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/extra_items.rs": "6eba0a0c795d5fd841d31471708e78324b4852adebb2e6ed700dcc0caab668cd",
"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_properties.rs": "0926fa3f3bc3d0608c45d02f564355825ca3c3526a82bf9c1375c7a191fa5e12",
"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/identifier.rs": "37c921889c4f5d91f7c09ab2ee68d1a5e5a3c4fb1c49b4b189c987b4615fd2d6",
"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_after_use.rs": "2b6598ce5b7b304dea2c8057b4a1eb6530264ac4d0546c3da0c76deed9609da5",
"crates/horizon-world/src/item_blocking.rs": "f6eee0d6d177cc3148960122327ba1b459a2f0e85241c1d9a3e40f0b8c169296",
"crates/horizon-world/src/item_cooldowns.rs": "7b625868509ab3c51e72db0ac714bb0e7ec5e2610d37271005a1a737f4d14431",
"crates/horizon-world/src/item_durability.rs": "9fdf835e5c7bd0e1dd63ef2ba0076b770cdd4d6d14cdcd11de27690f0702f94e",
"crates/horizon-world/src/item_particles.rs": "861b14f65adb9b14f8158fe9f0b7128beac3df8107b1337c31b8b9b49434ba3f",
"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": "dc80025215d1867e656924ea2a9d273aacbcaea21293d986ba42d0004ee93b69",
"crates/horizon-world/src/item_use.rs": "b1c79428986efbf9dd5ede703a39eb387fb6dcc7d9950f0e49243a353a5b8070",
"crates/horizon-world/src/item_use_catalog.rs": "a9b53d2e816583239a75c3c61e78dacc5e3b27dee595be34b1c7fa169f17a571",
"crates/horizon-world/src/item_use_lifecycle.rs": "4639b70440cf811e79de09c48a3e035143fcb6be8a64c2f61b10ae55a2f133b7",
"crates/horizon-world/src/item_use_start.rs": "a84092dfb8b8f0a89d0928bb2f8ac252bd9bfd3f8d74fce1a7f7a5b3c3f4f50b",
"crates/horizon-world/src/java_hash_map.rs": "955502e696d7b0b33bae3ec485c8eb1453a8956116aad68226cf1fc67d60babc",
"crates/horizon-world/src/lib.rs": "577c16c021352b706d123f0f1c734375fc4a5a67b508caccbc38c1e1f693f6f4",
"crates/horizon-world/src/liquid_collision.rs": "0f0a83b04e5a5bc9d98ed05fde4d6584ba69642e93522e726e4cfc325d6fcb1d",
"crates/horizon-world/src/live_attribute_updates.rs": "778171faaaf7077deb0b62c4cc1db16351eba41adb8bb07656ba65e827056199",
"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/object_open_map.rs": "b4934a9cc38df93ed206ab0bc3bbc4499acd8e40b41b7def7d47067b7170065b",
"crates/horizon-world/src/object_open_set.rs": "d3e0373bf1b652dd054345d5a8e25ec828e06dd7cad65aada35163c95df4e637",
"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": "8155b315453c569db2fbe46228886c5881d1fd55eb095c5849e69bdb500ba2bd",
"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": "0a94885c4b7a0d294ba7f4cee18b96ee59649b50112988250b53cc224059a979",
"crates/horizon-world/src/server_player_damage.rs": "29af22dec321fe01776cee5334f050c5bc3e27a688f99c8c3da4c0ad8bc8254e",
"crates/horizon-world/src/simple_container.rs": "0fedbc7e974b1db79b88bd6aff977654189a5d553cf42852fe8bf0885cf90b30",
"crates/horizon-world/src/status_effect.rs": "588bfcf4d93f50be86cb89545bd5c431edbc71771f704ff55cb52906b1964c37",
"crates/horizon-world/src/stored_consume.rs": "621a52c9fba447c393e561f881a16cf1f97d336e3a0ce493725ef51e2db12ffd",
"crates/horizon-world/src/stored_effect_attributes.rs": "c79f6a52d3cfee1a5288225bf8fa91a7bf3ea8cd21faea9f6dc748ecefc6309a",
"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": "a1d4b53ae77d1899ba2b4ead67c9ec1e3c96615558e446f9d0760c1b4a520169",
"crates/horizon-world/src/teleport_consume.rs": "d6a53bbb6ac4dbbd4c0591d0646017898a95beb8ef093dc5d81b9833963be6c3",
"crates/horizon-world/src/tick_data.rs": "f8d04a69ea263f4168bce33f92e5b4ee2fe07d7caf50a1621c6b3ef6eb2479f3",
"crates/horizon-world/src/use_remainder.rs": "f555335afeca7970888131a6da2f5a614a73253b631185d1ba804593a349535e",
"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/server_player_combat_fixture.rs": "243ddd24d91337c07526b586a92e183c0524f584612e5a4ab304fa489b7a7082"
},
"fixtures_sha256": {
".local/rust-server-player-combat-parity/inputs.txt": "0267042ca199aba2647667b349b22be374c83fbae3d9846a33519c1f96a402b4",
".local/rust-server-player-combat-parity/catalog.json": "d1e488e4f432888beb9f643904c8bca242d1e2093f53e23e07da305d70cf7106",
".local/rust-server-player-combat-parity/ids.json": "f7d6037166d966e2714b01cff5626f0cc0a02ce883885ec791c93e977afde0e6",
".local/rust-server-player-combat-parity/slots.json": "29101ebf1ead685029508789eee51c4d4fff65524064d8e32a48efded7036982",
".local/rust-server-player-combat-parity/head.json": "ef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d"
},
"rust_output_sha256": "e2e937abc1e00904c23573390279fb6f7474b88e0adf8ebb0f0019504e888939",
"live_rust_output_sha256": "e2e937abc1e00904c23573390279fb6f7474b88e0adf8ebb0f0019504e888939",
"references": [
{
"side": "client",
"jar_sha256": "4508d006323f24fa02876310c192d739af56516eb259000ac50f0909a68c9a2d",
"output_sha256": "e2e937abc1e00904c23573390279fb6f7474b88e0adf8ebb0f0019504e888939",
"matched_output_lines": 1176994
},
{
"side": "server",
"jar_sha256": "a362163eec5d1612d520772bc16e5b39c09e3b234fdc045f56bf544284ee8ae6",
"output_sha256": "e2e937abc1e00904c23573390279fb6f7474b88e0adf8ebb0f0019504e888939",
"matched_output_lines": 1176994
}
],
"scope": "Both EntityAttributes and LiveAttributes storage bindings produce the same native traces. Actual ServerPlayer outer hurt through Player/LivingEntity gates and actual Player inner damage, native armor/resistance reduction, registered modified attributes, synchronized health/absorption and FoodData exhaustion. Repeated hits, cooldown/state writes, death rejection, callbacks and numeric edges. Actual inherited invulnerability predicates include virtual flags, empty-equipment enchantment immunity, damage gamerules and client-loading/dimension guards; blocking amount, durability, effects, PvP permission, attribution, knockback, death services and criterion listeners remain controlled; enchanted items, registered sources and complete entity/game lifecycle remain pending."
}
@@ -1,9 +1,11 @@
use horizon_world::damage_immunity::{DamageRule, ImmunityTag, ImmunityWorld};
use horizon_world::living_hurt::{HurtState, HurtTag, HurtWorld};
use horizon_world::{
attribute_health::HealthAttributes,
attributes::{
Modifier, Operation,
entity::{Catalog, EntityAttributes},
live::LiveAttributes,
},
combat_rules::ArmorWorld,
damage_reduction::Bypass,
@@ -25,6 +27,60 @@ use std::{
io::{self, Write},
path::Path,
};
// Run the identical native combat corpus through both attribute stores.
trait FixtureAttributes: HealthAttributes {
fn create(catalog: Arc<Catalog>) -> Self;
fn configure(&mut self, name: &str, base: f64, modifier: Option<Modifier>);
}
impl FixtureAttributes for EntityAttributes {
fn create(catalog: Arc<Catalog>) -> Self {
catalog.create("minecraft:player").unwrap()
}
fn configure(&mut self, name: &str, base: f64, modifier: Option<Modifier>) {
let key = self.catalog().id(name).unwrap();
self.edit(key, |a, o| {
a.set_base_value(base, o)?;
if let Some(m) = modifier {
a.add_transient(m, o)?;
}
Ok::<_, horizon_world::attributes::AttributeError<std::convert::Infallible>>(())
})
.unwrap()
.unwrap();
}
}
type Live = LiveAttributes<Box<dyn FnMut() -> i32>>;
impl FixtureAttributes for Live {
fn create(catalog: Arc<Catalog>) -> Self {
let hashes: Vec<_> = catalog
.attributes()
.enumerate()
.map(|(i, _)| i as i32)
.collect();
let mut next = 0i32;
Self::new(
catalog,
"minecraft:player",
&hashes,
Box::new(move || {
next = next.wrapping_add(1);
next
}),
)
.unwrap()
}
fn configure(&mut self, name: &str, base: f64, modifier: Option<Modifier>) {
let handle = self.get_instance(self.key(name)).unwrap().unwrap();
self.edit(&handle, |a, o| {
a.set_base_value(base, o)?;
if let Some(m) = modifier {
a.add_transient(m, o)?;
}
Ok(())
})
.unwrap();
}
}
fn single(v: &Value) -> f32 {
f32::from_bits(u32::from_str_radix(v.as_str().unwrap(), 16).unwrap())
}
@@ -320,7 +376,7 @@ impl ArmorWorld for Env<'_> {
Ok(v)
}
}
impl ServerDamageEnvironment for Env<'_> {
impl<A: FixtureAttributes> ServerDamageEnvironment<A> for Env<'_> {
type Attacker = ();
fn invulnerable(&mut self) -> io::Result<bool> {
self.event("invulnerable")?;
@@ -336,15 +392,10 @@ impl ServerDamageEnvironment for Env<'_> {
self.event(&format!("tag bypass_{n}"))?;
Ok(self.flag(&format!("bypass_{n}")))
}
fn hurt_armor(&mut self, a: &mut EntityAttributes, v: f32) -> io::Result<()> {
fn hurt_armor(&mut self, a: &mut A, v: f32) -> io::Result<()> {
self.event(&format!("hurt-armor {:08x}", bits(v)))?;
if self.flag("break_armor") {
let id = a.catalog().id("minecraft:armor").unwrap();
a.edit(id, |a, o| {
a.set_base_value(number(&self.op["armor_after"]), o)
})
.unwrap()
.unwrap();
a.configure("minecraft:armor", number(&self.op["armor_after"]), None);
}
Ok(())
}
@@ -405,7 +456,7 @@ impl ServerDamageEnvironment for Env<'_> {
self.event("damage-event")
}
}
impl CombatEnvironment for Env<'_> {
impl<A: FixtureAttributes> CombatEnvironment<A> for Env<'_> {
fn dead_flag(&self) -> bool {
self.dead
}
@@ -413,6 +464,13 @@ impl CombatEnvironment for Env<'_> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
let arg = std::env::args().nth(1).unwrap();
let dir = Path::new(&arg);
if std::env::args().nth(2).as_deref() == Some("--live") {
run::<Live>(dir, "rust-live.txt")
} else {
run::<EntityAttributes>(dir, "rust.txt")
}
}
fn run<A: FixtureAttributes>(dir: &Path, output: &str) -> Result<(), Box<dyn std::error::Error>> {
let ids: Value = serde_json::from_str(&fs::read_to_string(dir.join("ids.json"))?)?;
let ids = PlayerFloatIds {
health: ids["health"].as_u64().unwrap() as u8,
@@ -428,12 +486,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
"minecraft:armor_toughness",
"minecraft:max_health",
"minecraft:max_absorption",
]
.map(|k| catalog.id(k).unwrap());
let mut out = io::BufWriter::new(fs::File::create(dir.join("rust.txt"))?);
];
let mut out = io::BufWriter::new(fs::File::create(dir.join(output))?);
for line in fs::read_to_string(dir.join("inputs.txt"))?.lines() {
let f: Value = serde_json::from_str(line)?;
let mut attributes = catalog.create("minecraft:player").unwrap();
let mut attributes = A::create(catalog.clone());
for (i, key) in keys.iter().enumerate() {
let a = &f["attributes"][i];
let m = Modifier::new(
@@ -441,13 +498,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
number(&a["amount"]),
Operation::ALL[a["operation"].as_u64().unwrap() as usize],
)?;
attributes
.edit(*key, |a, o| {
a.set_base_value(number(&f["attributes"][i]["base"]), o)?;
a.add_transient(m, o)
})
.unwrap()
.unwrap();
attributes.configure(key, number(&f["attributes"][i]["base"]), Some(m));
}
let mut data = SyncedFloats::new(&[
FloatValue {
+28 -26
View File
@@ -1,7 +1,8 @@
//! Player absorption uses virtual synchronized-data access, unlike base living
//! absorption field storage. Health keeps its direct synchronized-data access.
use crate::{
attributes::entity::{AttributeId, EntityAttributes, LookupError},
attribute_health::HealthAttributes,
attributes::entity::{EntityAttributes, LookupError},
compression::invalid,
living_health::{self, HealthWorld},
synced_floats::{DataError, Observer, SyncedFloats},
@@ -29,11 +30,11 @@ pub struct PlayerFloatIds {
pub absorption: u8,
}
#[derive(Debug)]
pub enum PlayerHealthError<E> {
Attribute(LookupError),
pub enum PlayerHealthError<E, A = LookupError> {
Attribute(A),
Data(DataError<E>),
}
impl<E: fmt::Display> fmt::Display for PlayerHealthError<E> {
impl<E: fmt::Display, A: fmt::Debug> fmt::Display for PlayerHealthError<E, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Attribute(e) => write!(f, "player health attribute lookup: {e:?}"),
@@ -41,21 +42,21 @@ impl<E: fmt::Display> fmt::Display for PlayerHealthError<E> {
}
}
}
impl<E: std::error::Error + 'static> std::error::Error for PlayerHealthError<E> {}
impl<E: std::error::Error + 'static, A: fmt::Debug> std::error::Error for PlayerHealthError<E, A> {}
/// Ordinary registered-player state, borrowing its actual float table. IDs come
/// from the pinned entity-data schema; construction does not invent spawn state.
pub struct PlayerAttributeHealth<'a, O> {
attributes: &'a mut EntityAttributes,
pub struct PlayerAttributeHealth<'a, O, A: HealthAttributes = EntityAttributes> {
attributes: &'a mut A,
data: &'a mut SyncedFloats,
ids: PlayerFloatIds,
max_health: AttributeId,
max_absorption: AttributeId,
max_health: A::Key,
max_absorption: A::Key,
dead: bool,
observer: &'a mut O,
}
impl<'a, O: Observer> PlayerAttributeHealth<'a, O> {
impl<'a, O: Observer, A: HealthAttributes> PlayerAttributeHealth<'a, O, A> {
pub fn new(
attributes: &'a mut EntityAttributes,
attributes: &'a mut A,
data: &'a mut SyncedFloats,
ids: PlayerFloatIds,
dead: bool,
@@ -68,12 +69,10 @@ impl<'a, O: Observer> PlayerAttributeHealth<'a, O> {
return Err(invalid("missing or aliased player float fields"));
}
let max_health = attributes
.catalog()
.id("minecraft:max_health")
.health_attribute_key("minecraft:max_health")
.ok_or_else(|| invalid("missing MAX_HEALTH definition"))?;
let max_absorption = attributes
.catalog()
.id("minecraft:max_absorption")
.health_attribute_key("minecraft:max_absorption")
.ok_or_else(|| invalid("missing MAX_ABSORPTION definition"))?;
Ok(Self {
attributes,
@@ -85,27 +84,30 @@ impl<'a, O: Observer> PlayerAttributeHealth<'a, O> {
observer,
})
}
pub fn heal(&mut self, amount: f32) -> Result<(), PlayerHealthError<O::Error>> {
pub fn heal(&mut self, amount: f32) -> Result<(), PlayerHealthError<O::Error, A::Error>> {
living_health::heal(self, amount)
}
pub fn set_health(&mut self, value: f32) -> Result<(), PlayerHealthError<O::Error>> {
pub fn set_health(&mut self, value: f32) -> Result<(), PlayerHealthError<O::Error, A::Error>> {
living_health::set_health(self, value)
}
pub fn set_absorption(&mut self, value: f32) -> Result<(), PlayerHealthError<O::Error>> {
pub fn set_absorption(
&mut self,
value: f32,
) -> Result<(), PlayerHealthError<O::Error, A::Error>> {
living_health::set_absorption(self, value)
}
pub fn absorption(&mut self) -> Result<f32, PlayerHealthError<O::Error>> {
pub fn absorption(&mut self) -> Result<f32, PlayerHealthError<O::Error, A::Error>> {
absorption(self)
}
pub fn is_hurt(&mut self) -> Result<bool, PlayerHealthError<O::Error>> {
pub fn is_hurt(&mut self) -> Result<bool, PlayerHealthError<O::Error, A::Error>> {
living_health::is_hurt(self)
}
pub fn is_dead_or_dying(&mut self) -> Result<bool, PlayerHealthError<O::Error>> {
pub fn is_dead_or_dying(&mut self) -> Result<bool, PlayerHealthError<O::Error, A::Error>> {
living_health::is_dead_or_dying(self)
}
}
impl<O: Observer> HealthWorld for PlayerAttributeHealth<'_, O> {
type Error = PlayerHealthError<O::Error>;
impl<O: Observer, A: HealthAttributes> HealthWorld for PlayerAttributeHealth<'_, O, A> {
type Error = PlayerHealthError<O::Error, A::Error>;
type Data = ();
fn health(&mut self) -> Result<f32, Self::Error> {
self.data
@@ -115,12 +117,12 @@ impl<O: Observer> HealthWorld for PlayerAttributeHealth<'_, O> {
fn health_data(&self) {}
fn max_health_attribute(&mut self) -> Result<f64, Self::Error> {
self.attributes
.value(self.max_health)
.health_attribute_value(self.max_health.clone())
.map_err(PlayerHealthError::Attribute)
}
fn max_absorption_attribute(&mut self) -> Result<f64, Self::Error> {
self.attributes
.value(self.max_absorption)
.health_attribute_value(self.max_absorption.clone())
.map_err(PlayerHealthError::Attribute)
}
fn store_health(&mut self, _: (), value: f32) -> Result<(), Self::Error> {
@@ -138,7 +140,7 @@ impl<O: Observer> HealthWorld for PlayerAttributeHealth<'_, O> {
living_health::set_health(self, value)
}
}
impl<O: Observer> PlayerHealthWorld for PlayerAttributeHealth<'_, O> {
impl<O: Observer, A: HealthAttributes> PlayerHealthWorld for PlayerAttributeHealth<'_, O, A> {
fn entity_data(&mut self) -> Result<(), Self::Error> {
Ok(())
}
@@ -1,5 +1,6 @@
//! Server-player outer hurt composed with registered attributes and player storage.
use crate::{
attribute_health::HealthAttributes,
attributes::entity::EntityAttributes,
combat_rules::ArmorWorld,
damage_immunity::{self, ImmunityWorld},
@@ -14,24 +15,24 @@ use crate::{
};
use std::io;
type Error<E> = <E as ArmorWorld>::Error;
pub trait CombatEnvironment:
ServerDamageEnvironment
pub trait CombatEnvironment<A: HealthAttributes = EntityAttributes>:
ServerDamageEnvironment<A>
+ ServerPlayerHurtWorld<Error = <Self as ArmorWorld>::Error>
+ ImmunityWorld<Error = <Self as ArmorWorld>::Error>
{
/// Direct death flag, read only after health fails the native <= zero test.
fn dead_flag(&self) -> bool;
}
pub struct ServerPlayerCombat<'a, E> {
attributes: &'a mut EntityAttributes,
pub struct ServerPlayerCombat<'a, E, A: HealthAttributes = EntityAttributes> {
attributes: &'a mut A,
data: &'a mut SyncedFloats,
food: &'a mut FoodData,
ids: PlayerFloatIds,
environment: &'a mut E,
}
impl<'a, E: CombatEnvironment> ServerPlayerCombat<'a, E> {
impl<'a, A: HealthAttributes, E: CombatEnvironment<A>> ServerPlayerCombat<'a, E, A> {
pub fn new(
attributes: &'a mut EntityAttributes,
attributes: &'a mut A,
data: &'a mut SyncedFloats,
food: &'a mut FoodData,
ids: PlayerFloatIds,
@@ -50,12 +51,12 @@ impl<'a, E: CombatEnvironment> ServerPlayerCombat<'a, E> {
&mut self,
state: &mut HurtState<E::Source>,
damage: f32,
) -> Result<bool, ServerDamageError<Error<E>>> {
) -> Result<bool, ServerDamageError<Error<E>, A::Error>> {
server_player_hurt_server(state, self, damage)
}
}
impl<E: CombatEnvironment> HurtWorld for ServerPlayerCombat<'_, E> {
type Error = ServerDamageError<Error<E>>;
impl<A: HealthAttributes, E: CombatEnvironment<A>> HurtWorld for ServerPlayerCombat<'_, E, A> {
type Error = ServerDamageError<Error<E>, A::Error>;
type Source = E::Source;
type UseItem = E::UseItem;
type Blocking = E::Blocking;
@@ -249,7 +250,9 @@ impl<E: CombatEnvironment> HurtWorld for ServerPlayerCombat<'_, E> {
.map_err(ServerDamageError::Environment)
}
}
impl<E: CombatEnvironment> PlayerHurtWorld for ServerPlayerCombat<'_, E> {
impl<A: HealthAttributes, E: CombatEnvironment<A>> PlayerHurtWorld
for ServerPlayerCombat<'_, E, A>
{
fn ability_invulnerable(&self) -> bool {
ServerDamageEnvironment::ability_invulnerable(self.environment)
}
@@ -278,7 +281,9 @@ impl<E: CombatEnvironment> PlayerHurtWorld for ServerPlayerCombat<'_, E> {
PlayerHurtWorld::difficulty(self.environment, state).map_err(ServerDamageError::Environment)
}
}
impl<E: CombatEnvironment> ServerPlayerHurtWorld for ServerPlayerCombat<'_, E> {
impl<A: HealthAttributes, E: CombatEnvironment<A>> ServerPlayerHurtWorld
for ServerPlayerCombat<'_, E, A>
{
type Player = E::Player;
type Arrow = E::Arrow;
fn causing_entity(
@@ -2,7 +2,8 @@
//! synchronized health/absorption and stored hunger. Outer hurt gates stay with
//! the caller; equipment, effect, statistic and combat services stay explicit.
use crate::{
attributes::entity::{AttributeId, EntityAttributes, LookupError},
attribute_health::HealthAttributes,
attributes::entity::{EntityAttributes, LookupError},
combat_rules::ArmorWorld,
compression::invalid,
damage_reduction::{self, Bypass, DamageReductionWorld},
@@ -14,12 +15,12 @@ use crate::{
use std::{fmt, io};
type EnvError<E> = <E as ArmorWorld>::Error;
#[derive(Debug)]
pub enum ServerDamageError<E> {
Attribute(LookupError),
pub enum ServerDamageError<E, A = LookupError> {
Attribute(A),
Data(DataError<E>),
Environment(E),
}
impl<E: fmt::Display> fmt::Display for ServerDamageError<E> {
impl<E: fmt::Display, A: fmt::Debug> fmt::Display for ServerDamageError<E, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Attribute(e) => write!(f, "damage attribute lookup: {e:?}"),
@@ -28,14 +29,14 @@ impl<E: fmt::Display> fmt::Display for ServerDamageError<E> {
}
}
}
impl<E: std::error::Error + 'static> std::error::Error for ServerDamageError<E> {}
fn health_error<E>(e: PlayerHealthError<E>) -> ServerDamageError<E> {
impl<E: std::error::Error + 'static, A: fmt::Debug> std::error::Error for ServerDamageError<E, A> {}
fn health_error<E, A>(e: PlayerHealthError<E, A>) -> ServerDamageError<E, A> {
match e {
PlayerHealthError::Attribute(e) => ServerDamageError::Attribute(e),
PlayerHealthError::Data(e) => ServerDamageError::Data(e),
}
}
pub trait ServerDamageEnvironment:
pub trait ServerDamageEnvironment<A: HealthAttributes = EntityAttributes>:
ArmorWorld + Observer<Error = <Self as ArmorWorld>::Error>
{
type Attacker: Copy;
@@ -43,11 +44,7 @@ pub trait ServerDamageEnvironment:
fn bypasses(&mut self, kind: Bypass) -> Result<bool, EnvError<Self>>;
/// Equipment breakage may update the live attribute map before armor and
/// toughness are queried by the rest of this hit.
fn hurt_armor(
&mut self,
attributes: &mut EntityAttributes,
damage: f32,
) -> Result<(), EnvError<Self>>;
fn hurt_armor(&mut self, attributes: &mut A, damage: f32) -> Result<(), EnvError<Self>>;
fn has_resistance(&mut self) -> Result<bool, EnvError<Self>>;
fn resistance_amplifier(&mut self) -> Result<i32, EnvError<Self>>;
fn award_resisted(&mut self, amount: i32) -> Result<(), EnvError<Self>>;
@@ -67,30 +64,28 @@ pub trait ServerDamageEnvironment:
fn record_damage(&mut self, amount: f32) -> Result<(), EnvError<Self>>;
fn damage_event(&mut self) -> Result<(), EnvError<Self>>;
}
pub struct ServerPlayerDamage<'a, E> {
attributes: &'a mut EntityAttributes,
pub struct ServerPlayerDamage<'a, E, A: HealthAttributes = EntityAttributes> {
attributes: &'a mut A,
data: &'a mut SyncedFloats,
food: &'a mut FoodData,
ids: PlayerFloatIds,
armor: AttributeId,
toughness: AttributeId,
armor: A::Key,
toughness: A::Key,
environment: &'a mut E,
}
impl<'a, E: ServerDamageEnvironment> ServerPlayerDamage<'a, E> {
impl<'a, A: HealthAttributes, E: ServerDamageEnvironment<A>> ServerPlayerDamage<'a, E, A> {
pub fn new(
attributes: &'a mut EntityAttributes,
attributes: &'a mut A,
data: &'a mut SyncedFloats,
food: &'a mut FoodData,
ids: PlayerFloatIds,
environment: &'a mut E,
) -> io::Result<Self> {
let armor = attributes
.catalog()
.id("minecraft:armor")
.health_attribute_key("minecraft:armor")
.ok_or_else(|| invalid("missing ARMOR definition"))?;
let toughness = attributes
.catalog()
.id("minecraft:armor_toughness")
.health_attribute_key("minecraft:armor_toughness")
.ok_or_else(|| invalid("missing ARMOR_TOUGHNESS definition"))?;
PlayerAttributeHealth::new(attributes, data, ids, false, environment)?;
Ok(Self {
@@ -103,7 +98,7 @@ impl<'a, E: ServerDamageEnvironment> ServerPlayerDamage<'a, E> {
environment,
})
}
fn health_binding(&mut self) -> PlayerAttributeHealth<'_, E> {
fn health_binding(&mut self) -> PlayerAttributeHealth<'_, E, A> {
PlayerAttributeHealth::new(
self.attributes,
self.data,
@@ -113,18 +108,20 @@ impl<'a, E: ServerDamageEnvironment> ServerPlayerDamage<'a, E> {
)
.expect("validated immutable player float schema")
}
pub fn apply(&mut self, damage: f32) -> Result<(), ServerDamageError<EnvError<E>>> {
pub fn apply(&mut self, damage: f32) -> Result<(), ServerDamageError<EnvError<E>, A::Error>> {
living_damage::actually_hurt(self, damage, true)
}
pub(crate) fn apply_after_immunity_check(
&mut self,
damage: f32,
) -> Result<(), ServerDamageError<EnvError<E>>> {
) -> Result<(), ServerDamageError<EnvError<E>, A::Error>> {
living_damage::actually_hurt_after_immunity_check(self, damage, true)
}
}
impl<E: ServerDamageEnvironment> ArmorWorld for ServerPlayerDamage<'_, E> {
type Error = ServerDamageError<EnvError<E>>;
impl<A: HealthAttributes, E: ServerDamageEnvironment<A>> ArmorWorld
for ServerPlayerDamage<'_, E, A>
{
type Error = ServerDamageError<EnvError<E>, A::Error>;
type Weapon = E::Weapon;
type ServerLevel = E::ServerLevel;
fn weapon(&mut self) -> Result<Option<Self::Weapon>, Self::Error> {
@@ -148,7 +145,9 @@ impl<E: ServerDamageEnvironment> ArmorWorld for ServerPlayerDamage<'_, E> {
.map_err(ServerDamageError::Environment)
}
}
impl<E: ServerDamageEnvironment> DamageReductionWorld for ServerPlayerDamage<'_, E> {
impl<A: HealthAttributes, E: ServerDamageEnvironment<A>> DamageReductionWorld
for ServerPlayerDamage<'_, E, A>
{
fn bypasses(&mut self, b: Bypass) -> Result<bool, Self::Error> {
self.environment
.bypasses(b)
@@ -161,13 +160,13 @@ impl<E: ServerDamageEnvironment> DamageReductionWorld for ServerPlayerDamage<'_,
}
fn armor_value(&mut self) -> Result<i32, Self::Error> {
self.attributes
.value(self.armor)
.health_attribute_value(self.armor.clone())
.map(damage_reduction::armor_from_attribute)
.map_err(ServerDamageError::Attribute)
}
fn toughness_attribute(&mut self) -> Result<f64, Self::Error> {
self.attributes
.value(self.toughness)
.health_attribute_value(self.toughness.clone())
.map_err(ServerDamageError::Attribute)
}
fn has_resistance(&mut self) -> Result<bool, Self::Error> {
@@ -205,8 +204,10 @@ impl<E: ServerDamageEnvironment> DamageReductionWorld for ServerPlayerDamage<'_,
.map_err(ServerDamageError::Environment)
}
}
impl<E: ServerDamageEnvironment> DamageWorld for ServerPlayerDamage<'_, E> {
type Error = ServerDamageError<EnvError<E>>;
impl<A: HealthAttributes, E: ServerDamageEnvironment<A>> DamageWorld
for ServerPlayerDamage<'_, E, A>
{
type Error = ServerDamageError<EnvError<E>, A::Error>;
type Attacker = E::Attacker;
fn invulnerable(&mut self) -> Result<bool, Self::Error> {
self.environment
+14
View File
@@ -2093,3 +2093,17 @@ retains **167,906 matching lines per JAR**. Targeted Clippy passes. Map-only run
use the same installed JDK; these comparisons do not assert gameplay parity or
equal identity hashes across processes. Keys must have pure operations; null
keys and other unexposed Map APIs remain outside this storage subset.
`PlayerAttributeHealth`, `ServerPlayerDamage` and `ServerPlayerCombat` can now
borrow `LiveAttributes`, the same storage used by the resident moving player,
as well as `EntityAttributes`. Health limits and armor queries use the borrowed
store; equipment damage callbacks can update it before damage reduction reads
armor and toughness. Player absorption retains synchronized float storage.
The [live player combat comparison](../benchmarks/rust-live-player-combat-2026-10-07/scoped-parity.json)
runs the identical corpus through both stores and matches 1,176,994 output lines
against each pinned Java reference. It covers repeated hits, cooldowns, health
and absorption writes, exhaustion, numeric edges, armor mutation during a hit
and callback failures. Equipment, attribution, death services and other world
consumers retain the controlled boundaries documented in the report. Connecting
this binding to the resident client landing consumer remains the next step.
+4 -2
View File
@@ -80,13 +80,15 @@ def main():
run(['cargo','build','--release','-p','horizon-world','--example','server_player_combat_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'/('server_player_combat_fixture.exe' if os.name=='nt' else 'server_player_combat_fixture')
run([binary,build],'rust');references=[]
run([binary,build],'rust')
run([binary,build,'--live'],'rust-live')
base.compare(build/'rust.txt',build/'rust-live.txt');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:,} server player combat 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 ServerPlayer outer hurt through Player/LivingEntity gates and actual Player inner damage, native armor/resistance reduction, registered modified attributes, synchronized health/absorption and FoodData exhaustion. Repeated hits, cooldown/state writes, death rejection, callbacks and numeric edges. Actual inherited invulnerability predicates include virtual flags, empty-equipment enchantment immunity, damage gamerules and client-loading/dimension guards; blocking amount, durability, effects, PvP permission, attribution, knockback, death services and criterion listeners remain controlled; enchanted items, registered sources and complete entity/game lifecycle remain pending.'}
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'),'live_rust_output_sha256':lab.digest(build/'rust-live.txt','sha256'),'references':references,'scope':'Both EntityAttributes and LiveAttributes storage bindings produce the same native traces. Actual ServerPlayer outer hurt through Player/LivingEntity gates and actual Player inner damage, native armor/resistance reduction, registered modified attributes, synchronized health/absorption and FoodData exhaustion. Repeated hits, cooldown/state writes, death rejection, callbacks and numeric edges. Actual inherited invulnerability predicates include virtual flags, empty-equipment enchantment immunity, damage gamerules and client-loading/dimension guards; blocking amount, durability, effects, PvP permission, attribution, knockback, death services and criterion listeners remain controlled; enchanted items, registered sources and complete entity/game lifecycle remain pending.'}
lab.write_json(report_path,report);print(f'Scoped server player combat parity passed: {report_path}')