mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
game/maps: honour can_place_on when using a map on a banner in adventure mode
In adventure mode, vanilla allows ItemStack.useOn if the item's can_place_on component matches the clicked block. Previously, use_map_on_banner checked only !self.may_build() and returned early without checking can_place_on. This honours can_place_on_in_adventure on the banner's block position, allowing adventure mode players with matching maps to toggle banner markers. Co-Authored-By: Antigravity <[email protected]>
This commit is contained in:
1 parent
3c7bb44aa1
commit
2948fb86ed
1 file changed
+104
-3
@@ -1171,9 +1171,7 @@ impl Game<'_> {
|
||||
let Some(id) = map_id(stack) else {
|
||||
return false;
|
||||
};
|
||||
// ItemStack.useOn passes in adventure mode (its `can_place_on`
|
||||
// exception is not ported).
|
||||
if !self.may_build() {
|
||||
if !self.may_build() && !self.can_place_on_in_adventure(hit.pos) {
|
||||
return false;
|
||||
}
|
||||
let [x, y, z] = hit.pos;
|
||||
@@ -2012,4 +2010,107 @@ mod tests {
|
||||
assert_eq!(clamp_map_coordinate(-70.0), -128);
|
||||
assert_eq!(clamp_map_coordinate(10.25), 21);
|
||||
}
|
||||
|
||||
/// `ItemStack.useOn` / `MapItem.useOn`: in adventure mode, a map whose
|
||||
/// `can_place_on` component includes the banner block toggles that banner's
|
||||
/// marker, while one without does not.
|
||||
#[test]
|
||||
fn map_on_banner_in_adventure_mode_honours_can_place_on() {
|
||||
use crate::game::{Audio, Game, Options, Progress, Settings, load_resources};
|
||||
use horizon_client::{chunk::Chunk, command::args::GameMode};
|
||||
use std::sync::Arc;
|
||||
|
||||
let Some(root) = std::env::var_os("HORIZON_TEST_RESOURCES") else {
|
||||
return;
|
||||
};
|
||||
let root = std::path::PathBuf::from(root);
|
||||
let settings = Settings::default();
|
||||
let loaded = load_resources(
|
||||
root.clone(),
|
||||
None,
|
||||
&root,
|
||||
&settings,
|
||||
std::time::Instant::now(),
|
||||
false,
|
||||
true,
|
||||
&Progress::new(),
|
||||
&mut |_, _| unreachable!(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut options = Options::parse(std::iter::empty()).unwrap().unwrap();
|
||||
options.resources = root.clone();
|
||||
options.execution_role = crate::game::execution_role::ExecutionRole::IntegratedServer;
|
||||
let mut game = Game::new(
|
||||
&loaded.resources,
|
||||
loaded.pack,
|
||||
loaded.gui.unwrap(),
|
||||
options,
|
||||
settings,
|
||||
Audio::silent(&root),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let pos = [0, 64, 0];
|
||||
game.world
|
||||
.chunks
|
||||
.insert((0, 0), Arc::new(Chunk::empty(0, 0)));
|
||||
let banner_state = game
|
||||
.pack
|
||||
.assets
|
||||
.registry
|
||||
.default_state("minecraft:red_banner")
|
||||
.unwrap();
|
||||
game.world
|
||||
.set(pos[0], pos[1], pos[2], banner_state)
|
||||
.unwrap();
|
||||
game.world.block_entities.insert(
|
||||
(pos[0], pos[1], pos[2]),
|
||||
horizon_client::containers::BlockEntity::Banner(horizon_client::containers::Banner {
|
||||
layers: Vec::new(),
|
||||
name: None,
|
||||
components: Default::default(),
|
||||
}),
|
||||
);
|
||||
|
||||
let map_id = 42;
|
||||
game.maps
|
||||
.data
|
||||
.insert(map_id, MapData::fresh(0.0, 0.0, 0, "minecraft:overworld"));
|
||||
game.set_mode(GameMode::Adventure);
|
||||
let hit = super::super::Hit {
|
||||
pos,
|
||||
face: [0, 1, 0],
|
||||
point: [
|
||||
pos[0] as f64 + 0.5,
|
||||
pos[1] as f64 + 0.5,
|
||||
pos[2] as f64 + 0.5,
|
||||
],
|
||||
};
|
||||
let mut stack = ItemStack::new("minecraft:filled_map", 1);
|
||||
stack.data_mut().map_id = Some(map_id);
|
||||
|
||||
// Without can_place_on, use_map_on_banner fails in adventure mode.
|
||||
*game.held_mut() = Some(stack.clone());
|
||||
assert!(!game.use_map_on_banner(&hit, &stack));
|
||||
assert!(game.map(map_id).unwrap().banners.is_empty());
|
||||
|
||||
// With can_place_on listing the banner block, the marker toggles.
|
||||
stack.data_mut().other.push((
|
||||
"minecraft:can_place_on".into(),
|
||||
Tag::compound([(
|
||||
"blocks",
|
||||
Tag::List(vec![Tag::String("minecraft:red_banner".into())]),
|
||||
)]),
|
||||
));
|
||||
*game.held_mut() = Some(stack.clone());
|
||||
assert!(game.use_map_on_banner(&hit, &stack));
|
||||
assert_eq!(game.map(map_id).unwrap().banners.len(), 1);
|
||||
assert_eq!(game.map(map_id).unwrap().banners[0].pos, pos);
|
||||
assert_eq!(game.map(map_id).unwrap().banners[0].color, "red");
|
||||
|
||||
// Second use toggles the marker off.
|
||||
assert!(game.use_map_on_banner(&hit, &stack));
|
||||
assert!(game.map(map_id).unwrap().banners.is_empty());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user