mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
native_summon: return experience orbs' ids, and place passengers without a Pos
Follow-up to #5408. A summoned orb spawned but native_summon returned None, since no command Target lookup covers orbs: return the stack's first spawned id. Passengers without Pos were not placed and got lost: share /summon's recursive place helper (place_summoned), which also supplies the Fire and Rotation defaults. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01XnU6QT61YPiPzVNysmVHsH
This commit is contained in:
3 files changed
+72
-37
No files matched your search
@@ -3,6 +3,7 @@
|
||||
mod admin;
|
||||
pub(super) mod compute;
|
||||
mod data;
|
||||
pub(super) use data::place_summoned;
|
||||
mod effects;
|
||||
pub(super) mod execute;
|
||||
pub(super) mod extra;
|
||||
|
||||
@@ -28,6 +28,36 @@ fn set_key(tag: &mut Tag, key: &str, value: Tag) {
|
||||
c.insert(JavaString::from(key), value);
|
||||
}
|
||||
}
|
||||
/// `EntityType.loadEntityRecursive` snaps every entity of the stack,
|
||||
/// passengers included, to the position (`/summon`, `native_summon`).
|
||||
pub(in crate::game) fn place_summoned(tag: &mut Tag, pos: [f64; 3]) {
|
||||
let p = pos.map(|v| Tag::Double(v.to_bits()));
|
||||
set_key(tag, "Pos", Tag::List(p.to_vec()));
|
||||
// Entity.load: an absent Fire reads as 0 (until the entity moves).
|
||||
if tag.get("Fire").is_none() {
|
||||
set_key(tag, "Fire", Tag::Short(0));
|
||||
}
|
||||
if tag.get("Rotation").is_none() {
|
||||
set_key(
|
||||
tag,
|
||||
"Rotation",
|
||||
Tag::List(vec![
|
||||
Tag::Float(0.0f32.to_bits()),
|
||||
Tag::Float(0.0f32.to_bits()),
|
||||
]),
|
||||
);
|
||||
}
|
||||
if let Tag::Compound(c) = tag
|
||||
&& let Some(Tag::List(riders)) = c.get_mut(&"Passengers".into())
|
||||
{
|
||||
for r in riders {
|
||||
if matches!(r, Tag::Compound(_)) {
|
||||
place_summoned(r, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Game<'_> {
|
||||
// ---- entity data ---------------------------------------------------
|
||||
|
||||
@@ -762,36 +792,7 @@ impl Game<'_> {
|
||||
return Err(err("argument.nbt.expected.compound", &[]));
|
||||
}
|
||||
set_key(&mut tag, "id", Tag::String(kind.into()));
|
||||
// EntityType.loadEntityRecursive snaps every entity of the stack,
|
||||
// passengers included, to the position.
|
||||
fn place(tag: &mut Tag, pos: [f64; 3]) {
|
||||
let p = pos.map(|v| Tag::Double(v.to_bits()));
|
||||
set_key(tag, "Pos", Tag::List(p.to_vec()));
|
||||
// Entity.load: an absent Fire reads as 0 (until the entity moves).
|
||||
if tag.get("Fire").is_none() {
|
||||
set_key(tag, "Fire", Tag::Short(0));
|
||||
}
|
||||
if tag.get("Rotation").is_none() {
|
||||
set_key(
|
||||
tag,
|
||||
"Rotation",
|
||||
Tag::List(vec![
|
||||
Tag::Float(0.0f32.to_bits()),
|
||||
Tag::Float(0.0f32.to_bits()),
|
||||
]),
|
||||
);
|
||||
}
|
||||
if let Tag::Compound(c) = tag
|
||||
&& let Some(Tag::List(riders)) = c.get_mut(&"Passengers".into())
|
||||
{
|
||||
for r in riders {
|
||||
if matches!(r, Tag::Compound(_)) {
|
||||
place(r, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
place(&mut tag, pos);
|
||||
place_summoned(&mut tag, pos);
|
||||
let from = self.mobs.len();
|
||||
let canceled = self.persist.joins_canceled;
|
||||
let target = self.spawn_entity_from_nbt(tag);
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
//! `item_display` showing an item model from the mod's assets. They act where
|
||||
//! the world is simulated, in the level in place, which each names by its
|
||||
//! `dimension` (`minecraft:overworld`) as `native_set_block` does.
|
||||
use super::{Game, commands::Target};
|
||||
use super::{
|
||||
Game,
|
||||
commands::{Target, place_summoned},
|
||||
};
|
||||
use horizon_core::geometry::Vec3;
|
||||
use horizon_world::nbt::{Compound, Tag};
|
||||
|
||||
@@ -134,14 +137,19 @@ impl Game<'_> {
|
||||
}
|
||||
let mut tag = nbt;
|
||||
tag.insert("id".into(), Tag::String(kind.into()));
|
||||
tag.insert(
|
||||
"Pos".into(),
|
||||
Tag::List(pos.map(|v| Tag::Double(v.to_bits())).to_vec()),
|
||||
);
|
||||
// As `/summon` does: every entity of the stack, passengers included,
|
||||
// stands at `pos`.
|
||||
let mut tag = Tag::Compound(tag);
|
||||
place_summoned(&mut tag, pos);
|
||||
let from = self.mobs.len();
|
||||
let target = self.spawn_entity_from_nbt(Tag::Compound(tag));
|
||||
let first = self.next_entity + 1;
|
||||
let target = self.spawn_entity_from_nbt(tag);
|
||||
self.native_mobs_joined(from, false);
|
||||
target.and_then(target_id)
|
||||
// The root is the first entity spawned, also for kinds no command
|
||||
// target stands for (experience orbs).
|
||||
target
|
||||
.and_then(target_id)
|
||||
.or((self.next_entity >= first).then_some(first))
|
||||
}
|
||||
/// Moves entity `id`, one Horizon keeps without simulating (a display, a
|
||||
/// marker, an interaction), to `pos` facing `yaw` and `pitch` in degrees;
|
||||
@@ -281,6 +289,31 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_passenger_without_a_position_stands_where_the_stack_is_summoned() {
|
||||
let mut rider = Compound::new();
|
||||
rider.insert("id".into(), Tag::String("minecraft:pig".into()));
|
||||
let mut root = Compound::new();
|
||||
root.insert("id".into(), Tag::String("minecraft:pig".into()));
|
||||
root.insert("Passengers".into(), Tag::List(vec![Tag::Compound(rider)]));
|
||||
let mut tag = Tag::Compound(root);
|
||||
place_summoned(&mut tag, [1.5, 70.0, -2.5]);
|
||||
let pos = Tag::List(
|
||||
[1.5, 70.0, -2.5]
|
||||
.map(|v: f64| Tag::Double(v.to_bits()))
|
||||
.to_vec(),
|
||||
);
|
||||
let Tag::Compound(root) = &tag else { panic!() };
|
||||
assert_eq!(root.get(&"Pos".into()), Some(&pos));
|
||||
let Some(Tag::List(riders)) = root.get(&"Passengers".into()) else {
|
||||
panic!("no passengers");
|
||||
};
|
||||
let Tag::Compound(rider) = &riders[0] else {
|
||||
panic!()
|
||||
};
|
||||
assert_eq!(rider.get(&"Pos".into()), Some(&pos));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summon_positions_are_summons() {
|
||||
assert!(position_ok([0.5, 64.0, 0.5]));
|
||||
|
||||
Reference in new issue
Block a user