Save and load creative toolbars with the toolbar keys

This commit is contained in:
Kacpherek committed 2026-10-27 06:21:01 +01:00
1 parent 91e332a5eb
commit 85f34393fe
3 files changed
+70 -1

No files matched your search

+11 -1
View File
@@ -34,6 +34,7 @@ mod consume;
mod control;
mod copper_golems;
mod creaking;
mod creative_hotbar;
mod creatures;
mod crossbow;
pub(crate) mod cushions;
@@ -11471,7 +11472,7 @@ impl Game<'_> {
| KeyCode::Digit9
if self.screen == Screen::Playing =>
{
self.selected = match key {
let slot = match key {
KeyCode::Digit1 => 0,
KeyCode::Digit2 => 1,
KeyCode::Digit3 => 2,
@@ -11482,6 +11483,15 @@ impl Game<'_> {
KeyCode::Digit8 => 7,
_ => 8,
};
// Minecraft.handleKeybinds: a creative player holding the load
// or save toolbar key loads or saves a toolbar instead (load
// first when both are held).
let load = self.mapped_key_down("key.loadToolbarActivator");
if self.creative && (load || self.mapped_key_down("key.saveToolbarActivator")) {
self.hotbar_load_or_save(slot, load);
} else {
self.selected = slot;
}
}
_ => {}
}
@@ -0,0 +1,39 @@
//! The creative toolbars, `hotbar.nbt` beside `options.txt`: hold the save or
//! load key and press a hotbar key (`Minecraft.handleKeybinds`).
use super::Game;
use horizon_client::{hotbar, keybinds, text::Text};
impl Game<'_> {
/// Whether the key bound to `mapping` is held.
pub(super) fn mapped_key_down(&self, mapping: &str) -> bool {
keybinds::key_code(self.settings.keys.get(mapping))
.is_some_and(|k| self.physical_keys.contains(&k))
}
/// `CreativeModeInventoryScreen.handleHotbarLoadOrSave` for the hotbar key
/// `index`: load puts the saved row in the hotbar (the creative slot
/// packets follow from the inventory change), save stores the hotbar and
/// says so on the action bar.
pub(super) fn hotbar_load_or_save(&mut self, index: usize, load: bool) {
let path = Self::options_path().with_file_name("hotbar.nbt");
let known = |id: &str| self.res.items().get(id).is_some();
let mut rows = hotbar::load(&path, &known);
if load {
for (slot, stack) in rows[index].iter().enumerate() {
self.inventory[slot] = stack.clone();
}
return;
}
rows[index] = self.inventory[..hotbar::SIZE].to_vec();
let _ = hotbar::save(&path, &rows);
let key = |mapping: &str| keybinds::display_name(self.settings.keys.get(mapping));
let message = Text::translate(
"inventory.hotbarSaved",
&[
key("key.loadToolbarActivator"),
key(&format!("key.hotbar.{}", index + 1)),
],
);
self.titles.set_overlay(message, false);
}
}
+20
View File
@@ -119,3 +119,23 @@ pub fn load(path: &Path, known: &dyn Fn(&str) -> bool) -> Vec<Hotbar> {
_ => (0..GROUPS).map(|_| empty()).collect(),
}
}
/// `HotbarManager.save`: the nine rows with the current data version, each
/// stack as `ItemStack.OPTIONAL_CODEC` writes it (an empty one is `{}`).
pub fn save(path: &Path, rows: &[Hotbar]) -> crate::Result<()> {
let mut entries = vec![(
JavaString::from("DataVersion"),
Tag::Int(horizon_world::DATA_VERSION),
)];
for (i, row) in rows.iter().enumerate() {
let stacks = row.iter().map(|s| match s {
Some(s) => save::item_to_nbt(s),
None => Tag::compound(Vec::<(&str, Tag)>::new()),
});
entries.push((
JavaString::from(i.to_string().as_str()),
Tag::List(stacks.collect()),
));
}
save::write_dat(path, Tag::compound(entries))
}