mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Save the modeled mob loot-pickup flag
Write CanPickUpLoot on every save through the existing virtual getter, preserving the Allay and sulfur-cube overrides instead of retaining stale raw bytes. Cover decoded and mutated models plus frozen actual command reads. Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
This commit is contained in:
1 parent
1532c9c153
commit
c843c1aa05
4 files changed
+114
-2
No files matched your search
@@ -366,6 +366,8 @@ pub fn mob_to_nbt(
|
||||
"DeathTime",
|
||||
Tag::Short(m.death_time.clamp(0, i32::from(i16::MAX)) as i16),
|
||||
),
|
||||
// Mob.addAdditionalSaveData writes the current virtual getter, not raw input.
|
||||
("CanPickUpLoot", Tag::Byte(i8::from(m.can_pick_up_loot()))),
|
||||
("PersistenceRequired", Tag::Byte(i8::from(m.persistent))),
|
||||
] {
|
||||
put(&mut tag, key, value);
|
||||
@@ -527,7 +529,6 @@ pub fn mob_to_nbt(
|
||||
for (key, value) in [
|
||||
("AbsorptionAmount", Tag::Float(0)),
|
||||
("FallFlying", Tag::Byte(0)),
|
||||
("CanPickUpLoot", Tag::Byte(i8::from(m.can_pick_up_loot()))),
|
||||
("current_impulse_context_reset_grace_time", Tag::Int(0)),
|
||||
(
|
||||
"Brain",
|
||||
@@ -7026,3 +7027,57 @@ mod piglin_live_anger_memory_tests {
|
||||
assert_unrelated(&saved);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod pickup_loot_save_tests {
|
||||
use super::*;
|
||||
use crate::mobs::Species;
|
||||
|
||||
#[test]
|
||||
fn pickup_save_uses_live_state_instead_of_raw_and_preserves_overrides() {
|
||||
for (species, id) in [
|
||||
(Species::Pig, "minecraft:pig"),
|
||||
(Species::Allay, "minecraft:allay"),
|
||||
(Species::SulfurCube, "minecraft:sulfur_cube"),
|
||||
] {
|
||||
let mut kind = crate::mobs::sensor_scan_tests::kind();
|
||||
let ty = Arc::make_mut(&mut kind);
|
||||
ty.id = id.into();
|
||||
ty.species = species;
|
||||
let types = HashMap::from([(id.to_string(), kind)]);
|
||||
for supplied in [None, Some(false), Some(true)] {
|
||||
let mut raw = Tag::compound([
|
||||
("id", string(id)),
|
||||
("Pos", doubles(&[4.5, 200.0, 4.5])),
|
||||
("audit:unrelated", Tag::Int(7)),
|
||||
]);
|
||||
if let Some(on) = supplied {
|
||||
put(&mut raw, "CanPickUpLoot", Tag::Byte(i8::from(on)));
|
||||
}
|
||||
let mut mob = mob_from_nbt(&raw, &types, 1, None).unwrap();
|
||||
for live in [false, true] {
|
||||
mob.extra.pick_up_loot = live;
|
||||
mob.extra.main_hand = live.then(|| "minecraft:stone".into());
|
||||
mob.extra.body = live.then(|| "minecraft:stone".into());
|
||||
let expected = if species == Species::SulfurCube {
|
||||
!live
|
||||
} else {
|
||||
live
|
||||
};
|
||||
for input in [None, Some(&raw)] {
|
||||
let saved = mob_to_nbt(&mob, [46, 0, 0, 1], input, None);
|
||||
assert_eq!(
|
||||
saved.get("CanPickUpLoot"),
|
||||
Some(&Tag::Byte(i8::from(expected))),
|
||||
"{id} supplied={supplied:?} live={live} raw={}",
|
||||
input.is_some()
|
||||
);
|
||||
if input.is_some() {
|
||||
assert_eq!(saved.get("audit:unrelated"), Some(&Tag::Int(7)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3855,6 +3855,42 @@ def awake_villager_saved_position():
|
||||
|
||||
|
||||
|
||||
def mob_saved_pickup_loot():
|
||||
"""Valid boolean inputs only; full bodies retain unrelated save diagnostics."""
|
||||
ops = [cmd('/tick freeze'), cmd('/forceload add 160 160 175 175'),
|
||||
{'op': 'wait_chunks', 'chunks': [[10, 10]]},
|
||||
cmd('/fill 160 199 160 175 199 175 stone', expect_result=256),
|
||||
cmd('/execute if loaded 164 200 164', expect_result=1),
|
||||
cmd('/execute if block 164 199 164 stone', expect_result=1),
|
||||
cmd('/scoreboard objectives add pickup_save dummy', expect_result=1)]
|
||||
ops += setup('/execute store result score start pickup_save run time query gametime')
|
||||
for species, name in enumerate(['pig', 'allay', 'sulfur_cube']):
|
||||
for value, supplied in enumerate(['', ',CanPickUpLoot:0b', ',CanPickUpLoot:1b']):
|
||||
n = 1 + species * 3 + value
|
||||
uuid = f'0000002e-0000-0000-0000-{n:012x}'
|
||||
array = f'[I;46,0,0,{n}]'
|
||||
tag = f'pickup_save_{n}'
|
||||
body = 'Pos:[164.5d,200d,164.5d],Motion:[0d,0d,0d],NoAI:1b,NoGravity:1b,Silent:1b,PersistenceRequired:1b,Health:4f'
|
||||
expected = int(name == 'sulfur_cube' or (name == 'pig' and value == 2))
|
||||
ops += [cmd(f'/summon minecraft:{name} 164.5 200 164.5 {{UUID:{array},Tags:["{tag}"],{body}{supplied}}}', expect_result=1),
|
||||
cmd(f'/execute as {uuid} if entity @s[type=minecraft:{name},tag={tag}]', expect_result=1),
|
||||
cmd(f'/execute if data entity {uuid} {{UUID:{array},{body}}}', expect_result=1)]
|
||||
for _ in range(2):
|
||||
ops += setup('/scoreboard players set value pickup_save 317',
|
||||
'/scoreboard players set success pickup_save 17')
|
||||
ops += [cmd(f'/data get entity {uuid} CanPickUpLoot', expect_result=expected),
|
||||
cmd(f'/execute store result score value pickup_save store success score success pickup_save run data get entity {uuid} CanPickUpLoot', expect_result=expected),
|
||||
cmd('/scoreboard players get value pickup_save', expect_result=expected),
|
||||
cmd('/scoreboard players get success pickup_save', expect_result=1),
|
||||
cmd(f'/execute if data entity {uuid} {{CanPickUpLoot:{expected}b}}', expect_result=1)]
|
||||
full = cmd(f'/data get entity {uuid}', record=False)
|
||||
full['trace'] = True
|
||||
ops.append(full)
|
||||
ops += setup('/execute store result score elapsed pickup_save run time query gametime',
|
||||
'/scoreboard players operation elapsed pickup_save -= start pickup_save')
|
||||
return ops + [cmd('/scoreboard players get elapsed pickup_save', expect_result=0)]
|
||||
|
||||
|
||||
def projectile_saved_uuid():
|
||||
"""Direct identity guards are separate from repeated saved UUID views."""
|
||||
from uuid import UUID
|
||||
@@ -5526,7 +5562,8 @@ ISOLATED_REINFORCEMENTS = frozenset({'command zombie reinforcements', 'command r
|
||||
# These overlays replace built-in recipes, never beside the corpus's fixed vanilla recipe-count controls.
|
||||
ISOLATED_RECIPES = frozenset({'crafting recipe priority', 'crafting base recipe control', 'transmute result patches'})
|
||||
ISOLATED_FRAME_MAPS = frozenset({'frame live map detachment'})
|
||||
ISOLATED_GROUPS = ISOLATED_REINFORCEMENTS | ISOLATED_RECIPES | ISOLATED_WOLF_ANGER | ISOLATED_FRAME_MAPS
|
||||
ISOLATED_PICKUP_SAVE = frozenset({'mob saved pickup loot'})
|
||||
ISOLATED_GROUPS = ISOLATED_REINFORCEMENTS | ISOLATED_RECIPES | ISOLATED_WOLF_ANGER | ISOLATED_FRAME_MAPS | ISOLATED_PICKUP_SAVE
|
||||
|
||||
|
||||
def groups():
|
||||
@@ -5562,6 +5599,7 @@ def groups():
|
||||
from item_merge_corpus import stack_limit_merges
|
||||
return [
|
||||
('setup', group_setup()),
|
||||
('mob saved pickup loot', mob_saved_pickup_loot()),
|
||||
('transmute result patches', transmute_patches(cmd, setup)),
|
||||
('mob effect predicate view', mob_effect_predicates(cmd, setup)),
|
||||
('frame live map detachment', frame_maps(cmd, setup)),
|
||||
|
||||
@@ -139,6 +139,7 @@ def main():
|
||||
parser.add_argument('--map-decoration-patch-fixture', action='store_true')
|
||||
parser.add_argument('--map-decoration-removal-diagnostic', action='store_true')
|
||||
parser.add_argument("--selector-bounds-fixture", action="store_true")
|
||||
parser.add_argument("--mob-pickup-save-fixture", action="store_true")
|
||||
args = parser.parse_args()
|
||||
build = args.work_dir.resolve() if args.work_dir else lab.LOCAL / 'command-exec-parity'
|
||||
build.mkdir(parents=True, exist_ok=True)
|
||||
@@ -164,6 +165,10 @@ def main():
|
||||
sys.exit(f'{name} failed ({result.returncode}):\n{tail}')
|
||||
|
||||
groups = corpus_module.groups()
|
||||
if args.mob_pickup_save_fixture or args.only == "mob saved pickup loot":
|
||||
groups = [(name, ops) for name, ops in groups if name == "mob saved pickup loot"]
|
||||
elif not args.only:
|
||||
groups = [(name, ops) for name, ops in groups if name not in corpus_module.ISOLATED_PICKUP_SAVE]
|
||||
if not args.only:
|
||||
groups = [(name, ops) for name, ops in groups if name not in corpus_module.ISOLATED_FRAME_MAPS]
|
||||
if not args.only and not args.wolf_anger_clock_diagnostic:
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Actual command saves of modeled loot-pickup flags, including species overrides."""
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
raise SystemExit(subprocess.run([
|
||||
sys.executable, str(root / 'tools/test_command_exec_parity.py'),
|
||||
'--mob-pickup-save-fixture', '--work-dir', str(root / '.local/mob-pickup-save-parity'),
|
||||
*sys.argv[1:],
|
||||
], cwd=root).returncode)
|
||||
Reference in new issue
Block a user