mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-09 17:19:15 -10:00
Load configured spawner passengers with default entity fields
Normalize entity type identifiers and place every configured passenger before loading a spawner entity stack. Cover namespace resolution and actual passenger selection and vehicle relations. Co-Authored-By: Codex <[email protected]>
This commit is contained in:
1 parent
4f4f1db13c
commit
2d73371393
3 files changed
+63
-2
No files matched your search
@@ -27,7 +27,7 @@ fn string(s: &str) -> Tag {
|
||||
}
|
||||
/// Entity type ID (`id`).
|
||||
pub fn kind(tag: &Tag) -> Option<String> {
|
||||
text(tag.get("id"))
|
||||
horizon_client_core::identifier::normalize_id(&text(tag.get("id"))?)
|
||||
}
|
||||
pub fn position(tag: &Tag) -> Option<Vec3> {
|
||||
read_doubles::<3>(tag.get("Pos")).map(|p| Vec3::new(p[0], p[1], p[2]))
|
||||
@@ -3311,6 +3311,31 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::items::ItemStack;
|
||||
|
||||
#[test]
|
||||
fn mob_loading_accepts_default_namespace_and_preserves_custom_namespaces() {
|
||||
let cow = crate::mobs::sensor_scan_tests::kind();
|
||||
let types = [
|
||||
("minecraft:cow".into(), cow.clone()),
|
||||
("test:cow".into(), cow),
|
||||
]
|
||||
.into();
|
||||
let pos = || {
|
||||
Tag::List(
|
||||
[4.5_f64, 220.0, 6.5]
|
||||
.map(|v| Tag::Double(v.to_bits()))
|
||||
.to_vec(),
|
||||
)
|
||||
};
|
||||
for id in ["cow", ":cow", "minecraft:cow", "test:cow"] {
|
||||
let tag = Tag::compound([("id", string(id)), ("Pos", pos()), ("NoAI", Tag::Byte(1))]);
|
||||
let mob = mob_from_nbt(&tag, &types, 7, None).expect(id);
|
||||
assert_eq!(mob.position, Vec3::new(4.5, 220.0, 6.5));
|
||||
assert!(mob.no_ai);
|
||||
}
|
||||
let unknown = Tag::compound([("id", string("other:cow")), ("Pos", pos())]);
|
||||
assert!(mob_from_nbt(&unknown, &types, 8, None).is_none());
|
||||
}
|
||||
|
||||
/// A saved rocket and trident come back with their own Life, LifeTime,
|
||||
/// flags and position (the keys vanilla's addAdditionalSaveData writes).
|
||||
#[test]
|
||||
|
||||
@@ -222,7 +222,10 @@ impl Game<'_> {
|
||||
if r.trial {
|
||||
tag.insert("PersistenceRequired".into(), Tag::Byte(1));
|
||||
}
|
||||
let tag = Tag::Compound(tag);
|
||||
let mut tag = Tag::Compound(tag);
|
||||
// EntityType.loadEntityRecursive applies the spawner's placement
|
||||
// callback to every passenger as well as the root.
|
||||
super::commands::place_summoned(&mut tag, r.position);
|
||||
let mob = horizon_client::entity_nbt::mob_from_nbt(
|
||||
&tag,
|
||||
self.res.mob_types(),
|
||||
|
||||
@@ -1686,6 +1686,38 @@ def summoned_potions():
|
||||
return ops
|
||||
|
||||
|
||||
def trial_spawner_passengers():
|
||||
"""Configured passengers must exist as entities with a vehicle (#7254)."""
|
||||
ops = [*setup('/fill 1 219 1 13 219 8 stone',
|
||||
'/fill 1 220 1 13 224 8 air', '/gamerule spawn_mobs true')]
|
||||
# Exercise namespace and position independently, plus the explicit control.
|
||||
for i, (kind, pos) in enumerate([
|
||||
('chicken', ''), ('minecraft:chicken', ''),
|
||||
('chicken', ',Pos:[4.5d,220.0d,6.5d]'),
|
||||
('minecraft:chicken', ',Pos:[4.5d,220.0d,6.5d]'),
|
||||
]):
|
||||
parent, rider = f'trial_parent_{i}', f'trial_rider_{i}'
|
||||
ops += setup(
|
||||
'/setblock 4 220 4 trial_spawner[trial_spawner_state=active]'
|
||||
'{normal_config:{spawn_range:3,total_mobs:1.0f,simultaneous_mobs:1.0f,'
|
||||
'total_mobs_added_per_player:0.0f,simultaneous_mobs_added_per_player:0.0f,'
|
||||
'ticks_between_spawn:1000},spawn_data:{entity:{id:"zombie",'
|
||||
f'Tags:["{parent}"],Pos:[4.5d,220.0d,6.5d],NoAI:1b,'
|
||||
f'Passengers:[{{id:"{kind}",NoAI:1b,Tags:["{rider}"]{pos}}}]'
|
||||
'}},next_mob_spawns_at:0L}',
|
||||
'/data modify block 4 220 4 registered_players append from entity @s UUID')
|
||||
ops += [
|
||||
{'op': 'tick', 'n': 5},
|
||||
cmd(f'/execute if entity @e[tag={parent}]'),
|
||||
cmd(f'/execute if entity @e[tag={rider}]'),
|
||||
cmd(f'/execute as @e[tag={rider}] on vehicle if entity @s[tag={parent}]'),
|
||||
cmd(f'/data get entity @e[tag={parent},limit=1] Passengers[0].Tags'),
|
||||
*setup(f'/kill @e[tag={parent}]', f'/kill @e[tag={rider}]',
|
||||
'/setblock 4 220 4 air'),
|
||||
]
|
||||
return ops + setup('/fill 1 219 1 13 224 8 air', '/gamerule spawn_mobs false')
|
||||
|
||||
|
||||
def groups():
|
||||
return [
|
||||
('setup', group_setup()),
|
||||
@@ -1698,6 +1730,7 @@ def groups():
|
||||
('wither spawn', wither_spawn()),
|
||||
('riding teleport', riding_teleport()),
|
||||
('mob riding', mob_riding()),
|
||||
('trial spawner passengers', trial_spawner_passengers()),
|
||||
('camel riders', camel_riders()),
|
||||
('scores, teams and bossbars', scores()),
|
||||
('execute', execute()),
|
||||
|
||||
Reference in new issue
Block a user