Skip to content

Commit 0ff8e9e

Browse files
committed
feat(engine, tag): add book API
1 parent e28e665 commit 0ff8e9e

File tree

7 files changed

+120
-18
lines changed

7 files changed

+120
-18
lines changed

crates/hyperion-item/src/builder.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use flecs_ecs::core::Entity;
22
use valence_protocol::{nbt, nbt::Value, ItemKind, ItemStack};
33

4+
mod book;
5+
pub use book::BookBuilder;
6+
47
/// A builder for creating Minecraft items with NBT data
5-
#[derive(Clone)]
8+
#[derive(Clone, Debug)]
69
#[must_use]
710
pub struct ItemBuilder {
811
kind: ItemKind,
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use hyperion::{ItemKind, ItemStack};
2+
use valence_protocol::nbt;
3+
4+
use crate::builder::ItemBuilder;
5+
6+
#[derive(Clone, Debug)]
7+
#[must_use]
8+
pub struct BookBuilder {
9+
item: ItemBuilder,
10+
}
11+
12+
// /give @p minecraft:written_book{author:"AuthorName",title:"BookTitle",pages:['{"text":"Page content"}']}
13+
14+
impl BookBuilder {
15+
pub fn new(author: impl Into<String>, title: impl Into<String>) -> Self {
16+
let mut item = ItemBuilder::new(ItemKind::WrittenBook);
17+
18+
let author = author.into();
19+
let title = title.into();
20+
21+
let mut nbt = nbt::Compound::new();
22+
23+
nbt.insert("author", nbt::Value::String(author));
24+
nbt.insert("resolved", nbt::Value::Byte(1));
25+
nbt.insert("title", nbt::Value::String(title));
26+
nbt.insert("pages", nbt::Value::List(nbt::List::String(Vec::new())));
27+
28+
item.nbt = Some(nbt);
29+
30+
Self { item }
31+
}
32+
33+
pub fn add_page(mut self, page: impl Into<String>) -> Self {
34+
let page = page.into();
35+
let json = format!(r#"{{"text":"{page}"}}"#);
36+
37+
if let Some(nbt) = &mut self.item.nbt {
38+
if let nbt::Value::List(nbt::List::String(pages)) = nbt.get_mut("pages").unwrap() {
39+
pages.push(json);
40+
}
41+
}
42+
43+
self
44+
}
45+
46+
#[must_use]
47+
pub fn build(self) -> ItemStack {
48+
self.item.build()
49+
}
50+
}

crates/hyperion-item/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use flecs_ecs::{
44
macros::Component,
55
prelude::Module,
66
};
7-
use hyperion::storage::{EventFn, GlobalEventHandlers};
8-
use valence_protocol::{nbt, Hand};
7+
use hyperion::storage::{ClickEvent, EventFn, GlobalEventHandlers};
8+
use valence_protocol::nbt;
99

1010
pub mod builder;
1111

@@ -14,7 +14,7 @@ pub struct ItemModule;
1414

1515
#[derive(Component, Constructor, Deref, DerefMut)]
1616
pub struct Handler {
17-
on_click: EventFn<Hand>,
17+
on_click: EventFn<ClickEvent>,
1818
}
1919

2020
impl Module for ItemModule {
@@ -23,7 +23,7 @@ impl Module for ItemModule {
2323
world.component::<Handler>();
2424

2525
world.get::<&mut GlobalEventHandlers>(|handlers| {
26-
handlers.click.register(|query, hand| {
26+
handlers.click.register(|query, event| {
2727
let world = query.world;
2828
let inventory = &mut *query.inventory;
2929

@@ -51,7 +51,7 @@ impl Module for ItemModule {
5151

5252
handler.try_get::<&Handler>(|handler| {
5353
let on_interact = &handler.on_click;
54-
on_interact(query, hand);
54+
on_interact(query, event);
5555
});
5656
});
5757
});

crates/hyperion-rank-tree/src/inventory.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use flecs_ecs::core::{World, WorldGet};
22
use hyperion_inventory::PlayerInventory;
3-
use hyperion_item::builder::{AttackDamage, Color, ItemBuilder};
3+
use hyperion_item::builder::{AttackDamage, BookBuilder, Color, ItemBuilder};
44
use valence_protocol::ItemKind;
55

66
use crate::{Handles, Rank, Team};
@@ -22,7 +22,8 @@ pub const MAIN_SLOT: u16 = 0;
2222
pub const PICKAXE_SLOT: u16 = 1;
2323
pub const BLOCK_SLOT: u16 = 2;
2424
pub const UPGRADE_START_SLOT: u16 = 3;
25-
pub const GUI_SLOT: u16 = 8;
25+
pub const GUI_SLOT: u16 = 7;
26+
pub const HELP_SLOT: u16 = 8;
2627

2728
impl Rank {
2829
pub fn apply_inventory(
@@ -32,9 +33,34 @@ impl Rank {
3233
world: &World,
3334
build_count: i8,
3435
) {
36+
inventory.clear();
3537
let upgrade_not_available = ItemBuilder::new(ItemKind::GrayDye);
3638

37-
inventory.clear();
39+
let book = BookBuilder::new("§b@andrewgazelka", "§6§l10k Guide")
40+
.add_page(
41+
"§6Welcome to Hyperion!\n\n§7This is a §c10,000§7 player PvP battle to break the \
42+
Guinness World Record!\n\n§7Current record: §b8,825 players",
43+
)
44+
.add_page(
45+
"§6§lTeams\n\n§cRed Team\n§9Blue Team\n§aGreen Team\n§6Yellow Team\n\n§7Teams are \
46+
identified by boot color!",
47+
)
48+
.add_page(
49+
"§6§lProgression\n\n§7Gain XP by:\n§7- Mining ores\n§7- Killing players\n\n§7When \
50+
killed:\n§7- Keep §61/3§7 of XP\n§7- Killer gets §61/2§7 of your XP",
51+
)
52+
.add_page(
53+
"§6§lClasses\n\n§7Everyone starts with the §dStick§7 class\n\n§7Unlock new \
54+
classes by gaining XP and defeating players!\n\n§7Upgrade your gear to become \
55+
stronger!",
56+
)
57+
.add_page(
58+
"§6§lControls\n\n§7[1-4] §7Combat Items\n§7[5-6] §7Building Blocks\n§7[7] \
59+
§7Upgrades Menu\n§7[8] §7Help Book\n\n§6Good luck!",
60+
)
61+
.build();
62+
63+
inventory.set_hotbar(HELP_SLOT, book);
3864

3965
let color = match team {
4066
Team::Red => Color(255, 0, 0),
@@ -49,7 +75,7 @@ impl Rank {
4975

5076
inventory.set_boots(boots);
5177

52-
let upgrades = ["Speed", "Vision", "Health", "Armor", "Damage"];
78+
let upgrades = ["Speed", "Health", "Armor", "Damage"];
5379

5480
world.get::<&Handles>(|handles| {
5581
for (i, upgrade) in upgrades.into_iter().enumerate() {

crates/hyperion-rank-tree/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use flecs_ecs::{
44
macros::Component,
55
prelude::Module,
66
};
7-
use hyperion::storage::EventFn;
8-
use valence_protocol::Hand;
7+
use hyperion::storage::{ClickEvent, EventFn};
98

109
pub mod inventory;
1110
pub mod skin;
@@ -51,7 +50,7 @@ impl Module for RankTree {
5150
world.component::<Rank>();
5251
world.component::<Handles>();
5352

54-
let handler: EventFn<Hand> = |query, _| {
53+
let handler: EventFn<ClickEvent> = |query, _| {
5554
let cursor = query.inventory.get_cursor();
5655
println!("clicked {cursor:?}");
5756
};

crates/hyperion/src/simulation/handlers.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use geometry::aabb::Aabb;
88
use glam::{IVec3, Vec3};
99
use hyperion_utils::EntityExt;
1010
use tracing::{info, instrument, trace, warn};
11-
use valence_generated::block::{BlockKind, BlockState, PropName};
11+
use valence_generated::{
12+
block::{BlockKind, BlockState, PropName},
13+
item::ItemKind,
14+
};
1215
use valence_protocol::{
1316
Decode, Hand, ItemStack, Packet, VarInt,
1417
packets::play::{
@@ -28,7 +31,7 @@ use super::{
2831
use crate::{
2932
net::{Compose, NetworkStreamRef, decoder::BorrowedPacketFrame},
3033
simulation::{Pitch, Yaw, aabb, event, event::PluginMessage, metadata::entity::Pose},
31-
storage::{CommandCompletionRequest, Events, GlobalEventHandlers},
34+
storage::{ClickEvent, CommandCompletionRequest, Events, GlobalEventHandlers},
3235
system_registry::SystemId,
3336
};
3437

@@ -334,9 +337,25 @@ pub fn player_interact_item(
334337
mut data: &'static [u8],
335338
query: &mut PacketSwitchQuery<'_>,
336339
) -> anyhow::Result<()> {
337-
let packet = play::PlayerInteractItemC2s::decode(&mut data)?;
340+
let play::PlayerInteractItemC2s { hand, sequence } =
341+
play::PlayerInteractItemC2s::decode(&mut data)?;
342+
343+
let event = ClickEvent {
344+
hand,
345+
sequence: sequence.0,
346+
};
347+
348+
let cursor = query.inventory.get_cursor();
349+
350+
if !cursor.is_empty() && cursor.item == ItemKind::WrittenBook {
351+
let packet = play::OpenWrittenBookS2c { hand };
352+
353+
query
354+
.compose
355+
.unicast(&packet, query.io_ref, SystemId(0), query.world)?;
356+
}
338357

339-
query.handlers.click.trigger_all(query, &packet.hand);
358+
query.handlers.click.trigger_all(query, &event);
340359

341360
Ok(())
342361
}

crates/hyperion/src/storage/event/sync.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@ pub struct CommandCompletionRequest<'a> {
1010
pub id: i32,
1111
}
1212

13+
pub struct ClickEvent {
14+
pub hand: Hand,
15+
pub sequence: i32,
16+
}
17+
1318
#[derive(Component, Default)]
1419
pub struct GlobalEventHandlers {
15-
pub click: EventHandlers<Hand>,
20+
pub click: EventHandlers<ClickEvent>,
1621

1722
// todo: this should be a lifetime for<'a>
1823
pub completion: EventHandlers<CommandCompletionRequest<'static>>,

0 commit comments

Comments
 (0)