mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
improve docs
This commit is contained in:
parent
a72b768397
commit
0d3a091c23
16 changed files with 122 additions and 91 deletions
|
@ -8,7 +8,8 @@ use uuid::Uuid;
|
||||||
|
|
||||||
/// Something that can join Minecraft servers.
|
/// Something that can join Minecraft servers.
|
||||||
///
|
///
|
||||||
/// To join a server using this account, use [`crate::Client::join`].
|
/// To join a server using this account, use [`Client::join`] or
|
||||||
|
/// [`azalea::ClientBuilder`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -21,6 +22,9 @@ use uuid::Uuid;
|
||||||
/// // or Account::offline("example");
|
/// // or Account::offline("example");
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`Client::join`]: crate::Client::join
|
||||||
|
/// [`azalea::ClientBuilder`]: https://docs.rs/azalea/latest/azalea/struct.ClientBuilder.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
/// The Minecraft username of the account.
|
/// The Minecraft username of the account.
|
||||||
|
|
|
@ -42,7 +42,7 @@ use azalea_protocol::{
|
||||||
},
|
},
|
||||||
resolver, ServerAddress,
|
resolver, ServerAddress,
|
||||||
};
|
};
|
||||||
use azalea_world::{EntityPlugin, Local, PartialWorld, World, WorldContainer};
|
use azalea_world::{entity::WorldName, EntityPlugin, Local, PartialWorld, World, WorldContainer};
|
||||||
use log::{debug, error};
|
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};
|
use std::{collections::HashMap, fmt::Debug, io, net::SocketAddr, sync::Arc};
|
||||||
|
@ -52,8 +52,13 @@ use uuid::Uuid;
|
||||||
|
|
||||||
pub type ClientInformation = ServerboundClientInformationPacket;
|
pub type ClientInformation = ServerboundClientInformationPacket;
|
||||||
|
|
||||||
/// 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.
|
||||||
/// Things that a player in the world will want to know are in [`LocalPlayer`].
|
/// Things that a player in the world will want to know are in [`LocalPlayer`].
|
||||||
|
///
|
||||||
|
/// To make a new client, use either [`azalea::ClientBuilder`] or
|
||||||
|
/// [`Client::join`].
|
||||||
|
///
|
||||||
|
/// [`azalea::ClientBuilder`]: https://docs.rs/azalea/latest/azalea/struct.ClientBuilder.html
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
/// The [`GameProfile`] for our client. This contains your username, UUID,
|
/// The [`GameProfile`] for our client. This contains your username, UUID,
|
||||||
|
@ -362,6 +367,17 @@ impl Client {
|
||||||
|
|
||||||
/// Get a component from this client. This will clone the component and
|
/// Get a component from this client. This will clone the component and
|
||||||
/// return it.
|
/// return it.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This will panic if the component doesn't exist on the client.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn example(client: &azalea::Client) {
|
||||||
|
/// let world_name = client.component::<WorldName>();
|
||||||
|
/// # }
|
||||||
pub fn component<T: Component + Clone>(&self) -> T {
|
pub fn component<T: Component + Clone>(&self) -> T {
|
||||||
self.query::<&T>(&mut self.ecs.lock()).clone()
|
self.query::<&T>(&mut self.ecs.lock()).clone()
|
||||||
}
|
}
|
||||||
|
@ -373,17 +389,8 @@ impl Client {
|
||||||
/// If the client using a shared world, then the shared world will be a
|
/// If the client using a shared world, then the shared world will be a
|
||||||
/// superset of the client's world.
|
/// superset of the client's world.
|
||||||
pub fn world(&self) -> Arc<RwLock<World>> {
|
pub fn world(&self) -> Arc<RwLock<World>> {
|
||||||
let mut ecs = self.ecs.lock();
|
let world_name = self.component::<WorldName>();
|
||||||
|
let ecs = self.ecs.lock();
|
||||||
let world_name = {
|
|
||||||
let local_player = self.local_player(&mut ecs);
|
|
||||||
local_player
|
|
||||||
.world_name
|
|
||||||
.as_ref()
|
|
||||||
.expect("World name must be known if we're doing Client::world")
|
|
||||||
.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let world_container = ecs.resource::<WorldContainer>();
|
let world_container = ecs.resource::<WorldContainer>();
|
||||||
world_container.get(&world_name).unwrap()
|
world_container.get(&world_name).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -391,7 +398,8 @@ impl Client {
|
||||||
/// Returns whether we have a received the login packet yet.
|
/// Returns whether we have a received the login packet yet.
|
||||||
pub fn logged_in(&self) -> bool {
|
pub fn logged_in(&self) -> bool {
|
||||||
// the login packet tells us the world name
|
// the login packet tells us the world name
|
||||||
self.local_player(&mut self.ecs.lock()).world_name.is_some()
|
self.query::<Option<&WorldName>>(&mut self.ecs.lock())
|
||||||
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tell the server we changed our game options (i.e. render distance, main
|
/// Tell the server we changed our game options (i.e. render distance, main
|
||||||
|
|
|
@ -12,6 +12,15 @@ use crate::Client;
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// A convenience function for getting components of our player's entity.
|
/// A convenience function for getting components of our player's entity.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # fn example(mut client: azalea_client::Client) {
|
||||||
|
/// let is_logged_in = client
|
||||||
|
/// .query::<Option<&WorldName>>(&mut client.ecs.lock())
|
||||||
|
/// .is_some();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn query<'w, Q: WorldQuery>(&self, ecs: &'w mut Ecs) -> <Q as WorldQuery>::Item<'w> {
|
pub fn query<'w, Q: WorldQuery>(&self, ecs: &'w mut Ecs) -> <Q as WorldQuery>::Item<'w> {
|
||||||
ecs.query::<Q>()
|
ecs.query::<Q>()
|
||||||
.get_mut(ecs, self.entity)
|
.get_mut(ecs, self.entity)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{collections::HashMap, io, sync::Arc};
|
use std::{collections::HashMap, io, sync::Arc};
|
||||||
|
|
||||||
use azalea_auth::game_profile::GameProfile;
|
use azalea_auth::game_profile::GameProfile;
|
||||||
use azalea_core::{ChunkPos, ResourceLocation};
|
use azalea_core::ChunkPos;
|
||||||
use azalea_ecs::component::Component;
|
use azalea_ecs::component::Component;
|
||||||
use azalea_ecs::entity::Entity;
|
use azalea_ecs::entity::Entity;
|
||||||
use azalea_ecs::{query::Added, system::Query};
|
use azalea_ecs::{query::Added, system::Query};
|
||||||
|
@ -21,22 +21,29 @@ use crate::{
|
||||||
ClientInformation, PlayerInfo, WalkDirection,
|
ClientInformation, PlayerInfo, WalkDirection,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A player that you control that is currently in a Minecraft server.
|
/// This is a component for our local player entities that are probably in a
|
||||||
|
/// world. If you have access to a [`Client`], you probably don't need to care
|
||||||
|
/// about this since `Client` gives you access to everything here.
|
||||||
|
///
|
||||||
|
/// You can also use the [`Local`] marker component for queries if you're only
|
||||||
|
/// checking for a local player and don't need the contents of this component.
|
||||||
|
///
|
||||||
|
/// [`Local`]: azalea_world::Local
|
||||||
|
/// [`Client`]: crate::Client
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct LocalPlayer {
|
pub struct LocalPlayer {
|
||||||
pub packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>,
|
packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>,
|
||||||
|
/// Some of the "settings" for this client that are sent to the server, such
|
||||||
|
/// as render distance.
|
||||||
pub client_information: ClientInformation,
|
pub client_information: ClientInformation,
|
||||||
/// A map of player uuids to their information in the tab list
|
/// A map of player UUIDs to their information in the tab list
|
||||||
pub players: HashMap<Uuid, PlayerInfo>,
|
pub players: HashMap<Uuid, PlayerInfo>,
|
||||||
|
|
||||||
/// The partial world is the world this client currently has loaded. It has
|
/// The partial world is the world this client currently has loaded. It has
|
||||||
/// a limited render distance.
|
/// a limited render distance.
|
||||||
pub partial_world: Arc<RwLock<PartialWorld>>,
|
pub partial_world: Arc<RwLock<PartialWorld>>,
|
||||||
/// The world is the combined [`PartialWorld`]s of all clients in the same
|
/// The world is the combined [`PartialWorld`]s of all clients in the same
|
||||||
/// world. (Only relevant if you're using a shared world, i.e. a swarm)
|
/// world. (Only relevant if you're using a shared world, i.e. a swarm)
|
||||||
pub world: Arc<RwLock<World>>,
|
pub world: Arc<RwLock<World>>,
|
||||||
pub world_name: Option<ResourceLocation>,
|
|
||||||
|
|
||||||
/// A list of async tasks that are running and will stop running when this
|
/// A list of async tasks that are running and will stop running when this
|
||||||
/// LocalPlayer is dropped or disconnected with [`Self::disconnect`]
|
/// LocalPlayer is dropped or disconnected with [`Self::disconnect`]
|
||||||
|
@ -93,13 +100,12 @@ impl LocalPlayer {
|
||||||
client_information.view_distance.into(),
|
client_information.view_distance.into(),
|
||||||
Some(entity),
|
Some(entity),
|
||||||
))),
|
))),
|
||||||
world_name: None,
|
|
||||||
|
|
||||||
tasks: Vec::new(),
|
tasks: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawn a task to write a packet directly to the server.
|
/// Write a packet directly to the server.
|
||||||
pub fn write_packet(&mut self, packet: ServerboundGamePacket) {
|
pub fn write_packet(&mut self, packet: ServerboundGamePacket) {
|
||||||
self.packet_writer
|
self.packet_writer
|
||||||
.send(packet)
|
.send(packet)
|
||||||
|
|
|
@ -333,6 +333,8 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An event sent when the client starts walking. This does not get sent for
|
||||||
|
/// non-local entities.
|
||||||
pub struct StartWalkEvent {
|
pub struct StartWalkEvent {
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
pub direction: WalkDirection,
|
pub direction: WalkDirection,
|
||||||
|
@ -354,6 +356,8 @@ pub fn walk_listener(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An event sent when the client starts sprinting. This does not get sent for
|
||||||
|
/// non-local entities.
|
||||||
pub struct StartSprintEvent {
|
pub struct StartSprintEvent {
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
pub direction: SprintDirection,
|
pub direction: SprintDirection,
|
||||||
|
|
|
@ -26,7 +26,7 @@ use azalea_world::{
|
||||||
entity::{
|
entity::{
|
||||||
metadata::{apply_metadata, Health, PlayerMetadataBundle},
|
metadata::{apply_metadata, Health, PlayerMetadataBundle},
|
||||||
set_rotation, Dead, EntityBundle, EntityKind, LastSentPosition, MinecraftEntityId, Physics,
|
set_rotation, Dead, EntityBundle, EntityKind, LastSentPosition, MinecraftEntityId, Physics,
|
||||||
PlayerBundle, Position,
|
PlayerBundle, Position, WorldName,
|
||||||
},
|
},
|
||||||
LoadedBy, PartialWorld, RelativeEntityUpdate, WorldContainer,
|
LoadedBy, PartialWorld, RelativeEntityUpdate, WorldContainer,
|
||||||
};
|
};
|
||||||
|
@ -128,11 +128,16 @@ fn handle_packets(ecs: &mut Ecs) {
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
let mut system_state: SystemState<(
|
let mut system_state: SystemState<(
|
||||||
Commands,
|
Commands,
|
||||||
Query<(&mut LocalPlayer, &GameProfileComponent)>,
|
Query<(
|
||||||
|
&mut LocalPlayer,
|
||||||
|
Option<&mut WorldName>,
|
||||||
|
&GameProfileComponent,
|
||||||
|
)>,
|
||||||
ResMut<WorldContainer>,
|
ResMut<WorldContainer>,
|
||||||
)> = SystemState::new(ecs);
|
)> = SystemState::new(ecs);
|
||||||
let (mut commands, mut query, mut world_container) = system_state.get_mut(ecs);
|
let (mut commands, mut query, mut world_container) = system_state.get_mut(ecs);
|
||||||
let (mut local_player, game_profile) = query.get_mut(player_entity).unwrap();
|
let (mut local_player, world_name, 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
|
||||||
|
@ -188,12 +193,19 @@ fn handle_packets(ecs: &mut Ecs) {
|
||||||
.as_int()
|
.as_int()
|
||||||
.expect("min_y tag is not an int");
|
.expect("min_y tag is not an int");
|
||||||
|
|
||||||
let world_name = p.dimension.clone();
|
let new_world_name = p.dimension.clone();
|
||||||
|
|
||||||
local_player.world_name = Some(world_name.clone());
|
if let Some(mut world_name) = world_name {
|
||||||
|
*world_name = world_name.clone();
|
||||||
|
} else {
|
||||||
|
commands
|
||||||
|
.entity(player_entity)
|
||||||
|
.insert(WorldName(new_world_name.clone()));
|
||||||
|
}
|
||||||
// add this world to the world_container (or don't if it's already
|
// add this world to the world_container (or don't if it's already
|
||||||
// there)
|
// there)
|
||||||
let weak_world = world_container.insert(world_name.clone(), height, min_y);
|
let weak_world =
|
||||||
|
world_container.insert(new_world_name.clone(), height, min_y);
|
||||||
// set the partial_world to an empty world
|
// set the partial_world to an empty world
|
||||||
// (when we add chunks or entities those will be in the
|
// (when we add chunks or entities those will be in the
|
||||||
// world_container)
|
// world_container)
|
||||||
|
@ -212,7 +224,7 @@ fn handle_packets(ecs: &mut Ecs) {
|
||||||
game_profile.uuid,
|
game_profile.uuid,
|
||||||
Vec3::default(),
|
Vec3::default(),
|
||||||
azalea_registry::EntityKind::Player,
|
azalea_registry::EntityKind::Player,
|
||||||
world_name,
|
new_world_name,
|
||||||
),
|
),
|
||||||
metadata: PlayerMetadataBundle::default(),
|
metadata: PlayerMetadataBundle::default(),
|
||||||
};
|
};
|
||||||
|
@ -506,12 +518,12 @@ fn handle_packets(ecs: &mut Ecs) {
|
||||||
ClientboundGamePacket::AddEntity(p) => {
|
ClientboundGamePacket::AddEntity(p) => {
|
||||||
debug!("Got add entity packet {:?}", p);
|
debug!("Got add entity packet {:?}", p);
|
||||||
|
|
||||||
let mut system_state: SystemState<(Commands, Query<&mut LocalPlayer>)> =
|
let mut system_state: SystemState<(Commands, Query<Option<&WorldName>>)> =
|
||||||
SystemState::new(ecs);
|
SystemState::new(ecs);
|
||||||
let (mut commands, mut query) = system_state.get_mut(ecs);
|
let (mut commands, mut query) = system_state.get_mut(ecs);
|
||||||
let local_player = query.get_mut(player_entity).unwrap();
|
let world_name = query.get_mut(player_entity).unwrap();
|
||||||
|
|
||||||
if let Some(world_name) = &local_player.world_name {
|
if let Some(WorldName(world_name)) = world_name {
|
||||||
let bundle = p.as_entity_bundle(world_name.clone());
|
let bundle = p.as_entity_bundle(world_name.clone());
|
||||||
let mut entity_commands = commands.spawn((
|
let mut entity_commands = commands.spawn((
|
||||||
MinecraftEntityId(p.id),
|
MinecraftEntityId(p.id),
|
||||||
|
@ -570,12 +582,14 @@ fn handle_packets(ecs: &mut Ecs) {
|
||||||
ClientboundGamePacket::AddPlayer(p) => {
|
ClientboundGamePacket::AddPlayer(p) => {
|
||||||
debug!("Got add player packet {:?}", p);
|
debug!("Got add player packet {:?}", p);
|
||||||
|
|
||||||
let mut system_state: SystemState<(Commands, Query<&mut LocalPlayer>)> =
|
let mut system_state: SystemState<(
|
||||||
SystemState::new(ecs);
|
Commands,
|
||||||
|
Query<(&mut LocalPlayer, Option<&WorldName>)>,
|
||||||
|
)> = SystemState::new(ecs);
|
||||||
let (mut commands, mut query) = system_state.get_mut(ecs);
|
let (mut commands, mut query) = system_state.get_mut(ecs);
|
||||||
let local_player = query.get_mut(player_entity).unwrap();
|
let (local_player, world_name) = query.get_mut(player_entity).unwrap();
|
||||||
|
|
||||||
if let Some(world_name) = &local_player.world_name {
|
if let Some(WorldName(world_name)) = world_name {
|
||||||
let bundle = p.as_player_bundle(world_name.clone());
|
let bundle = p.as_player_bundle(world_name.clone());
|
||||||
let mut spawned = commands.spawn((
|
let mut spawned = commands.spawn((
|
||||||
MinecraftEntityId(p.id),
|
MinecraftEntityId(p.id),
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Plugin for TaskPoolPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for configuring and creating the default task pools. For end-users
|
/// Helper for configuring and creating the default task pools. For end-users
|
||||||
/// who want full control, set up [`TaskPoolPlugin`](super::TaskPoolPlugin)
|
/// who want full control, set up [`TaskPoolPlugin`](TaskPoolPlugin)
|
||||||
#[derive(Clone, Resource)]
|
#[derive(Clone, Resource)]
|
||||||
pub struct TaskPoolOptions {
|
pub struct TaskPoolOptions {
|
||||||
/// If the number of physical cores is less than min_total_threads, force
|
/// If the number of physical cores is less than min_total_threads, force
|
||||||
|
|
|
@ -109,6 +109,8 @@ macro_rules! vec3_impl {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to represent an exact position in the world where an entity could be.
|
||||||
|
/// For blocks, [`BlockPos`] is used instead.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, McBuf)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, McBuf)]
|
||||||
pub struct Vec3 {
|
pub struct Vec3 {
|
||||||
pub x: f64,
|
pub x: f64,
|
||||||
|
@ -117,6 +119,8 @@ pub struct Vec3 {
|
||||||
}
|
}
|
||||||
vec3_impl!(Vec3, f64);
|
vec3_impl!(Vec3, f64);
|
||||||
|
|
||||||
|
/// The coordinates of a block in the world. For entities (if the coordinate
|
||||||
|
/// with decimals), use [`Vec3`] instead.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||||
pub struct BlockPos {
|
pub struct BlockPos {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
|
@ -137,6 +141,8 @@ impl BlockPos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Chunk coordinates are used to represent where a chunk is in the world. You
|
||||||
|
/// can convert the x and z to block coordinates by multiplying them by 16.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||||
pub struct ChunkPos {
|
pub struct ChunkPos {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
//! Re-export important parts of `bevy_ecs` and `bevy_app` and make them more
|
//! Re-export important parts of [`bevy_ecs`] and [`bevy_app`] and make them
|
||||||
//! compatible with Azalea.
|
//! more compatible with Azalea.
|
||||||
//!
|
//!
|
||||||
//! This is completely compatible with `bevy_ecs`, so it won't cause issues if
|
//! This is completely compatible with `bevy_ecs`, so it won't cause issues if
|
||||||
//! you use plugins meant for Bevy.
|
//! you use plugins meant for Bevy.
|
||||||
//!
|
//!
|
||||||
//! Changes:
|
//! Changes:
|
||||||
//! - Add [`TickPlugin`], [`TickStage`] and [`AppTickExt`]
|
//! - Add [`TickPlugin`], [`TickStage`] and [`AppTickExt`] (which adds
|
||||||
|
//! `app.add_tick_system` and `app.add_tick_system_set`).
|
||||||
//! - Change the macros to use azalea/azalea_ecs instead of bevy/bevy_ecs
|
//! - Change the macros to use azalea/azalea_ecs instead of bevy/bevy_ecs
|
||||||
//! - Rename bevy_ecs::world::World to azalea_ecs::ecs::Ecs
|
//! - Rename `world::World` to [`ecs::Ecs`]
|
||||||
//! - Re-export `bevy_app` in the `app` module.
|
//! - Re-export `bevy_app` in the [`app`] module.
|
||||||
|
//!
|
||||||
|
//! [`bevy_ecs`]: https://docs.rs/bevy_ecs
|
||||||
|
//! [`bevy_app`]: https://docs.rs/bevy_app
|
||||||
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! <https://minecraft.fandom.com/wiki/Attribute>
|
//! See <https://minecraft.fandom.com/wiki/Attribute>.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
|
|
@ -103,6 +103,7 @@ impl McBufWritable for OptionalUnsignedInt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A set of x, y, and z rotations. This is used for armor stands.
|
||||||
#[derive(Clone, Debug, McBuf, Default)]
|
#[derive(Clone, Debug, McBuf, Default)]
|
||||||
pub struct Rotations {
|
pub struct Rotations {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
|
|
|
@ -172,7 +172,7 @@ impl From<&LastSentPosition> for BlockPos {
|
||||||
/// The name of the world the entity is in. If two entities share the same world
|
/// The name of the world the entity is in. If two entities share the same world
|
||||||
/// name, we assume they're in the same world.
|
/// name, we assume they're in the same world.
|
||||||
#[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)]
|
#[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)]
|
||||||
pub struct WorldName(ResourceLocation);
|
pub struct WorldName(pub ResourceLocation);
|
||||||
|
|
||||||
/// A component for entities that can jump.
|
/// A component for entities that can jump.
|
||||||
///
|
///
|
||||||
|
|
|
@ -324,34 +324,3 @@ impl Debug for EntityInfos {
|
||||||
f.debug_struct("EntityInfos").finish()
|
f.debug_struct("EntityInfos").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(test)]
|
|
||||||
// mod tests {
|
|
||||||
// use crate::entity::metadata;
|
|
||||||
|
|
||||||
// use super::*;
|
|
||||||
// use azalea_core::Vec3;
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn test_store_entity() {
|
|
||||||
// let mut storage = PartialEntityInfos::default();
|
|
||||||
// assert!(storage.limited_get_by_id(0).is_none());
|
|
||||||
// assert!(storage.shared.read().get_by_id(0).is_none());
|
|
||||||
|
|
||||||
// let uuid = Uuid::from_u128(100);
|
|
||||||
// storage.insert(
|
|
||||||
// 0,
|
|
||||||
// EntityData::new(
|
|
||||||
// uuid,
|
|
||||||
// Vec3::default(),
|
|
||||||
// EntityMetadata::Player(metadata::Player::default()),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// assert_eq!(storage.limited_get_by_id(0).unwrap().uuid, uuid);
|
|
||||||
// assert_eq!(storage.shared.read().get_by_id(0).unwrap().uuid, uuid);
|
|
||||||
|
|
||||||
// storage.remove_by_id(0);
|
|
||||||
// assert!(storage.limited_get_by_id(0).is_none());
|
|
||||||
// assert!(storage.shared.read().get_by_id(0).is_none());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ opt-level = 3
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
A bot that logs chat messages sent in the server to the console.
|
//! A bot that logs chat messages sent in the server to the console.
|
||||||
|
|
||||||
use azalea::prelude::*;
|
use azalea::prelude::*;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
@ -48,15 +48,13 @@ async fn main() {
|
||||||
let account = Account::offline("bot");
|
let account = Account::offline("bot");
|
||||||
// or Account::microsoft("example@example.com").await.unwrap();
|
// or Account::microsoft("example@example.com").await.unwrap();
|
||||||
|
|
||||||
azalea::start(azalea::Options {
|
loop {
|
||||||
account,
|
let e = azalea::ClientBuilder::new()
|
||||||
address: "localhost",
|
.set_handler(handle)
|
||||||
state: State::default(),
|
.start(account, "localhost")
|
||||||
plugins: plugins![],
|
.await;
|
||||||
handle,
|
eprintln!("{:?}", e);
|
||||||
})
|
}
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Component)]
|
#[derive(Default, Clone, Component)]
|
||||||
|
@ -76,10 +74,10 @@ async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
|
||||||
|
|
||||||
# Plugins
|
# Plugins
|
||||||
|
|
||||||
Azalea uses [Bevy ECS](https://docs.rs/bevy_ecs) internally to store information about the world and clients. Bevy plugins are more powerful than async handler functions, but more difficult to use. See [pathfinder](azalea/src/pathfinder/mod.rs) as an example of how to make a plugin. You can then use a plugin by adding `.add_plugin(ExamplePlugin)` in the client or swarm builder.
|
Azalea uses [Bevy ECS](https://docs.rs/bevy_ecs) internally to store information about the world and clients. Bevy plugins are more powerful than async handler functions, but more difficult to use. See [pathfinder](azalea/src/pathfinder/mod.rs) as an example of how to make a plugin. You can then enable a plugin by adding `.add_plugin(ExamplePlugin)` in your client/swarm builder.
|
||||||
|
|
||||||
Also note that just because something is an entity in the ECS doesn't mean that it's a Minecraft entity. You can filter for that by having `With<MinecraftEntityId>` as a filter.
|
Also note that just because something is an entity in the ECS doesn't mean that it's a Minecraft entity. You can filter for that by having `With<MinecraftEntityId>` as a filter.
|
||||||
|
|
||||||
See the [https://bevy-cheatbook.github.io/programming/ecs-intro.html](Bevy Cheatbook) to learn more about Bevy ECS (and ECS in general).
|
See the [Bevy Cheatbook](https://bevy-cheatbook.github.io/programming/ecs-intro.html) to learn more about Bevy ECS (and the ECS paradigm in general).
|
||||||
|
|
||||||
[`azalea_client`]: https://docs.rs/azalea-client
|
[`azalea_client`]: https://docs.rs/azalea-client
|
|
@ -6,7 +6,6 @@ use azalea::ecs::query::With;
|
||||||
use azalea::entity::metadata::Player;
|
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::{prelude::*, BlockPos, GameProfileComponent, 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;
|
||||||
|
@ -66,7 +65,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
// .set_handler(handle)
|
// .set_handler(handle)
|
||||||
// .start(Account::offline("bot"), "localhost")
|
// .start(Account::offline("bot"), "localhost")
|
||||||
// .await;
|
// .await;
|
||||||
println!("{e:?}");
|
eprintln!("{e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,15 @@ pub enum StartError {
|
||||||
Join(#[from] azalea_client::JoinError),
|
Join(#[from] azalea_client::JoinError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A builder for creating new [`Client`]s. This is the recommended way of
|
||||||
|
/// making Azalea bots.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// azalea::ClientBuilder::new()
|
||||||
|
/// .set_handler(handle)
|
||||||
|
/// .start(Account::offline("bot"), "localhost")
|
||||||
|
/// .await;
|
||||||
|
/// ```
|
||||||
pub struct ClientBuilder<S, Fut>
|
pub struct ClientBuilder<S, Fut>
|
||||||
where
|
where
|
||||||
S: Default + Send + Sync + Clone + 'static,
|
S: Default + Send + Sync + Clone + 'static,
|
||||||
|
|
Loading…
Add table
Reference in a new issue