mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
chest
This commit is contained in:
parent
b44dc94274
commit
6286e953a6
17 changed files with 282 additions and 44 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -181,6 +181,7 @@ dependencies = [
|
||||||
"azalea-chat",
|
"azalea-chat",
|
||||||
"azalea-client",
|
"azalea-client",
|
||||||
"azalea-core",
|
"azalea-core",
|
||||||
|
"azalea-inventory",
|
||||||
"azalea-physics",
|
"azalea-physics",
|
||||||
"azalea-protocol",
|
"azalea-protocol",
|
||||||
"azalea-registry",
|
"azalea-registry",
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
disconnect::{DisconnectEvent, DisconnectPlugin},
|
disconnect::{DisconnectEvent, DisconnectPlugin},
|
||||||
events::{Event, EventPlugin, LocalPlayerEvents},
|
events::{Event, EventPlugin, LocalPlayerEvents},
|
||||||
interact::{CurrentSequenceNumber, InteractPlugin},
|
interact::{CurrentSequenceNumber, InteractPlugin},
|
||||||
inventory::{InventoryComponent, InventoryPlugin},
|
inventory_plugin::{InventoryComponent, InventoryPlugin},
|
||||||
local_player::{
|
local_player::{
|
||||||
death_event, handle_send_packet_event, update_in_loaded_chunk, GameProfileComponent,
|
death_event, handle_send_packet_event, update_in_loaded_chunk, GameProfileComponent,
|
||||||
LocalPlayer, PhysicsState, SendPacketEvent,
|
LocalPlayer, PhysicsState, SendPacketEvent,
|
||||||
|
@ -50,6 +50,7 @@ use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
schedule::IntoSystemConfig,
|
schedule::IntoSystemConfig,
|
||||||
schedule::{LogLevel, ScheduleBuildSettings, ScheduleLabel},
|
schedule::{LogLevel, ScheduleBuildSettings, ScheduleLabel},
|
||||||
|
system::{ResMut, Resource},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_log::LogPlugin;
|
use bevy_log::LogPlugin;
|
||||||
|
@ -59,7 +60,10 @@ use log::{debug, error};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use std::{collections::HashMap, fmt::Debug, io, net::SocketAddr, sync::Arc, time::Duration};
|
use std::{collections::HashMap, fmt::Debug, io, net::SocketAddr, sync::Arc, time::Duration};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::{sync::mpsc, time};
|
use tokio::{
|
||||||
|
sync::{broadcast, mpsc},
|
||||||
|
time,
|
||||||
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
/// `Client` has the things that a user interacting with the library will want.
|
/// `Client` has the things that a user interacting with the library will want.
|
||||||
|
@ -627,6 +631,36 @@ pub async fn tick_run_schedule_loop(run_schedule_sender: mpsc::UnboundedSender<(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A resource that contains a [`broadcast::Sender`] that will be sent every
|
||||||
|
/// time the ECS schedule is run.
|
||||||
|
///
|
||||||
|
/// This is useful for running code every schedule from async user code.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// let mut receiver = {
|
||||||
|
/// let ecs = client.ecs.lock();
|
||||||
|
/// let schedule_broadcast = ecs.resource::<RanScheduleBroadcast>();
|
||||||
|
/// schedule_broadcast.subscribe()
|
||||||
|
/// };
|
||||||
|
/// while receiver.recv().await.is_ok() {
|
||||||
|
/// // do something
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[derive(Resource, Deref)]
|
||||||
|
pub struct RanScheduleBroadcast(broadcast::Sender<()>);
|
||||||
|
|
||||||
|
fn send_ran_schedule_event(ran_schedule_broadcast: ResMut<RanScheduleBroadcast>) {
|
||||||
|
let _ = ran_schedule_broadcast.0.send(());
|
||||||
|
}
|
||||||
|
/// A plugin that makes the [`RanScheduleBroadcast`] resource available.
|
||||||
|
pub struct RanSchedulePlugin;
|
||||||
|
impl Plugin for RanSchedulePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.insert_resource(RanScheduleBroadcast(broadcast::channel(1).0))
|
||||||
|
.add_system(send_ran_schedule_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This plugin group will add all the default plugins necessary for Azalea to
|
/// This plugin group will add all the default plugins necessary for Azalea to
|
||||||
/// work.
|
/// work.
|
||||||
pub struct DefaultPlugins;
|
pub struct DefaultPlugins;
|
||||||
|
@ -647,5 +681,6 @@ impl PluginGroup for DefaultPlugins {
|
||||||
.add(DisconnectPlugin)
|
.add(DisconnectPlugin)
|
||||||
.add(PlayerMovePlugin)
|
.add(PlayerMovePlugin)
|
||||||
.add(InteractPlugin)
|
.add(InteractPlugin)
|
||||||
|
.add(RanSchedulePlugin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,11 @@ impl Plugin for InteractPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<BlockInteractEvent>().add_systems(
|
app.add_event::<BlockInteractEvent>().add_systems(
|
||||||
(
|
(
|
||||||
handle_block_interact_event,
|
|
||||||
update_hit_result_component.after(clamp_look_direction),
|
update_hit_result_component.after(clamp_look_direction),
|
||||||
|
handle_block_interact_event,
|
||||||
)
|
)
|
||||||
.before(handle_send_packet_event),
|
.before(handle_send_packet_event)
|
||||||
|
.chain(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,63 @@
|
||||||
|
use azalea_chat::FormattedText;
|
||||||
|
use azalea_core::BlockPos;
|
||||||
use azalea_inventory::{ItemSlot, Menu};
|
use azalea_inventory::{ItemSlot, Menu};
|
||||||
|
use azalea_registry::MenuKind;
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::{component::Component, entity::Entity, event::EventReader, system::Query};
|
use bevy_ecs::{
|
||||||
|
component::Component,
|
||||||
|
entity::Entity,
|
||||||
|
event::EventReader,
|
||||||
|
schedule::IntoSystemConfigs,
|
||||||
|
system::{Commands, Query},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{client::RanScheduleBroadcast, Client};
|
||||||
|
|
||||||
pub struct InventoryPlugin;
|
pub struct InventoryPlugin;
|
||||||
impl Plugin for InventoryPlugin {
|
impl Plugin for InventoryPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<ClientSideCloseContainerEvent>()
|
app.add_event::<ClientSideCloseContainerEvent>()
|
||||||
.add_system(handle_client_side_close_container_event);
|
.add_event::<MenuOpenedEvent>()
|
||||||
|
.add_systems(
|
||||||
|
(
|
||||||
|
handle_menu_opened_event,
|
||||||
|
handle_client_side_close_container_event,
|
||||||
|
)
|
||||||
|
.chain(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Debug)]
|
||||||
|
pub struct WaitingForInventoryOpen;
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn open_container(&mut self, pos: BlockPos) -> Option<Menu> {
|
||||||
|
self.ecs
|
||||||
|
.lock()
|
||||||
|
.entity_mut(self.entity)
|
||||||
|
.insert(WaitingForInventoryOpen);
|
||||||
|
self.block_interact(pos);
|
||||||
|
|
||||||
|
let mut receiver = {
|
||||||
|
let ecs = self.ecs.lock();
|
||||||
|
let schedule_broadcast = ecs.resource::<RanScheduleBroadcast>();
|
||||||
|
schedule_broadcast.subscribe()
|
||||||
|
};
|
||||||
|
while receiver.recv().await.is_ok() {
|
||||||
|
let ecs = self.ecs.lock();
|
||||||
|
if ecs.get::<WaitingForInventoryOpen>(self.entity).is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ecs = self.ecs.lock();
|
||||||
|
let inventory = ecs.get::<InventoryComponent>(self.entity);
|
||||||
|
if let Some(inventory) = inventory {
|
||||||
|
inventory.container_menu.clone()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +84,7 @@ pub struct InventoryComponent {
|
||||||
pub carried: ItemSlot,
|
pub carried: ItemSlot,
|
||||||
/// An identifier used by the server to track client inventory desyncs.
|
/// An identifier used by the server to track client inventory desyncs.
|
||||||
pub state_id: u32,
|
pub state_id: u32,
|
||||||
// minecraft also has these fields, but i don't need they're necessary?:
|
// minecraft also has these fields, but i don't think they're necessary?:
|
||||||
// private final NonNullList<ItemStack> remoteSlots;
|
// private final NonNullList<ItemStack> remoteSlots;
|
||||||
// private final IntList remoteDataSlots;
|
// private final IntList remoteDataSlots;
|
||||||
// private ItemStack remoteCarried;
|
// private ItemStack remoteCarried;
|
||||||
|
@ -70,9 +121,33 @@ impl Default for InventoryComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sent from the server when a menu (like a chest or crafting table) was
|
||||||
|
/// opened by the client.
|
||||||
|
pub struct MenuOpenedEvent {
|
||||||
|
pub entity: Entity,
|
||||||
|
pub window_id: u32,
|
||||||
|
pub menu_type: MenuKind,
|
||||||
|
pub title: FormattedText,
|
||||||
|
}
|
||||||
|
fn handle_menu_opened_event(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut events: EventReader<MenuOpenedEvent>,
|
||||||
|
mut query: Query<&mut InventoryComponent>,
|
||||||
|
) {
|
||||||
|
for event in events.iter() {
|
||||||
|
commands
|
||||||
|
.entity(event.entity)
|
||||||
|
.remove::<WaitingForInventoryOpen>();
|
||||||
|
|
||||||
|
let mut inventory = query.get_mut(event.entity).unwrap();
|
||||||
|
inventory.id = event.window_id as i8;
|
||||||
|
inventory.container_menu = Some(Menu::from_kind(event.menu_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Close a container without notifying the server.
|
/// Close a container without notifying the server.
|
||||||
///
|
///
|
||||||
/// Note that this also gets fired from [`CloseContainerEvent`].
|
/// Note that this also gets fired when we get a [`CloseContainerEvent`].
|
||||||
pub struct ClientSideCloseContainerEvent {
|
pub struct ClientSideCloseContainerEvent {
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
}
|
}
|
|
@ -19,7 +19,7 @@ mod entity_query;
|
||||||
mod events;
|
mod events;
|
||||||
mod get_mc_dir;
|
mod get_mc_dir;
|
||||||
pub mod interact;
|
pub mod interact;
|
||||||
pub mod inventory;
|
pub mod inventory_plugin;
|
||||||
mod local_player;
|
mod local_player;
|
||||||
mod movement;
|
mod movement;
|
||||||
pub mod packet_handling;
|
pub mod packet_handling;
|
||||||
|
|
|
@ -39,7 +39,7 @@ use crate::{
|
||||||
chat::{ChatPacket, ChatReceivedEvent},
|
chat::{ChatPacket, ChatReceivedEvent},
|
||||||
client::TabList,
|
client::TabList,
|
||||||
disconnect::DisconnectEvent,
|
disconnect::DisconnectEvent,
|
||||||
inventory::{ClientSideCloseContainerEvent, InventoryComponent},
|
inventory_plugin::{ClientSideCloseContainerEvent, InventoryComponent, MenuOpenedEvent},
|
||||||
local_player::{GameProfileComponent, LocalGameMode, LocalPlayer},
|
local_player::{GameProfileComponent, LocalGameMode, LocalPlayer},
|
||||||
ClientInformation, PlayerInfo,
|
ClientInformation, PlayerInfo,
|
||||||
};
|
};
|
||||||
|
@ -971,7 +971,17 @@ fn process_packet_events(ecs: &mut World) {
|
||||||
ClientboundGamePacket::MerchantOffers(_) => {}
|
ClientboundGamePacket::MerchantOffers(_) => {}
|
||||||
ClientboundGamePacket::MoveVehicle(_) => {}
|
ClientboundGamePacket::MoveVehicle(_) => {}
|
||||||
ClientboundGamePacket::OpenBook(_) => {}
|
ClientboundGamePacket::OpenBook(_) => {}
|
||||||
ClientboundGamePacket::OpenScreen(_) => {}
|
ClientboundGamePacket::OpenScreen(p) => {
|
||||||
|
let mut system_state: SystemState<EventWriter<MenuOpenedEvent>> =
|
||||||
|
SystemState::new(ecs);
|
||||||
|
let mut menu_opened_events = system_state.get_mut(ecs);
|
||||||
|
menu_opened_events.send(MenuOpenedEvent {
|
||||||
|
entity: player_entity,
|
||||||
|
window_id: p.container_id,
|
||||||
|
menu_type: p.menu_type,
|
||||||
|
title: p.title,
|
||||||
|
})
|
||||||
|
}
|
||||||
ClientboundGamePacket::OpenSignEditor(_) => {}
|
ClientboundGamePacket::OpenSignEditor(_) => {}
|
||||||
ClientboundGamePacket::Ping(_) => {}
|
ClientboundGamePacket::Ping(_) => {}
|
||||||
ClientboundGamePacket::PlaceGhostRecipe(_) => {}
|
ClientboundGamePacket::PlaceGhostRecipe(_) => {}
|
||||||
|
|
|
@ -5,6 +5,8 @@ use quote::quote;
|
||||||
pub fn generate(input: &DeclareMenus) -> TokenStream {
|
pub fn generate(input: &DeclareMenus) -> TokenStream {
|
||||||
let mut slot_mut_match_variants = quote! {};
|
let mut slot_mut_match_variants = quote! {};
|
||||||
let mut len_match_variants = quote! {};
|
let mut len_match_variants = quote! {};
|
||||||
|
let mut kind_match_variants = quote! {};
|
||||||
|
let mut contents_match_variants = quote! {};
|
||||||
|
|
||||||
let mut hotbar_slot_start = 0;
|
let mut hotbar_slot_start = 0;
|
||||||
let mut hotbar_slot_end = 0;
|
let mut hotbar_slot_end = 0;
|
||||||
|
@ -12,6 +14,8 @@ pub fn generate(input: &DeclareMenus) -> TokenStream {
|
||||||
for menu in &input.menus {
|
for menu in &input.menus {
|
||||||
slot_mut_match_variants.extend(generate_match_variant_for_slot_mut(menu));
|
slot_mut_match_variants.extend(generate_match_variant_for_slot_mut(menu));
|
||||||
len_match_variants.extend(generate_match_variant_for_len(menu));
|
len_match_variants.extend(generate_match_variant_for_len(menu));
|
||||||
|
kind_match_variants.extend(generate_match_variant_for_kind(menu));
|
||||||
|
contents_match_variants.extend(generate_match_variant_for_contents(menu));
|
||||||
|
|
||||||
// this part is only used to generate `Player::is_hotbar_slot`
|
// this part is only used to generate `Player::is_hotbar_slot`
|
||||||
if menu.name == "Player" {
|
if menu.name == "Player" {
|
||||||
|
@ -55,6 +59,19 @@ pub fn generate(input: &DeclareMenus) -> TokenStream {
|
||||||
#len_match_variants
|
#len_match_variants
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_kind(kind: azalea_registry::MenuKind) -> Self {
|
||||||
|
match kind {
|
||||||
|
#kind_match_variants
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the contents of the menu, not including the player's inventory.
|
||||||
|
pub fn contents(&self) -> Vec<ItemSlot> {
|
||||||
|
match self {
|
||||||
|
#contents_match_variants
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +131,67 @@ pub fn generate_match_variant_for_len(menu: &Menu) -> TokenStream {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_match_variant_for_kind(menu: &Menu) -> TokenStream {
|
||||||
|
// azalea_registry::MenuKind::Player => Menu::Player(Player::default()),
|
||||||
|
// azalea_registry::MenuKind::Generic9x3 => Menu::Generic9x3 { contents:
|
||||||
|
// Default::default(), player: Default::default() },
|
||||||
|
|
||||||
|
let menu_name = &menu.name;
|
||||||
|
let menu_field_names = if menu.name == "Player" {
|
||||||
|
return quote! {};
|
||||||
|
} else {
|
||||||
|
let mut menu_field_names = quote! {};
|
||||||
|
for field in &menu.fields {
|
||||||
|
let field_name = &field.name;
|
||||||
|
menu_field_names.extend(quote! { #field_name: Default::default(), })
|
||||||
|
}
|
||||||
|
quote! { { #menu_field_names } }
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
azalea_registry::MenuKind::#menu_name => Menu::#menu_name #menu_field_names,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_match_variant_for_contents(menu: &Menu) -> TokenStream {
|
||||||
|
// Menu::Generic9x3(m) => {
|
||||||
|
// let mut contents = Vec::new();
|
||||||
|
// contents.extend(player.m.iter().copied());
|
||||||
|
// ...
|
||||||
|
// contents
|
||||||
|
// },
|
||||||
|
// Menu::Generic9x3(m) => {
|
||||||
|
// let mut contents = Vec::new();
|
||||||
|
// contents.extend(m.contents.iter().copied());
|
||||||
|
// contents
|
||||||
|
// },
|
||||||
|
|
||||||
|
let mut instructions = quote! {};
|
||||||
|
let mut length = 0;
|
||||||
|
for field in &menu.fields {
|
||||||
|
let field_name = &field.name;
|
||||||
|
if field_name == "player" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
instructions.extend(if field.length == 1 {
|
||||||
|
quote! { items.push(#field_name.clone()); }
|
||||||
|
} else {
|
||||||
|
quote! { items.extend(#field_name.iter().cloned()); }
|
||||||
|
});
|
||||||
|
length += field.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_matcher(
|
||||||
|
menu,
|
||||||
|
"e! {
|
||||||
|
let mut items = Vec::with_capacity(#length);
|
||||||
|
#instructions
|
||||||
|
items
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_matcher(menu: &Menu, match_arms: &TokenStream, needs_fields: bool) -> TokenStream {
|
fn generate_matcher(menu: &Menu, match_arms: &TokenStream, needs_fields: bool) -> TokenStream {
|
||||||
let menu_name = &menu.name;
|
let menu_name = &menu.name;
|
||||||
let menu_field_names = if needs_fields {
|
let menu_field_names = if needs_fields {
|
||||||
|
|
|
@ -27,6 +27,21 @@ impl<const N: usize> Default for SlotList<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Menu {
|
||||||
|
/// Get the [`Player`] from this [`Menu`].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Will panic if the menu isn't `Menu::Player`.
|
||||||
|
pub fn as_player(&self) -> &Player {
|
||||||
|
if let Menu::Player(player) = &self {
|
||||||
|
player
|
||||||
|
} else {
|
||||||
|
unreachable!("Called `Menu::as_player` on a menu that wasn't `Player`.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the player inventory part is always the last 36 slots (except in the Player
|
// the player inventory part is always the last 36 slots (except in the Player
|
||||||
// menu), so we don't have to explicitly specify it
|
// menu), so we don't have to explicitly specify it
|
||||||
|
|
||||||
|
@ -142,18 +157,3 @@ declare_menus! {
|
||||||
result: 1,
|
result: 1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Menu {
|
|
||||||
/// Get the [`Player`] from this [`Menu`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Will panic if the menu isn't `Menu::Player`.
|
|
||||||
pub fn as_player(&self) -> &Player {
|
|
||||||
if let Menu::Player(player) = &self {
|
|
||||||
player
|
|
||||||
} else {
|
|
||||||
unreachable!("Called `Menu::as_player` on a menu that wasn't `Player`.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,6 +10,15 @@ pub enum ItemSlot {
|
||||||
Present(ItemSlotData),
|
Present(ItemSlotData),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ItemSlot {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
matches!(self, ItemSlot::Empty)
|
||||||
|
}
|
||||||
|
pub fn is_present(&self) -> bool {
|
||||||
|
matches!(self, ItemSlot::Present(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An item in an inventory, with a count and NBT. Usually you want [`ItemSlot`]
|
/// An item in an inventory, with a count and NBT. Usually you want [`ItemSlot`]
|
||||||
/// or [`azalea_registry::Item`] instead.
|
/// or [`azalea_registry::Item`] instead.
|
||||||
#[derive(Debug, Clone, McBuf)]
|
#[derive(Debug, Clone, McBuf)]
|
||||||
|
|
|
@ -6,6 +6,6 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
pub struct ClientboundOpenScreenPacket {
|
pub struct ClientboundOpenScreenPacket {
|
||||||
#[var]
|
#[var]
|
||||||
pub container_id: u32,
|
pub container_id: u32,
|
||||||
pub menu_type: azalea_registry::Menu,
|
pub menu_type: azalea_registry::MenuKind,
|
||||||
pub title: FormattedText,
|
pub title: FormattedText,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3010,7 +3010,7 @@ enum MemoryModuleKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
registry! {
|
registry! {
|
||||||
enum Menu {
|
enum MenuKind {
|
||||||
Generic9x1 => "minecraft:generic_9x1",
|
Generic9x1 => "minecraft:generic_9x1",
|
||||||
Generic9x2 => "minecraft:generic_9x2",
|
Generic9x2 => "minecraft:generic_9x2",
|
||||||
Generic9x3 => "minecraft:generic_9x3",
|
Generic9x3 => "minecraft:generic_9x3",
|
||||||
|
|
|
@ -18,6 +18,7 @@ azalea-block = { version = "0.6.0", path = "../azalea-block" }
|
||||||
azalea-chat = { version = "0.6.0", path = "../azalea-chat" }
|
azalea-chat = { version = "0.6.0", path = "../azalea-chat" }
|
||||||
azalea-client = { version = "0.6.0", path = "../azalea-client" }
|
azalea-client = { version = "0.6.0", path = "../azalea-client" }
|
||||||
azalea-core = { version = "0.6.0", path = "../azalea-core" }
|
azalea-core = { version = "0.6.0", path = "../azalea-core" }
|
||||||
|
azalea-inventory = { version = "0.1.0", path = "../azalea-inventory" }
|
||||||
azalea-physics = { version = "0.6.0", path = "../azalea-physics" }
|
azalea-physics = { version = "0.6.0", path = "../azalea-physics" }
|
||||||
azalea-protocol = { version = "0.6.0", path = "../azalea-protocol" }
|
azalea-protocol = { version = "0.6.0", path = "../azalea-protocol" }
|
||||||
azalea-registry = { version = "0.6.0", path = "../azalea-registry" }
|
azalea-registry = { version = "0.6.0", path = "../azalea-registry" }
|
||||||
|
|
|
@ -48,7 +48,10 @@ async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
bot.goto(chest_block.into());
|
bot.goto(chest_block.into());
|
||||||
let chest = bot.open_container(&chest_block).await.unwrap();
|
let Some(chest) = bot.open_container(&chest_block).await else {
|
||||||
|
println!("Couldn't open chest");
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
bot.take_amount_from_container(&chest, 5, |i| i.id == "#minecraft:planks")
|
bot.take_amount_from_container(&chest, 5, |i| i.id == "#minecraft:planks")
|
||||||
.await;
|
.await;
|
||||||
chest.close().await;
|
chest.close().await;
|
||||||
|
|
|
@ -6,7 +6,8 @@ use azalea::ecs::query::With;
|
||||||
use azalea::entity::metadata::Player;
|
use azalea::entity::metadata::Player;
|
||||||
use azalea::entity::{EyeHeight, Position};
|
use azalea::entity::{EyeHeight, Position};
|
||||||
use azalea::interact::HitResultComponent;
|
use azalea::interact::HitResultComponent;
|
||||||
use azalea::inventory::InventoryComponent;
|
use azalea::inventory::ItemSlot;
|
||||||
|
use azalea::inventory_plugin::InventoryComponent;
|
||||||
use azalea::pathfinder::BlockPosGoal;
|
use azalea::pathfinder::BlockPosGoal;
|
||||||
use azalea::{prelude::*, swarm::prelude::*, BlockPos, GameProfileComponent, WalkDirection};
|
use azalea::{prelude::*, swarm::prelude::*, BlockPos, GameProfileComponent, WalkDirection};
|
||||||
use azalea::{Account, Client, Event};
|
use azalea::{Account, Client, Event};
|
||||||
|
@ -149,17 +150,17 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
|
||||||
println!("inventory: {:?}", inventory.menu());
|
println!("inventory: {:?}", inventory.menu());
|
||||||
}
|
}
|
||||||
"findblock" => {
|
"findblock" => {
|
||||||
let target_pos = bot.world().read().find_block(
|
let target_pos = bot
|
||||||
bot.position(),
|
.world()
|
||||||
&azalea_registry::Block::DiamondBlock.into(),
|
.read()
|
||||||
);
|
.find_block(bot.position(), &azalea::Block::DiamondBlock.into());
|
||||||
bot.chat(&format!("target_pos: {target_pos:?}",));
|
bot.chat(&format!("target_pos: {target_pos:?}",));
|
||||||
}
|
}
|
||||||
"gotoblock" => {
|
"gotoblock" => {
|
||||||
let target_pos = bot.world().read().find_block(
|
let target_pos = bot
|
||||||
bot.position(),
|
.world()
|
||||||
&azalea_registry::Block::DiamondBlock.into(),
|
.read()
|
||||||
);
|
.find_block(bot.position(), &azalea::Block::DiamondBlock.into());
|
||||||
if let Some(target_pos) = target_pos {
|
if let Some(target_pos) = target_pos {
|
||||||
// +1 to stand on top of the block
|
// +1 to stand on top of the block
|
||||||
bot.goto(BlockPosGoal::from(target_pos.up(1)));
|
bot.goto(BlockPosGoal::from(target_pos.up(1)));
|
||||||
|
@ -171,7 +172,7 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
|
||||||
let target_pos = bot
|
let target_pos = bot
|
||||||
.world()
|
.world()
|
||||||
.read()
|
.read()
|
||||||
.find_block(bot.position(), &azalea_registry::Block::Lever.into());
|
.find_block(bot.position(), &azalea::Block::Lever.into());
|
||||||
let Some(target_pos) = target_pos else {
|
let Some(target_pos) = target_pos else {
|
||||||
bot.chat("no lever found");
|
bot.chat("no lever found");
|
||||||
return Ok(())
|
return Ok(())
|
||||||
|
@ -184,6 +185,27 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
|
||||||
let hit_result = bot.get_component::<HitResultComponent>();
|
let hit_result = bot.get_component::<HitResultComponent>();
|
||||||
bot.chat(&format!("hit_result: {hit_result:?}",));
|
bot.chat(&format!("hit_result: {hit_result:?}",));
|
||||||
}
|
}
|
||||||
|
"chest" => {
|
||||||
|
let target_pos = bot
|
||||||
|
.world()
|
||||||
|
.read()
|
||||||
|
.find_block(bot.position(), &azalea::Block::Chest.into());
|
||||||
|
let Some(target_pos) = target_pos else {
|
||||||
|
bot.chat("no chest found");
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
|
bot.look_at(target_pos.center());
|
||||||
|
let container = bot.open_container(target_pos).await;
|
||||||
|
if let Some(container) = container {
|
||||||
|
for item in container.contents() {
|
||||||
|
if let ItemSlot::Present(item) = item {
|
||||||
|
println!("item: {:?}", item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("no container found");
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
|
||||||
bot.goto(pathfinder::Goals::NearXZ(5, azalea::BlockXZ(0, 0)))
|
bot.goto(pathfinder::Goals::NearXZ(5, azalea::BlockXZ(0, 0)))
|
||||||
.await;
|
.await;
|
||||||
let chest = bot
|
let chest = bot
|
||||||
.open_container(&bot.world().find_block(azalea_registry::Block::Chest))
|
.open_container(&bot.world().find_block(azalea::Block::Chest))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
bot.take_amount_from_container(&chest, 5, |i| i.id == "#minecraft:planks")
|
bot.take_amount_from_container(&chest, 5, |i| i.id == "#minecraft:planks")
|
||||||
|
@ -46,9 +46,7 @@ async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
|
||||||
chest.close().await;
|
chest.close().await;
|
||||||
|
|
||||||
let crafting_table = bot
|
let crafting_table = bot
|
||||||
.open_crafting_table(
|
.open_crafting_table(&bot.world.find_block(azalea::Block::CraftingTable))
|
||||||
&bot.world.find_block(azalea_registry::Block::CraftingTable),
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
bot.craft(&crafting_table, &bot.recipe_for("minecraft:sticks"))
|
bot.craft(&crafting_table, &bot.recipe_for("minecraft:sticks"))
|
||||||
|
|
|
@ -10,6 +10,7 @@ use app::{App, Plugin, PluginGroup};
|
||||||
pub use azalea_block as blocks;
|
pub use azalea_block as blocks;
|
||||||
pub use azalea_client::*;
|
pub use azalea_client::*;
|
||||||
pub use azalea_core::{BlockPos, Vec3};
|
pub use azalea_core::{BlockPos, Vec3};
|
||||||
|
pub use azalea_inventory as inventory;
|
||||||
pub use azalea_protocol as protocol;
|
pub use azalea_protocol as protocol;
|
||||||
pub use azalea_registry::{Block, EntityKind};
|
pub use azalea_registry::{Block, EntityKind};
|
||||||
pub use azalea_world::{entity, Instance};
|
pub use azalea_world::{entity, Instance};
|
||||||
|
|
|
@ -16,12 +16,16 @@ def generate_registries(registries: dict):
|
||||||
# Stone => "minecraft:stone"
|
# Stone => "minecraft:stone"
|
||||||
# });
|
# });
|
||||||
|
|
||||||
|
registry_name = registry_name.split(':')[1]
|
||||||
|
|
||||||
if registry_name.endswith('_type'):
|
if registry_name.endswith('_type'):
|
||||||
# change _type to _kind because that's Rustier (and because _type
|
# change _type to _kind because that's Rustier (and because _type
|
||||||
# is a reserved keyword)
|
# is a reserved keyword)
|
||||||
registry_name = registry_name[:-5] + '_kind'
|
registry_name = registry_name[:-5] + '_kind'
|
||||||
|
elif registry_name == 'menu':
|
||||||
|
registry_name = 'menu_kind'
|
||||||
|
|
||||||
registry_struct_name = to_camel_case(registry_name.split(':')[1])
|
registry_struct_name = to_camel_case(registry_name)
|
||||||
|
|
||||||
registry_code = []
|
registry_code = []
|
||||||
registry_code.append(f'enum {registry_struct_name} {{')
|
registry_code.append(f'enum {registry_struct_name} {{')
|
||||||
|
|
Loading…
Add table
Reference in a new issue