mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
everything compiles
This commit is contained in:
parent
8921ae4887
commit
8ea3d728c1
8 changed files with 76 additions and 35 deletions
|
@ -4,7 +4,9 @@ use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(McBuf, Debug, Clone, Default)]
|
#[derive(McBuf, Debug, Clone, Default)]
|
||||||
pub struct GameProfile {
|
pub struct GameProfile {
|
||||||
|
/// The UUID of the player.
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
|
/// The username of the player.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub properties: HashMap<String, ProfilePropertyValue>,
|
pub properties: HashMap<String, ProfilePropertyValue>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ impl Client {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn chat(&self, message: &str) {
|
pub fn chat(&self, message: &str) {
|
||||||
if let Some(command) = message.strip_prefix('/') {
|
if let Some(command) = message.strip_prefix('/') {
|
||||||
self.send_command_packet(command);
|
self.send_command_packet(command);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
pub use crate::chat::ChatPacket;
|
pub use crate::chat::ChatPacket;
|
||||||
use crate::{
|
use crate::{
|
||||||
local_player::{
|
local_player::{
|
||||||
death_event, send_tick_event, update_in_loaded_chunk, LocalPlayer, PhysicsState,
|
death_event, send_tick_event, update_in_loaded_chunk, LocalPlayer, PhysicsState, GameProfileComponent,
|
||||||
},
|
},
|
||||||
movement::{local_player_ai_step, send_position, sprint_listener, walk_listener},
|
movement::{local_player_ai_step, send_position, sprint_listener, walk_listener},
|
||||||
packet_handling::{self, PacketHandlerPlugin},
|
packet_handling::{self, PacketHandlerPlugin},
|
||||||
|
@ -232,7 +232,6 @@ impl Client {
|
||||||
|
|
||||||
let mut local_player = crate::local_player::LocalPlayer::new(
|
let mut local_player = crate::local_player::LocalPlayer::new(
|
||||||
entity,
|
entity,
|
||||||
game_profile,
|
|
||||||
packet_writer_sender,
|
packet_writer_sender,
|
||||||
// default to an empty world, it'll be set correctly later when we
|
// default to an empty world, it'll be set correctly later when we
|
||||||
// get the login packet
|
// get the login packet
|
||||||
|
@ -258,6 +257,7 @@ impl Client {
|
||||||
ecs.entity_mut(entity).insert((
|
ecs.entity_mut(entity).insert((
|
||||||
local_player,
|
local_player,
|
||||||
packet_receiver,
|
packet_receiver,
|
||||||
|
GameProfileComponent(game_profile),
|
||||||
PhysicsState::default(),
|
PhysicsState::default(),
|
||||||
Local,
|
Local,
|
||||||
));
|
));
|
||||||
|
|
|
@ -25,12 +25,34 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// You can then use [`Self::map_entity`] to get components from this
|
/// You can then use [`Self::map_entity`] to get components from this
|
||||||
/// entity.
|
/// entity.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Note that this will very likely change in the future.
|
||||||
|
/// ```
|
||||||
|
/// let entity = bot.entity_by::<With<Player>, (&GameProfileComponent,)>(
|
||||||
|
/// |profile: &&GameProfileComponent| profile.name == sender,
|
||||||
|
/// );
|
||||||
|
/// if let Some(entity) = entity {
|
||||||
|
/// let position = bot.entity_components::<Position>(entity);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn entity_by<F: ReadOnlyWorldQuery, Q: ReadOnlyWorldQuery>(
|
pub fn entity_by<F: ReadOnlyWorldQuery, Q: ReadOnlyWorldQuery>(
|
||||||
&mut self,
|
&mut self,
|
||||||
predicate: impl EntityPredicate<Q, F>,
|
predicate: impl EntityPredicate<Q, F>,
|
||||||
) -> Option<Entity> {
|
) -> Option<Entity> {
|
||||||
predicate.find(self.ecs.clone())
|
predicate.find(self.ecs.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a component from an entity. Note that this will return an owned type
|
||||||
|
/// (i.e. not a reference) so it may be expensive for larger types.
|
||||||
|
pub fn entity_components<Q: Component + Clone>(&mut self, entity: Entity) -> Q {
|
||||||
|
let mut ecs = self.ecs.lock();
|
||||||
|
let mut q = ecs.query::<&Q>();
|
||||||
|
let components = q
|
||||||
|
.get(&ecs, entity)
|
||||||
|
.expect("Entity components must be present in Client::entity)components.");
|
||||||
|
components.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EntityPredicate<Q: ReadOnlyWorldQuery, Filter: ReadOnlyWorldQuery> {
|
pub trait EntityPredicate<Q: ReadOnlyWorldQuery, Filter: ReadOnlyWorldQuery> {
|
||||||
|
|
|
@ -26,7 +26,7 @@ mod plugins;
|
||||||
pub use account::Account;
|
pub use account::Account;
|
||||||
pub use bevy_ecs as ecs;
|
pub use bevy_ecs as ecs;
|
||||||
pub use client::{start_ecs, ChatPacket, Client, ClientInformation, Event, JoinError};
|
pub use client::{start_ecs, ChatPacket, Client, ClientInformation, Event, JoinError};
|
||||||
pub use local_player::LocalPlayer;
|
pub use local_player::{GameProfileComponent, LocalPlayer};
|
||||||
pub use movement::{SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection};
|
pub use movement::{SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection};
|
||||||
pub use player::PlayerInfo;
|
pub use player::PlayerInfo;
|
||||||
pub use plugins::{Plugin, PluginState, PluginStates, Plugins};
|
pub use plugins::{Plugin, PluginState, PluginStates, Plugins};
|
||||||
|
|
|
@ -8,6 +8,7 @@ use azalea_world::{
|
||||||
EntityInfos, PartialWorld, World,
|
EntityInfos, PartialWorld, World,
|
||||||
};
|
};
|
||||||
use bevy_ecs::{component::Component, query::Added, system::Query};
|
use bevy_ecs::{component::Component, query::Added, system::Query};
|
||||||
|
use derive_more::{Deref, DerefMut};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -19,8 +20,6 @@ use crate::{ClientInformation, Event, PlayerInfo, WalkDirection};
|
||||||
/// A player that you control that is currently in a Minecraft server.
|
/// A player that you control that is currently in a Minecraft server.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct LocalPlayer {
|
pub struct LocalPlayer {
|
||||||
pub profile: GameProfile,
|
|
||||||
|
|
||||||
pub packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>,
|
pub packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>,
|
||||||
|
|
||||||
pub client_information: ClientInformation,
|
pub client_information: ClientInformation,
|
||||||
|
@ -59,6 +58,14 @@ pub struct PhysicsState {
|
||||||
pub left_impulse: f32,
|
pub left_impulse: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A component only present in players that contains the [`GameProfile`] (which
|
||||||
|
/// you can use to get a player's name).
|
||||||
|
///
|
||||||
|
/// Note that it's possible for this to be missing in a player if the server
|
||||||
|
/// never sent the player info for them (though this is uncommon).
|
||||||
|
#[derive(Component, Clone, Debug, Deref, DerefMut)]
|
||||||
|
pub struct GameProfileComponent(pub GameProfile);
|
||||||
|
|
||||||
/// Marks a [`LocalPlayer`] that's in a loaded chunk. This is updated at the
|
/// Marks a [`LocalPlayer`] that's in a loaded chunk. This is updated at the
|
||||||
/// beginning of every tick.
|
/// beginning of every tick.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
@ -71,7 +78,6 @@ impl LocalPlayer {
|
||||||
/// defaults, otherwise use [`Client::join`].
|
/// defaults, otherwise use [`Client::join`].
|
||||||
pub fn new(
|
pub fn new(
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
profile: GameProfile,
|
|
||||||
packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>,
|
packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>,
|
||||||
world: Arc<RwLock<World>>,
|
world: Arc<RwLock<World>>,
|
||||||
tx: mpsc::UnboundedSender<Event>,
|
tx: mpsc::UnboundedSender<Event>,
|
||||||
|
@ -79,8 +85,6 @@ impl LocalPlayer {
|
||||||
let client_information = ClientInformation::default();
|
let client_information = ClientInformation::default();
|
||||||
|
|
||||||
LocalPlayer {
|
LocalPlayer {
|
||||||
profile,
|
|
||||||
|
|
||||||
packet_writer,
|
packet_writer,
|
||||||
|
|
||||||
client_information: ClientInformation::default(),
|
client_information: ClientInformation::default(),
|
||||||
|
|
|
@ -31,7 +31,10 @@ use log::{debug, error, trace, warn};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
use crate::{local_player::LocalPlayer, ChatPacket, ClientInformation, Event, PlayerInfo};
|
use crate::{
|
||||||
|
local_player::{GameProfileComponent, LocalPlayer},
|
||||||
|
ChatPacket, ClientInformation, Event, PlayerInfo,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct PacketHandlerPlugin;
|
pub struct PacketHandlerPlugin;
|
||||||
|
|
||||||
|
@ -89,13 +92,13 @@ fn handle_packets(ecs: &mut bevy_ecs::world::World) {
|
||||||
|
|
||||||
let mut system_state: SystemState<(
|
let mut system_state: SystemState<(
|
||||||
Commands,
|
Commands,
|
||||||
Query<&mut LocalPlayer>,
|
Query<(&mut LocalPlayer, &GameProfileComponent)>,
|
||||||
ResMut<WorldContainer>,
|
ResMut<WorldContainer>,
|
||||||
ResMut<EntityInfos>,
|
ResMut<EntityInfos>,
|
||||||
)> = SystemState::new(ecs);
|
)> = SystemState::new(ecs);
|
||||||
let (mut commands, mut query, mut world_container, mut entity_infos) =
|
let (mut commands, mut query, mut world_container, mut entity_infos) =
|
||||||
system_state.get_mut(ecs);
|
system_state.get_mut(ecs);
|
||||||
let mut local_player = query.get_mut(player_entity).unwrap();
|
let (mut local_player, game_profile) = query.get_mut(player_entity).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
// TODO: have registry_holder be a struct because this sucks rn
|
// TODO: have registry_holder be a struct because this sucks rn
|
||||||
|
@ -172,7 +175,7 @@ fn handle_packets(ecs: &mut bevy_ecs::world::World) {
|
||||||
|
|
||||||
let player_bundle = PlayerBundle {
|
let player_bundle = PlayerBundle {
|
||||||
entity: EntityBundle::new(
|
entity: EntityBundle::new(
|
||||||
local_player.profile.uuid,
|
game_profile.uuid,
|
||||||
Vec3::default(),
|
Vec3::default(),
|
||||||
azalea_registry::EntityKind::Player,
|
azalea_registry::EntityKind::Player,
|
||||||
world_name,
|
world_name,
|
||||||
|
@ -527,6 +530,7 @@ fn handle_packets(ecs: &mut bevy_ecs::world::World) {
|
||||||
LoadedBy(HashSet::from([player_entity])),
|
LoadedBy(HashSet::from([player_entity])),
|
||||||
bundle,
|
bundle,
|
||||||
));
|
));
|
||||||
|
|
||||||
println!("spawned player entity: {:?}", spawned.id());
|
println!("spawned player entity: {:?}", spawned.id());
|
||||||
} else {
|
} else {
|
||||||
warn!("got add player packet but we haven't gotten a login packet yet");
|
warn!("got add player packet but we haven't gotten a login packet yet");
|
||||||
|
|
|
@ -5,7 +5,7 @@ use azalea::entity::metadata::Player;
|
||||||
use azalea::entity::Position;
|
use azalea::entity::Position;
|
||||||
use azalea::pathfinder::BlockPosGoal;
|
use azalea::pathfinder::BlockPosGoal;
|
||||||
// use azalea::ClientInformation;
|
// use azalea::ClientInformation;
|
||||||
use azalea::{prelude::*, BlockPos, Swarm, SwarmEvent, WalkDirection};
|
use azalea::{prelude::*, BlockPos, GameProfileComponent, Swarm, SwarmEvent, WalkDirection};
|
||||||
use azalea::{Account, Client, Event};
|
use azalea::{Account, Client, Event};
|
||||||
use azalea_protocol::packets::game::serverbound_client_command_packet::ServerboundClientCommandPacket;
|
use azalea_protocol::packets::game::serverbound_client_command_packet::ServerboundClientCommandPacket;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -103,28 +103,37 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
|
||||||
// .iter(&mut ecs)
|
// .iter(&mut ecs)
|
||||||
// .find(|e| e.name() == Some(sender));
|
// .find(|e| e.name() == Some(sender));
|
||||||
// let entity = bot.entity_by::<With<Player>>(|name: &Name| name == sender);
|
// let entity = bot.entity_by::<With<Player>>(|name: &Name| name == sender);
|
||||||
// let entity = bot.entity_by(|name: &Name| name == sender);
|
let entity = bot.entity_by::<With<Player>, (&GameProfileComponent,)>(
|
||||||
let entity = bot.entity_by::<With<Player>, (&Position,)>(|pos: &&Position| true);
|
|profile: &&GameProfileComponent| profile.name == sender,
|
||||||
|
);
|
||||||
if let Some(entity) = entity {
|
if let Some(entity) = entity {
|
||||||
// if m.content() == "goto" {
|
match m.content().as_str() {
|
||||||
// let target_pos_vec3 = entity.pos();
|
"goto" => {
|
||||||
// let target_pos: BlockPos = target_pos_vec3.into();
|
let entity_pos = bot.entity_components::<Position>(entity);
|
||||||
// bot.goto(BlockPosGoal::from(target_pos));
|
let target_pos: BlockPos = entity_pos.into();
|
||||||
// } else if m.content() == "look" {
|
bot.goto(BlockPosGoal::from(target_pos));
|
||||||
// let target_pos_vec3 = entity.pos();
|
}
|
||||||
// let target_pos: BlockPos = target_pos_vec3.into();
|
"look" => {
|
||||||
// println!("target_pos: {:?}", target_pos);
|
let entity_pos = bot.entity_components::<Position>(entity);
|
||||||
// bot.look_at(target_pos.center());
|
let target_pos: BlockPos = entity_pos.into();
|
||||||
// } else if m.content() == "jump" {
|
println!("target_pos: {:?}", target_pos);
|
||||||
// bot.set_jumping(true);
|
bot.look_at(target_pos.center());
|
||||||
// } else if m.content() == "walk" {
|
}
|
||||||
// bot.walk(WalkDirection::Forward);
|
"jump" => {
|
||||||
// } else if m.content() == "stop" {
|
bot.set_jumping(true);
|
||||||
// bot.set_jumping(false);
|
}
|
||||||
// bot.walk(WalkDirection::None);
|
"walk" => {
|
||||||
// } else if m.content() == "lag" {
|
bot.walk(WalkDirection::Forward);
|
||||||
// std::thread::sleep(Duration::from_millis(1000));
|
}
|
||||||
// }
|
"stop" => {
|
||||||
|
bot.set_jumping(false);
|
||||||
|
bot.walk(WalkDirection::None);
|
||||||
|
}
|
||||||
|
"lag" => {
|
||||||
|
std::thread::sleep(Duration::from_millis(1000));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Death(_) => {
|
Event::Death(_) => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue