mirror of
https://github.com/mat-1/azalea.git
synced 2024-09-20 07:02:31 +00:00
Merge branch 'main' of https://github.com/mat-1/azalea into main
This commit is contained in:
commit
ca00dbab12
44 changed files with 258 additions and 163 deletions
|
@ -1,5 +1,4 @@
|
||||||
//! Tell Mojang you're joining a multiplayer server.
|
//! Tell Mojang you're joining a multiplayer server.
|
||||||
//!
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
|
@ -324,7 +324,8 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
let mut properties_with_name: Vec<PropertyWithNameAndDefault> =
|
let mut properties_with_name: Vec<PropertyWithNameAndDefault> =
|
||||||
Vec::with_capacity(block.properties_and_defaults.len());
|
Vec::with_capacity(block.properties_and_defaults.len());
|
||||||
// Used to determine the index of the property so we can optionally add a number to it
|
// Used to determine the index of the property so we can optionally add a number
|
||||||
|
// to it
|
||||||
let mut previous_names: Vec<String> = Vec::new();
|
let mut previous_names: Vec<String> = Vec::new();
|
||||||
for property in &block.properties_and_defaults {
|
for property in &block.properties_and_defaults {
|
||||||
let index: Option<usize> = if block
|
let index: Option<usize> = if block
|
||||||
|
@ -343,10 +344,12 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
// ```ignore
|
||||||
// let mut property_name = property_struct_names_to_names
|
// let mut property_name = property_struct_names_to_names
|
||||||
// .get(&property.property_type.to_string())
|
// .get(&property.property_type.to_string())
|
||||||
// .unwrap_or_else(|| panic!("Property '{}' is bad", property.property_type))
|
// .unwrap_or_else(|| panic!("Property '{}' is bad", property.property_type))
|
||||||
// .clone();
|
// .clone();
|
||||||
|
// ```
|
||||||
let mut property_name = property_struct_names_to_names
|
let mut property_name = property_struct_names_to_names
|
||||||
.get(&property.name.to_string())
|
.get(&property.name.to_string())
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|
|
@ -260,7 +260,8 @@ impl<S> CommandDispatcher<S> {
|
||||||
// consumer.on_command_complete(context, true, value);
|
// consumer.on_command_complete(context, true, value);
|
||||||
successful_forks += 1;
|
successful_forks += 1;
|
||||||
|
|
||||||
// TODO: allow context_command to error and handle those errors
|
// TODO: allow context_command to error and handle those
|
||||||
|
// errors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,14 +45,16 @@ impl<S> Clone for CommandNode<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> CommandNode<S> {
|
impl<S> CommandNode<S> {
|
||||||
/// Gets the literal, or panics. You should use match if you're not certain about the type.
|
/// Gets the literal, or panics. You should use match if you're not certain
|
||||||
|
/// about the type.
|
||||||
pub fn literal(&self) -> &Literal {
|
pub fn literal(&self) -> &Literal {
|
||||||
match self.value {
|
match self.value {
|
||||||
ArgumentBuilderType::Literal(ref literal) => literal,
|
ArgumentBuilderType::Literal(ref literal) => literal,
|
||||||
_ => panic!("CommandNode::literal() called on non-literal node"),
|
_ => panic!("CommandNode::literal() called on non-literal node"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Gets the argument, or panics. You should use match if you're not certain about the type.
|
/// Gets the argument, or panics. You should use match if you're not certain
|
||||||
|
/// about the type.
|
||||||
pub fn argument(&self) -> &Argument {
|
pub fn argument(&self) -> &Argument {
|
||||||
match self.value {
|
match self.value {
|
||||||
ArgumentBuilderType::Argument(ref argument) => argument,
|
ArgumentBuilderType::Argument(ref argument) => argument,
|
||||||
|
|
|
@ -92,7 +92,8 @@ fn read_utf_with_len(buf: &mut Cursor<&[u8]>, max_length: u32) -> Result<String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// fast varints modified from https://github.com/luojia65/mc-varint/blob/master/src/lib.rs#L67
|
// fast varints modified from https://github.com/luojia65/mc-varint/blob/master/src/lib.rs#L67
|
||||||
/// Read a single varint from the reader and return the value, along with the number of bytes read
|
/// Read a single varint from the reader and return the value, along with the
|
||||||
|
/// number of bytes read
|
||||||
// pub async fn read_varint_async(
|
// pub async fn read_varint_async(
|
||||||
// reader: &mut (dyn AsyncRead + Unpin + Send),
|
// reader: &mut (dyn AsyncRead + Unpin + Send),
|
||||||
// ) -> Result<i32, BufReadError> {
|
// ) -> Result<i32, BufReadError> {
|
||||||
|
|
|
@ -61,8 +61,8 @@ impl Component {
|
||||||
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code), so you
|
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code), so you
|
||||||
/// can print it to your terminal and get styling.
|
/// can print it to your terminal and get styling.
|
||||||
///
|
///
|
||||||
/// This is technically a shortcut for [`Component::to_ansi_custom_style`] with a
|
/// This is technically a shortcut for [`Component::to_ansi_custom_style`]
|
||||||
/// default [`Style`] colored white.
|
/// with a default [`Style`] colored white.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -166,8 +166,9 @@ impl<'de> Deserialize<'de> for Component {
|
||||||
.ok_or_else(|| de::Error::custom("\"with\" must be an array"))?;
|
.ok_or_else(|| de::Error::custom("\"with\" must be an array"))?;
|
||||||
let mut with_array = Vec::with_capacity(with.len());
|
let mut with_array = Vec::with_capacity(with.len());
|
||||||
for item in with {
|
for item in with {
|
||||||
// if it's a string component with no styling and no siblings, just add a string to with_array
|
// if it's a string component with no styling and no siblings, just add a
|
||||||
// otherwise add the component to the array
|
// string to with_array otherwise add the component
|
||||||
|
// to the array
|
||||||
let c = Component::deserialize(item).map_err(de::Error::custom)?;
|
let c = Component::deserialize(item).map_err(de::Error::custom)?;
|
||||||
if let Component::Text(text_component) = c {
|
if let Component::Text(text_component) = c {
|
||||||
if text_component.base.siblings.is_empty()
|
if text_component.base.siblings.is_empty()
|
||||||
|
@ -253,7 +254,8 @@ impl<'de> Deserialize<'de> for Component {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let json_array = json.as_array().unwrap();
|
let json_array = json.as_array().unwrap();
|
||||||
// the first item in the array is the one that we're gonna return, the others are siblings
|
// the first item in the array is the one that we're gonna return, the others
|
||||||
|
// are siblings
|
||||||
let mut component = Component::deserialize(&json_array[0]).map_err(de::Error::custom)?;
|
let mut component = Component::deserialize(&json_array[0]).map_err(de::Error::custom)?;
|
||||||
for i in 1..json_array.len() {
|
for i in 1..json_array.len() {
|
||||||
component.append(
|
component.append(
|
||||||
|
|
|
@ -435,7 +435,8 @@ impl Style {
|
||||||
if !before.underlined.unwrap_or(false) && after.underlined.unwrap_or(false) {
|
if !before.underlined.unwrap_or(false) && after.underlined.unwrap_or(false) {
|
||||||
ansi_codes.push_str(Ansi::UNDERLINED);
|
ansi_codes.push_str(Ansi::UNDERLINED);
|
||||||
}
|
}
|
||||||
// if strikethrough used to be false/default and now it's true, set strikethrough
|
// if strikethrough used to be false/default and now it's true, set
|
||||||
|
// strikethrough
|
||||||
if !before.strikethrough.unwrap_or(false) && after.strikethrough.unwrap_or(false) {
|
if !before.strikethrough.unwrap_or(false) && after.strikethrough.unwrap_or(false) {
|
||||||
ansi_codes.push_str(Ansi::STRIKETHROUGH);
|
ansi_codes.push_str(Ansi::STRIKETHROUGH);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,16 @@ impl Serialize for TextComponent {
|
||||||
const LEGACY_FORMATTING_CODE_SYMBOL: char = '§';
|
const LEGACY_FORMATTING_CODE_SYMBOL: char = '§';
|
||||||
|
|
||||||
/// Convert a legacy color code string into a Component
|
/// Convert a legacy color code string into a Component
|
||||||
/// Technically in Minecraft this is done when displaying the text, but AFAIK it's the same as just doing it in TextComponent
|
/// Technically in Minecraft this is done when displaying the text, but AFAIK
|
||||||
|
/// it's the same as just doing it in TextComponent
|
||||||
pub fn legacy_color_code_to_text_component(legacy_color_code: &str) -> TextComponent {
|
pub fn legacy_color_code_to_text_component(legacy_color_code: &str) -> TextComponent {
|
||||||
let mut components: Vec<TextComponent> = Vec::with_capacity(1);
|
let mut components: Vec<TextComponent> = Vec::with_capacity(1);
|
||||||
// iterate over legacy_color_code, if it starts with LEGACY_COLOR_CODE_SYMBOL then read the next character and get the style from that
|
// iterate over legacy_color_code, if it starts with LEGACY_COLOR_CODE_SYMBOL
|
||||||
// otherwise, add the character to the text
|
// then read the next character and get the style from that otherwise, add
|
||||||
|
// the character to the text
|
||||||
|
|
||||||
// we don't use a normal for loop since we need to be able to skip after reading the formatter code symbol
|
// we don't use a normal for loop since we need to be able to skip after reading
|
||||||
|
// the formatter code symbol
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < legacy_color_code.chars().count() {
|
while i < legacy_color_code.chars().count() {
|
||||||
if legacy_color_code.chars().nth(i).unwrap() == LEGACY_FORMATTING_CODE_SYMBOL {
|
if legacy_color_code.chars().nth(i).unwrap() == LEGACY_FORMATTING_CODE_SYMBOL {
|
||||||
|
@ -72,7 +75,8 @@ pub fn legacy_color_code_to_text_component(legacy_color_code: &str) -> TextCompo
|
||||||
return TextComponent::new("".to_string());
|
return TextComponent::new("".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the final component by using the first one as the base, and then adding the rest as siblings
|
// create the final component by using the first one as the base, and then
|
||||||
|
// adding the rest as siblings
|
||||||
let mut final_component = components.remove(0);
|
let mut final_component = components.remove(0);
|
||||||
for component in components {
|
for component in components {
|
||||||
final_component.base.siblings.push(component.get());
|
final_component.base.siblings.push(component.get());
|
||||||
|
|
|
@ -104,7 +104,8 @@ impl Account {
|
||||||
AuthOpts::Microsoft { email } => {
|
AuthOpts::Microsoft { email } => {
|
||||||
let new_account = Account::microsoft(email).await?;
|
let new_account = Account::microsoft(email).await?;
|
||||||
let access_token = self
|
let access_token = self
|
||||||
.access_token.as_ref()
|
.access_token
|
||||||
|
.as_ref()
|
||||||
.expect("Access token should always be set for Microsoft accounts");
|
.expect("Access token should always be set for Microsoft accounts");
|
||||||
let new_access_token = new_account
|
let new_access_token = new_account
|
||||||
.access_token
|
.access_token
|
||||||
|
|
|
@ -112,7 +112,8 @@ pub struct Client {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PhysicsState {
|
pub struct PhysicsState {
|
||||||
/// Minecraft only sends a movement packet either after 20 ticks or if the player moved enough. This is that tick counter.
|
/// Minecraft only sends a movement packet either after 20 ticks or if the
|
||||||
|
/// player moved enough. This is that tick counter.
|
||||||
pub position_remainder: u32,
|
pub position_remainder: u32,
|
||||||
pub was_sprinting: bool,
|
pub was_sprinting: bool,
|
||||||
// Whether we're going to try to start sprinting this tick. Equivalent to
|
// Whether we're going to try to start sprinting this tick. Equivalent to
|
||||||
|
@ -383,8 +384,8 @@ impl Client {
|
||||||
/// Start the protocol and game tick loop.
|
/// Start the protocol and game tick loop.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn start_tasks(&self, tx: Sender<Event>) {
|
pub fn start_tasks(&self, tx: Sender<Event>) {
|
||||||
// if you get an error right here that means you're doing something with locks wrong
|
// if you get an error right here that means you're doing something with locks
|
||||||
// read the error to see where the issue is
|
// wrong read the error to see where the issue is
|
||||||
// you might be able to just drop the lock or put it in its own scope to fix
|
// you might be able to just drop the lock or put it in its own scope to fix
|
||||||
|
|
||||||
let mut tasks = self.tasks.lock();
|
let mut tasks = self.tasks.lock();
|
||||||
|
@ -789,7 +790,8 @@ impl Client {
|
||||||
if let Some(mut entity) = world.entity_mut(p.id) {
|
if let Some(mut entity) = world.entity_mut(p.id) {
|
||||||
entity.apply_metadata(&p.packed_items.0);
|
entity.apply_metadata(&p.packed_items.0);
|
||||||
} else {
|
} else {
|
||||||
// warn!("Server sent an entity data packet for an entity id ({}) that we don't know about", p.id);
|
// warn!("Server sent an entity data packet for an entity id
|
||||||
|
// ({}) that we don't know about", p.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClientboundGamePacket::UpdateAttributes(_p) => {
|
ClientboundGamePacket::UpdateAttributes(_p) => {
|
||||||
|
@ -1041,7 +1043,8 @@ impl Client {
|
||||||
/// of the client's world.
|
/// of the client's world.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if the client has not received the login packet yet. You can check this with [`Client::logged_in`].
|
/// Panics if the client has not received the login packet yet. You can
|
||||||
|
/// check this with [`Client::logged_in`].
|
||||||
pub fn world(&self) -> Arc<WeakWorld> {
|
pub fn world(&self) -> Arc<WeakWorld> {
|
||||||
let world_name = self.world_name.read();
|
let world_name = self.world_name.read();
|
||||||
let world_name = world_name
|
let world_name = world_name
|
||||||
|
@ -1086,8 +1089,9 @@ impl Client {
|
||||||
self.world_name.read().is_some()
|
self.world_name.read().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tell the server we changed our game options (i.e. render distance, main hand).
|
/// Tell the server we changed our game options (i.e. render distance, main
|
||||||
/// If this is not set before the login packet, the default will be sent.
|
/// hand). If this is not set before the login packet, the default will
|
||||||
|
/// be sent.
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use azalea_client::{Client, ClientInformation};
|
/// # use azalea_client::{Client, ClientInformation};
|
||||||
|
|
|
@ -37,8 +37,8 @@ impl Client {
|
||||||
pub(crate) async fn send_position(&mut self) -> Result<(), MovePlayerError> {
|
pub(crate) async fn send_position(&mut self) -> Result<(), MovePlayerError> {
|
||||||
let packet = {
|
let packet = {
|
||||||
self.send_sprinting_if_needed().await?;
|
self.send_sprinting_if_needed().await?;
|
||||||
// TODO: the camera being able to be controlled by other entities isn't implemented yet
|
// TODO: the camera being able to be controlled by other entities isn't
|
||||||
// if !self.is_controlled_camera() { return };
|
// implemented yet if !self.is_controlled_camera() { return };
|
||||||
|
|
||||||
let mut physics_state = self.physics_state.lock();
|
let mut physics_state = self.physics_state.lock();
|
||||||
|
|
||||||
|
@ -54,7 +54,8 @@ impl Client {
|
||||||
|
|
||||||
physics_state.position_remainder += 1;
|
physics_state.position_remainder += 1;
|
||||||
|
|
||||||
// boolean sendingPosition = Mth.lengthSquared(xDelta, yDelta, zDelta) > Mth.square(2.0E-4D) || this.positionReminder >= 20;
|
// boolean sendingPosition = Mth.lengthSquared(xDelta, yDelta, zDelta) >
|
||||||
|
// Mth.square(2.0E-4D) || this.positionReminder >= 20;
|
||||||
let sending_position = ((x_delta.powi(2) + y_delta.powi(2) + z_delta.powi(2))
|
let sending_position = ((x_delta.powi(2) + y_delta.powi(2) + z_delta.powi(2))
|
||||||
> 2.0e-4f64.powi(2))
|
> 2.0e-4f64.powi(2))
|
||||||
|| physics_state.position_remainder >= 20;
|
|| physics_state.position_remainder >= 20;
|
||||||
|
@ -155,7 +156,8 @@ impl Client {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set our current position to the provided Vec3, potentially clipping through blocks.
|
// Set our current position to the provided Vec3, potentially clipping through
|
||||||
|
// blocks.
|
||||||
pub async fn set_position(&mut self, new_pos: Vec3) -> Result<(), MovePlayerError> {
|
pub async fn set_position(&mut self, new_pos: Vec3) -> Result<(), MovePlayerError> {
|
||||||
let player_entity_id = *self.entity_id.read();
|
let player_entity_id = *self.entity_id.read();
|
||||||
let mut world_lock = self.world.write();
|
let mut world_lock = self.world.write();
|
||||||
|
@ -198,7 +200,8 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: food data and abilities
|
// TODO: food data and abilities
|
||||||
// let has_enough_food_to_sprint = self.food_data().food_level || self.abilities().may_fly;
|
// let has_enough_food_to_sprint = self.food_data().food_level ||
|
||||||
|
// self.abilities().may_fly;
|
||||||
let has_enough_food_to_sprint = true;
|
let has_enough_food_to_sprint = true;
|
||||||
|
|
||||||
// TODO: double tapping w to sprint i think
|
// TODO: double tapping w to sprint i think
|
||||||
|
@ -223,7 +226,8 @@ impl Client {
|
||||||
player_entity.ai_step();
|
player_entity.ai_step();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the impulse from self.move_direction. The multipler is used for sneaking.
|
/// Update the impulse from self.move_direction. The multipler is used for
|
||||||
|
/// sneaking.
|
||||||
pub(crate) fn tick_controls(&mut self, multiplier: Option<f32>) {
|
pub(crate) fn tick_controls(&mut self, multiplier: Option<f32>) {
|
||||||
let mut physics_state = self.physics_state.lock();
|
let mut physics_state = self.physics_state.lock();
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,8 @@ impl BitSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the maximum potential items in the BitSet. This will be divisible by 64.
|
/// Returns the maximum potential items in the BitSet. This will be
|
||||||
|
/// divisible by 64.
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.data.len() * 64
|
self.data.len() * 64
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,8 @@ impl GameType {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn short_name(&self) -> &'static str {
|
pub fn short_name(&self) -> &'static str {
|
||||||
// TODO: these should be translated TranslatableComponent("selectWorld.gameMode." + string2)
|
// TODO: these should be translated
|
||||||
|
// TranslatableComponent("selectWorld.gameMode." + string2)
|
||||||
match self {
|
match self {
|
||||||
GameType::Survival => "Survival",
|
GameType::Survival => "Survival",
|
||||||
GameType::Creative => "Creative",
|
GameType::Creative => "Creative",
|
||||||
|
@ -59,7 +60,8 @@ impl GameType {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn long_name(&self) -> &'static str {
|
pub fn long_name(&self) -> &'static str {
|
||||||
// TODO: These should be translated TranslatableComponent("gameMode." + string2);
|
// TODO: These should be translated TranslatableComponent("gameMode." +
|
||||||
|
// string2);
|
||||||
match self {
|
match self {
|
||||||
GameType::Survival => "Survival Mode",
|
GameType::Survival => "Survival Mode",
|
||||||
GameType::Creative => "Creative Mode",
|
GameType::Creative => "Creative Mode",
|
||||||
|
@ -92,7 +94,8 @@ impl McBufWritable for GameType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rust doesn't let us `impl McBufReadable for Option<GameType>` so we have to make a new type :(
|
/// Rust doesn't let us `impl McBufReadable for Option<GameType>` so we have to
|
||||||
|
/// make a new type :(
|
||||||
#[derive(Hash, Copy, Clone, Debug)]
|
#[derive(Hash, Copy, Clone, Debug)]
|
||||||
pub struct OptionalGameType(Option<GameType>);
|
pub struct OptionalGameType(Option<GameType>);
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,8 @@ pub struct BlockPos {
|
||||||
vec3_impl!(BlockPos, i32);
|
vec3_impl!(BlockPos, i32);
|
||||||
|
|
||||||
impl BlockPos {
|
impl BlockPos {
|
||||||
/// Get the absolute center of a block position by adding 0.5 to each coordinate.
|
/// Get the absolute center of a block position by adding 0.5 to each
|
||||||
|
/// coordinate.
|
||||||
pub fn center(&self) -> Vec3 {
|
pub fn center(&self) -> Vec3 {
|
||||||
Vec3 {
|
Vec3 {
|
||||||
x: self.x as f64 + 0.5,
|
x: self.x as f64 + 0.5,
|
||||||
|
@ -176,7 +177,8 @@ impl ChunkBlockPos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The coordinates of a block inside a chunk section. Each coordinate must be in the range [0, 15].
|
/// The coordinates of a block inside a chunk section. Each coordinate must be
|
||||||
|
/// in the range [0, 15].
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct ChunkSectionBlockPos {
|
pub struct ChunkSectionBlockPos {
|
||||||
pub x: u8,
|
pub x: u8,
|
||||||
|
|
|
@ -45,7 +45,8 @@ pub fn encrypt(public_key: &[u8], nonce: &[u8]) -> Result<EncryptResult, String>
|
||||||
// generate a random 16-byte shared secret, to be used with the AES/CFB8
|
// generate a random 16-byte shared secret, to be used with the AES/CFB8
|
||||||
// stream cipher.
|
// stream cipher.
|
||||||
let secret_key = generate_secret_key();
|
let secret_key = generate_secret_key();
|
||||||
// let hash = hex_digest(&digest_data(server_id.as_bytes(), public_key, &secret_key));
|
// let hash = hex_digest(&digest_data(server_id.as_bytes(), public_key,
|
||||||
|
// &secret_key));
|
||||||
|
|
||||||
// this.keybytes = Crypt.encryptUsingKey(publicKey, secretKey.getEncoded());
|
// this.keybytes = Crypt.encryptUsingKey(publicKey, secretKey.getEncoded());
|
||||||
// this.nonce = Crypt.encryptUsingKey(publicKey, arrby);
|
// this.nonce = Crypt.encryptUsingKey(publicKey, arrby);
|
||||||
|
|
|
@ -18,8 +18,8 @@ use std::{collections::HashMap, fs::File};
|
||||||
// let mut file = File::open("en_us.json").unwrap();
|
// let mut file = File::open("en_us.json").unwrap();
|
||||||
// let mut contents = String::new();
|
// let mut contents = String::new();
|
||||||
// file.read_to_string(&mut contents).unwrap();
|
// file.read_to_string(&mut contents).unwrap();
|
||||||
// let en_us: HashMap<String, String> = serde_json::from_str(&contents).unwrap();
|
// let en_us: HashMap<String, String> =
|
||||||
// Language { storage: en_us }
|
// serde_json::from_str(&contents).unwrap(); Language { storage: en_us }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// pub fn get(&self, key: &str) -> Option<&str> {
|
// pub fn get(&self, key: &str) -> Option<&str> {
|
||||||
|
|
|
@ -36,25 +36,29 @@ pub trait MovableEntity {
|
||||||
impl HasCollision for World {
|
impl HasCollision for World {
|
||||||
// private Vec3 collide(Vec3 var1) {
|
// private Vec3 collide(Vec3 var1) {
|
||||||
// AABB var2 = this.getBoundingBox();
|
// AABB var2 = this.getBoundingBox();
|
||||||
// List var3 = this.level.getEntityCollisions(this, var2.expandTowards(var1));
|
// List var3 = this.level.getEntityCollisions(this,
|
||||||
// Vec3 var4 = var1.lengthSqr() == 0.0D ? var1 : collideBoundingBox(this, var1, var2, this.level, var3);
|
// var2.expandTowards(var1)); Vec3 var4 = var1.lengthSqr() == 0.0D ?
|
||||||
|
// var1 : collideBoundingBox(this, var1, var2, this.level, var3);
|
||||||
// boolean var5 = var1.x != var4.x;
|
// boolean var5 = var1.x != var4.x;
|
||||||
// boolean var6 = var1.y != var4.y;
|
// boolean var6 = var1.y != var4.y;
|
||||||
// boolean var7 = var1.z != var4.z;
|
// boolean var7 = var1.z != var4.z;
|
||||||
// boolean var8 = this.onGround || var6 && var1.y < 0.0D;
|
// boolean var8 = this.onGround || var6 && var1.y < 0.0D;
|
||||||
// if (this.maxUpStep > 0.0F && var8 && (var5 || var7)) {
|
// if (this.maxUpStep > 0.0F && var8 && (var5 || var7)) {
|
||||||
// Vec3 var9 = collideBoundingBox(this, new Vec3(var1.x, (double)this.maxUpStep, var1.z), var2, this.level, var3);
|
// Vec3 var9 = collideBoundingBox(this, new Vec3(var1.x,
|
||||||
// Vec3 var10 = collideBoundingBox(this, new Vec3(0.0D, (double)this.maxUpStep, 0.0D), var2.expandTowards(var1.x, 0.0D, var1.z), this.level, var3);
|
// (double)this.maxUpStep, var1.z), var2, this.level, var3); Vec3
|
||||||
|
// var10 = collideBoundingBox(this, new Vec3(0.0D, (double)this.maxUpStep,
|
||||||
|
// 0.0D), var2.expandTowards(var1.x, 0.0D, var1.z), this.level, var3);
|
||||||
// if (var10.y < (double)this.maxUpStep) {
|
// if (var10.y < (double)this.maxUpStep) {
|
||||||
// Vec3 var11 = collideBoundingBox(this, new Vec3(var1.x, 0.0D, var1.z), var2.move(var10), this.level, var3).add(var10);
|
// Vec3 var11 = collideBoundingBox(this, new Vec3(var1.x, 0.0D,
|
||||||
// if (var11.horizontalDistanceSqr() > var9.horizontalDistanceSqr()) {
|
// var1.z), var2.move(var10), this.level, var3).add(var10); if
|
||||||
|
// (var11.horizontalDistanceSqr() > var9.horizontalDistanceSqr()) {
|
||||||
// var9 = var11;
|
// var9 = var11;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (var9.horizontalDistanceSqr() > var4.horizontalDistanceSqr()) {
|
// if (var9.horizontalDistanceSqr() > var4.horizontalDistanceSqr()) {
|
||||||
// return var9.add(collideBoundingBox(this, new Vec3(0.0D, -var9.y + var1.y, 0.0D), var2.move(var9), this.level, var3));
|
// return var9.add(collideBoundingBox(this, new Vec3(0.0D, -var9.y +
|
||||||
// }
|
// var1.y, 0.0D), var2.move(var9), this.level, var3)); }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// return var4;
|
// return var4;
|
||||||
|
@ -62,7 +66,8 @@ impl HasCollision for World {
|
||||||
fn collide(&self, movement: &Vec3, entity: &EntityData) -> Vec3 {
|
fn collide(&self, movement: &Vec3, entity: &EntityData) -> Vec3 {
|
||||||
let entity_bounding_box = entity.bounding_box;
|
let entity_bounding_box = entity.bounding_box;
|
||||||
// TODO: get_entity_collisions
|
// TODO: get_entity_collisions
|
||||||
// let entity_collisions = world.get_entity_collisions(self, entity_bounding_box.expand_towards(movement));
|
// let entity_collisions = world.get_entity_collisions(self,
|
||||||
|
// entity_bounding_box.expand_towards(movement));
|
||||||
let entity_collisions = Vec::new();
|
let entity_collisions = Vec::new();
|
||||||
if movement.length_sqr() == 0.0 {
|
if movement.length_sqr() == 0.0 {
|
||||||
*movement
|
*movement
|
||||||
|
@ -144,7 +149,8 @@ impl<D: DerefMut<Target = World>> MovableEntity for Entity<'_, D> {
|
||||||
// .get_block_state(&block_pos_below)
|
// .get_block_state(&block_pos_below)
|
||||||
// .expect("Couldn't get block state below");
|
// .expect("Couldn't get block state below");
|
||||||
|
|
||||||
// self.check_fall_damage(collide_result.y, on_ground, block_state_below, block_pos_below);
|
// self.check_fall_damage(collide_result.y, on_ground, block_state_below,
|
||||||
|
// block_pos_below);
|
||||||
|
|
||||||
// if self.isRemoved() { return; }
|
// if self.isRemoved() { return; }
|
||||||
|
|
||||||
|
@ -159,12 +165,14 @@ impl<D: DerefMut<Target = World>> MovableEntity for Entity<'_, D> {
|
||||||
|
|
||||||
if vertical_collision {
|
if vertical_collision {
|
||||||
// blockBelow.updateEntityAfterFallOn(this.level, this);
|
// blockBelow.updateEntityAfterFallOn(this.level, this);
|
||||||
// the default implementation of updateEntityAfterFallOn sets the y movement to 0
|
// the default implementation of updateEntityAfterFallOn sets the y movement to
|
||||||
|
// 0
|
||||||
self.delta.y = 0.;
|
self.delta.y = 0.;
|
||||||
}
|
}
|
||||||
|
|
||||||
if on_ground {
|
if on_ground {
|
||||||
// blockBelow.stepOn(this.level, blockPosBelow, blockStateBelow, this);
|
// blockBelow.stepOn(this.level, blockPosBelow, blockStateBelow,
|
||||||
|
// this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sounds
|
// sounds
|
||||||
|
@ -172,21 +180,22 @@ impl<D: DerefMut<Target = World>> MovableEntity for Entity<'_, D> {
|
||||||
// this.tryCheckInsideBlocks();
|
// this.tryCheckInsideBlocks();
|
||||||
|
|
||||||
// float var25 = this.getBlockSpeedFactor();
|
// float var25 = this.getBlockSpeedFactor();
|
||||||
// this.setDeltaMovement(this.getDeltaMovement().multiply((double)var25, 1.0D, (double)var25));
|
// this.setDeltaMovement(this.getDeltaMovement().multiply((double)var25, 1.0D,
|
||||||
// if (this.level.getBlockStatesIfLoaded(this.getBoundingBox().deflate(1.0E-6D)).noneMatch((var0) -> {
|
// (double)var25)); if (this.level.getBlockStatesIfLoaded(this.
|
||||||
|
// getBoundingBox().deflate(1.0E-6D)).noneMatch((var0) -> {
|
||||||
// return var0.is(BlockTags.FIRE) || var0.is(Blocks.LAVA);
|
// return var0.is(BlockTags.FIRE) || var0.is(Blocks.LAVA);
|
||||||
// })) {
|
// })) {
|
||||||
// if (this.remainingFireTicks <= 0) {
|
// if (this.remainingFireTicks <= 0) {
|
||||||
// this.setRemainingFireTicks(-this.getFireImmuneTicks());
|
// this.setRemainingFireTicks(-this.getFireImmuneTicks());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (this.wasOnFire && (this.isInPowderSnow || this.isInWaterRainOrBubble())) {
|
// if (this.wasOnFire && (this.isInPowderSnow ||
|
||||||
// this.playEntityOnFireExtinguishedSound();
|
// this.isInWaterRainOrBubble())) { this.
|
||||||
// }
|
// playEntityOnFireExtinguishedSound(); }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (this.isOnFire() && (this.isInPowderSnow || this.isInWaterRainOrBubble())) {
|
// if (this.isOnFire() && (this.isInPowderSnow || this.isInWaterRainOrBubble()))
|
||||||
// this.setRemainingFireTicks(-this.getFireImmuneTicks());
|
// { this.setRemainingFireTicks(-this.getFireImmuneTicks());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -143,11 +143,17 @@ impl Shapes {
|
||||||
if b.is_empty() {
|
if b.is_empty() {
|
||||||
return if op_true_false { a } else { empty_shape() };
|
return if op_true_false { a } else { empty_shape() };
|
||||||
}
|
}
|
||||||
// IndexMerger var5 = createIndexMerger(1, a.getCoords(Direction.Axis.X), b.getCoords(Direction.Axis.X), var3, var4);
|
// IndexMerger var5 = createIndexMerger(1, a.getCoords(Direction.Axis.X),
|
||||||
// IndexMerger var6 = createIndexMerger(var5.size() - 1, a.getCoords(Direction.Axis.Y), b.getCoords(Direction.Axis.Y), var3, var4);
|
// b.getCoords(Direction.Axis.X), var3, var4); IndexMerger var6 =
|
||||||
// IndexMerger var7 = createIndexMerger((var5.size() - 1) * (var6.size() - 1), a.getCoords(Direction.Axis.Z), b.getCoords(Direction.Axis.Z), var3, var4);
|
// createIndexMerger(var5.size() - 1, a.getCoords(Direction.Axis.Y),
|
||||||
// BitSetDiscreteVoxelShape var8 = BitSetDiscreteVoxelShape.join(a.shape, b.shape, var5, var6, var7, op);
|
// b.getCoords(Direction.Axis.Y), var3, var4); IndexMerger var7 =
|
||||||
// return (VoxelShape)(var5 instanceof DiscreteCubeMerger && var6 instanceof DiscreteCubeMerger && var7 instanceof DiscreteCubeMerger ? new CubeVoxelShape(var8) : new ArrayVoxelShape(var8, var5.getList(), var6.getList(), var7.getList()));
|
// createIndexMerger((var5.size() - 1) * (var6.size() - 1),
|
||||||
|
// a.getCoords(Direction.Axis.Z), b.getCoords(Direction.Axis.Z), var3, var4);
|
||||||
|
// BitSetDiscreteVoxelShape var8 = BitSetDiscreteVoxelShape.join(a.shape,
|
||||||
|
// b.shape, var5, var6, var7, op); return (VoxelShape)(var5 instanceof
|
||||||
|
// DiscreteCubeMerger && var6 instanceof DiscreteCubeMerger && var7 instanceof
|
||||||
|
// DiscreteCubeMerger ? new CubeVoxelShape(var8) : new ArrayVoxelShape(var8,
|
||||||
|
// var5.getList(), var6.getList(), var7.getList()));
|
||||||
let var5 = Self::create_index_merger(
|
let var5 = Self::create_index_merger(
|
||||||
1,
|
1,
|
||||||
a.get_coords(Axis::X),
|
a.get_coords(Axis::X),
|
||||||
|
@ -266,8 +272,8 @@ impl Shapes {
|
||||||
) -> IndexMerger {
|
) -> IndexMerger {
|
||||||
let var5 = var1.len() - 1;
|
let var5 = var1.len() - 1;
|
||||||
let var6 = var2.len() - 1;
|
let var6 = var2.len() - 1;
|
||||||
// if (&var1 as &dyn Any).is::<CubePointRange>() && (&var2 as &dyn Any).is::<CubePointRange>()
|
// if (&var1 as &dyn Any).is::<CubePointRange>() && (&var2 as &dyn
|
||||||
// {
|
// Any).is::<CubePointRange>() {
|
||||||
// return new DiscreteCubeMerger(var0, var5, var6, var3, var4);
|
// return new DiscreteCubeMerger(var0, var5, var6, var3, var4);
|
||||||
// let var7: i64 = lcm(var5 as u32, var6 as u32).try_into().unwrap();
|
// let var7: i64 = lcm(var5 as u32, var6 as u32).try_into().unwrap();
|
||||||
// // if ((long)var0 * var7 <= 256L) {
|
// // if ((long)var0 * var7 <= 256L) {
|
||||||
|
@ -305,8 +311,8 @@ pub enum VoxelShape {
|
||||||
impl VoxelShape {
|
impl VoxelShape {
|
||||||
// public double min(Direction.Axis var1) {
|
// public double min(Direction.Axis var1) {
|
||||||
// int var2 = this.shape.firstFull(var1);
|
// int var2 = this.shape.firstFull(var1);
|
||||||
// return var2 >= this.shape.getSize(var1) ? 1.0D / 0.0 : this.get(var1, var2);
|
// return var2 >= this.shape.getSize(var1) ? 1.0D / 0.0 : this.get(var1,
|
||||||
// }
|
// var2); }
|
||||||
// public double max(Direction.Axis var1) {
|
// public double max(Direction.Axis var1) {
|
||||||
// int var2 = this.shape.lastFull(var1);
|
// int var2 = this.shape.lastFull(var1);
|
||||||
// return var2 <= 0 ? -1.0D / 0.0 : this.get(var1, var2);
|
// return var2 <= 0 ? -1.0D / 0.0 : this.get(var1, var2);
|
||||||
|
@ -467,8 +473,8 @@ impl VoxelShape {
|
||||||
// public VoxelShape optimize() {
|
// public VoxelShape optimize() {
|
||||||
// VoxelShape[] var1 = new VoxelShape[]{Shapes.empty()};
|
// VoxelShape[] var1 = new VoxelShape[]{Shapes.empty()};
|
||||||
// this.forAllBoxes((var1x, var3, var5, var7, var9, var11) -> {
|
// this.forAllBoxes((var1x, var3, var5, var7, var9, var11) -> {
|
||||||
// var1[0] = Shapes.joinUnoptimized(var1[0], Shapes.box(var1x, var3, var5, var7, var9, var11), BooleanOp.OR);
|
// var1[0] = Shapes.joinUnoptimized(var1[0], Shapes.box(var1x, var3,
|
||||||
// });
|
// var5, var7, var9, var11), BooleanOp.OR); });
|
||||||
// return var1[0];
|
// return var1[0];
|
||||||
// }
|
// }
|
||||||
fn optimize(&self) -> VoxelShape {
|
fn optimize(&self) -> VoxelShape {
|
||||||
|
@ -497,8 +503,9 @@ impl VoxelShape {
|
||||||
// DoubleList var3 = this.getCoords(Direction.Axis.Y);
|
// DoubleList var3 = this.getCoords(Direction.Axis.Y);
|
||||||
// DoubleList var4 = this.getCoords(Direction.Axis.Z);
|
// DoubleList var4 = this.getCoords(Direction.Axis.Z);
|
||||||
// this.shape.forAllBoxes((var4x, var5, var6, var7, var8, var9) -> {
|
// this.shape.forAllBoxes((var4x, var5, var6, var7, var8, var9) -> {
|
||||||
// var1.consume(var2.getDouble(var4x), var3.getDouble(var5), var4.getDouble(var6), var2.getDouble(var7), var3.getDouble(var8), var4.getDouble(var9));
|
// var1.consume(var2.getDouble(var4x), var3.getDouble(var5),
|
||||||
// }, true);
|
// var4.getDouble(var6), var2.getDouble(var7), var3.getDouble(var8),
|
||||||
|
// var4.getDouble(var9)); }, true);
|
||||||
// }
|
// }
|
||||||
pub fn for_all_boxes(&self, mut consumer: impl FnMut(f64, f64, f64, f64, f64, f64))
|
pub fn for_all_boxes(&self, mut consumer: impl FnMut(f64, f64, f64, f64, f64, f64))
|
||||||
where
|
where
|
||||||
|
|
|
@ -69,8 +69,8 @@ impl<'a> BlockCollisions<'a> {
|
||||||
// if (this.cachedBlockGetter != null && this.cachedBlockGetterPos == var5) {
|
// if (this.cachedBlockGetter != null && this.cachedBlockGetterPos == var5) {
|
||||||
// return this.cachedBlockGetter;
|
// return this.cachedBlockGetter;
|
||||||
// } else {
|
// } else {
|
||||||
// BlockGetter var7 = this.collisionGetter.getChunkForCollisions(chunkX, chunkZ);
|
// BlockGetter var7 = this.collisionGetter.getChunkForCollisions(chunkX,
|
||||||
// this.cachedBlockGetter = var7;
|
// chunkZ); this.cachedBlockGetter = var7;
|
||||||
// this.cachedBlockGetterPos = chunkPosLong;
|
// this.cachedBlockGetterPos = chunkPosLong;
|
||||||
// return var7;
|
// return var7;
|
||||||
// }
|
// }
|
||||||
|
@ -100,7 +100,8 @@ impl<'a> Iterator for BlockCollisions<'a> {
|
||||||
.get(&(&pos).into(), self.world.min_y())
|
.get(&(&pos).into(), self.world.min_y())
|
||||||
.unwrap_or(BlockState::Air);
|
.unwrap_or(BlockState::Air);
|
||||||
|
|
||||||
// TODO: continue if self.only_suffocating_blocks and the block is not suffocating
|
// TODO: continue if self.only_suffocating_blocks and the block is not
|
||||||
|
// suffocating
|
||||||
|
|
||||||
let block_shape = block_state.shape();
|
let block_shape = block_state.shape();
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,8 @@ impl<D: DerefMut<Target = World>> HasPhysics for Entity<'_, D> {
|
||||||
// if (this.shouldDiscardFriction()) {
|
// if (this.shouldDiscardFriction()) {
|
||||||
// this.setDeltaMovement(movement.x, yMovement, movement.z);
|
// this.setDeltaMovement(movement.x, yMovement, movement.z);
|
||||||
// } else {
|
// } else {
|
||||||
// this.setDeltaMovement(movement.x * (double)inertia, yMovement * 0.9800000190734863D, movement.z * (double)inertia);
|
// this.setDeltaMovement(movement.x * (double)inertia, yMovement *
|
||||||
// }
|
// 0.9800000190734863D, movement.z * (double)inertia); }
|
||||||
|
|
||||||
// if should_discard_friction(self) {
|
// if should_discard_friction(self) {
|
||||||
if false {
|
if false {
|
||||||
|
@ -79,7 +79,8 @@ impl<D: DerefMut<Target = World>> HasPhysics for Entity<'_, D> {
|
||||||
/// applies air resistance, calls self.travel(), and some other random
|
/// applies air resistance, calls self.travel(), and some other random
|
||||||
/// stuff.
|
/// stuff.
|
||||||
fn ai_step(&mut self) {
|
fn ai_step(&mut self) {
|
||||||
// vanilla does movement interpolation here, doesn't really matter much for a bot though
|
// vanilla does movement interpolation here, doesn't really matter much for a
|
||||||
|
// bot though
|
||||||
|
|
||||||
if self.delta.x.abs() < 0.003 {
|
if self.delta.x.abs() < 0.003 {
|
||||||
self.delta.x = 0.;
|
self.delta.x = 0.;
|
||||||
|
@ -157,17 +158,18 @@ fn handle_relative_friction_and_calculate_movement<D: DerefMut<Target = World>>(
|
||||||
.expect("Entity should exist.");
|
.expect("Entity should exist.");
|
||||||
// let delta_movement = entity.delta;
|
// let delta_movement = entity.delta;
|
||||||
// ladders
|
// ladders
|
||||||
// if ((entity.horizontalCollision || entity.jumping) && (entity.onClimbable() || entity.getFeetBlockState().is(Blocks.POWDER_SNOW) && PowderSnowBlock.canEntityWalkOnPowderSnow(entity))) {
|
// if ((entity.horizontalCollision || entity.jumping) && (entity.onClimbable()
|
||||||
// var3 = new Vec3(var3.x, 0.2D, var3.z);
|
// || entity.getFeetBlockState().is(Blocks.POWDER_SNOW) &&
|
||||||
// }
|
// PowderSnowBlock.canEntityWalkOnPowderSnow(entity))) { var3 = new
|
||||||
|
// Vec3(var3.x, 0.2D, var3.z); }
|
||||||
// TODO: powdered snow
|
// TODO: powdered snow
|
||||||
|
|
||||||
entity.delta
|
entity.delta
|
||||||
}
|
}
|
||||||
|
|
||||||
// private float getFrictionInfluencedSpeed(float friction) {
|
// private float getFrictionInfluencedSpeed(float friction) {
|
||||||
// return this.onGround ? this.getSpeed() * (0.21600002F / (friction * friction * friction)) : this.flyingSpeed;
|
// return this.onGround ? this.getSpeed() * (0.21600002F / (friction *
|
||||||
// }
|
// friction * friction)) : this.flyingSpeed; }
|
||||||
fn get_friction_influenced_speed(entity: &EntityData, friction: f32) -> f32 {
|
fn get_friction_influenced_speed(entity: &EntityData, friction: f32) -> f32 {
|
||||||
// TODO: have speed & flying_speed fields in entity
|
// TODO: have speed & flying_speed fields in entity
|
||||||
if entity.on_ground {
|
if entity.on_ground {
|
||||||
|
@ -207,8 +209,8 @@ fn block_jump_factor<D: DerefMut<Target = World>>(entity: &Entity<D>) -> f32 {
|
||||||
// return 0.42F * this.getBlockJumpFactor();
|
// return 0.42F * this.getBlockJumpFactor();
|
||||||
// }
|
// }
|
||||||
// public double getJumpBoostPower() {
|
// public double getJumpBoostPower() {
|
||||||
// return this.hasEffect(MobEffects.JUMP) ? (double)(0.1F * (float)(this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D;
|
// return this.hasEffect(MobEffects.JUMP) ? (double)(0.1F *
|
||||||
// }
|
// (float)(this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D; }
|
||||||
fn jump_power<D: DerefMut<Target = World>>(entity: &Entity<D>) -> f32 {
|
fn jump_power<D: DerefMut<Target = World>>(entity: &Entity<D>) -> f32 {
|
||||||
0.42 * block_jump_factor(entity)
|
0.42 * block_jump_factor(entity)
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,12 +226,14 @@ impl Connection<ClientboundHandshakePacket, ServerboundHandshakePacket> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change our state from handshake to login. This is the state that is used for logging in.
|
/// Change our state from handshake to login. This is the state that is used
|
||||||
|
/// for logging in.
|
||||||
pub fn login(self) -> Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
pub fn login(self) -> Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change our state from handshake to status. This is the state that is used for pinging the server.
|
/// Change our state from handshake to status. This is the state that is
|
||||||
|
/// used for pinging the server.
|
||||||
pub fn status(self) -> Connection<ClientboundStatusPacket, ServerboundStatusPacket> {
|
pub fn status(self) -> Connection<ClientboundStatusPacket, ServerboundStatusPacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
@ -252,14 +254,16 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the encryption key that is used to encrypt and decrypt packets. It's the same for both reading and writing.
|
/// Set the encryption key that is used to encrypt and decrypt packets. It's
|
||||||
|
/// the same for both reading and writing.
|
||||||
pub fn set_encryption_key(&mut self, key: [u8; 16]) {
|
pub fn set_encryption_key(&mut self, key: [u8; 16]) {
|
||||||
let (enc_cipher, dec_cipher) = azalea_crypto::create_cipher(&key);
|
let (enc_cipher, dec_cipher) = azalea_crypto::create_cipher(&key);
|
||||||
self.reader.dec_cipher = Some(dec_cipher);
|
self.reader.dec_cipher = Some(dec_cipher);
|
||||||
self.writer.enc_cipher = Some(enc_cipher);
|
self.writer.enc_cipher = Some(enc_cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change our state from login to game. This is the state that's used when you're actually in the game.
|
/// Change our state from login to game. This is the state that's used when
|
||||||
|
/// you're actually in the game.
|
||||||
pub fn game(self) -> Connection<ClientboundGamePacket, ServerboundGamePacket> {
|
pub fn game(self) -> Connection<ClientboundGamePacket, ServerboundGamePacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
@ -342,7 +346,8 @@ where
|
||||||
R1: ProtocolPacket + Debug,
|
R1: ProtocolPacket + Debug,
|
||||||
W1: ProtocolPacket + Debug,
|
W1: ProtocolPacket + Debug,
|
||||||
{
|
{
|
||||||
/// Creates a `Connection` of a type from a `Connection` of another type. Useful for servers or custom packets.
|
/// Creates a `Connection` of a type from a `Connection` of another type.
|
||||||
|
/// Useful for servers or custom packets.
|
||||||
pub fn from<R2, W2>(connection: Connection<R1, W1>) -> Connection<R2, W2>
|
pub fn from<R2, W2>(connection: Connection<R1, W1>) -> Connection<R2, W2>
|
||||||
where
|
where
|
||||||
R2: ProtocolPacket + Debug,
|
R2: ProtocolPacket + Debug,
|
||||||
|
|
|
@ -44,7 +44,8 @@ pub struct ServerAddress {
|
||||||
impl<'a> TryFrom<&'a str> for ServerAddress {
|
impl<'a> TryFrom<&'a str> for ServerAddress {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
/// Convert a Minecraft server address (host:port, the port is optional) to a ServerAddress
|
/// Convert a Minecraft server address (host:port, the port is optional) to
|
||||||
|
/// a ServerAddress
|
||||||
fn try_from(string: &str) -> Result<Self, Self::Error> {
|
fn try_from(string: &str) -> Result<Self, Self::Error> {
|
||||||
if string.is_empty() {
|
if string.is_empty() {
|
||||||
return Err("Empty string".to_string());
|
return Err("Empty string".to_string());
|
||||||
|
|
|
@ -4,7 +4,8 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use azalea_world::entity::{metadata, EntityData, EntityMetadata};
|
use azalea_world::entity::{metadata, EntityData, EntityMetadata};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
/// This packet is sent by the server when a player comes into visible range, not when a player joins.
|
/// This packet is sent by the server when a player comes into visible range,
|
||||||
|
/// not when a player joins.
|
||||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||||
pub struct ClientboundAddPlayerPacket {
|
pub struct ClientboundAddPlayerPacket {
|
||||||
#[var]
|
#[var]
|
||||||
|
|
|
@ -73,7 +73,8 @@ impl<T: McBufWritable> McBufWritable for BrigadierNumber<T> {
|
||||||
pub enum BrigadierString {
|
pub enum BrigadierString {
|
||||||
/// Reads a single word
|
/// Reads a single word
|
||||||
SingleWord = 0,
|
SingleWord = 0,
|
||||||
// If it starts with a ", keeps reading until another " (allowing escaping with \). Otherwise behaves the same as SINGLE_WORD
|
// If it starts with a ", keeps reading until another " (allowing escaping with \). Otherwise
|
||||||
|
// behaves the same as SINGLE_WORD
|
||||||
QuotablePhrase = 1,
|
QuotablePhrase = 1,
|
||||||
// Reads the rest of the content after the cursor. Quotes will not be removed.
|
// Reads the rest of the content after the cursor. Quotes will not be removed.
|
||||||
GreedyPhrase = 2,
|
GreedyPhrase = 2,
|
||||||
|
|
|
@ -73,7 +73,8 @@ pub struct MapDecoration {
|
||||||
pub decoration_type: DecorationType,
|
pub decoration_type: DecorationType,
|
||||||
pub x: i8,
|
pub x: i8,
|
||||||
pub y: i8,
|
pub y: i8,
|
||||||
/// Minecraft does & 15 on this value, azalea-protocol doesn't. I don't think it matters.
|
/// Minecraft does & 15 on this value, azalea-protocol doesn't. I don't
|
||||||
|
/// think it matters.
|
||||||
pub rot: i8,
|
pub rot: i8,
|
||||||
pub name: Option<Component>,
|
pub name: Option<Component>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,8 +83,8 @@ pub struct MessageSignatureCache {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// impl PackedSignedMessageBody {
|
// impl PackedSignedMessageBody {
|
||||||
// pub fn unpack(&self, unpacker: impl Fn(u32) -> Option<SignedMessageBody>) {}
|
// pub fn unpack(&self, unpacker: impl Fn(u32) -> Option<SignedMessageBody>)
|
||||||
// }
|
// {} }
|
||||||
|
|
||||||
impl ClientboundPlayerChatPacket {
|
impl ClientboundPlayerChatPacket {
|
||||||
/// Returns the content of the message. If you want to get the Component
|
/// Returns the content of the message. If you want to get the Component
|
||||||
|
@ -176,7 +176,8 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::backtrace::Backtrace;
|
use std::backtrace::Backtrace;
|
||||||
|
|
||||||
// you can remove or update this test if it breaks because mojang changed the structure of the packet again
|
// you can remove or update this test if it breaks because mojang changed the
|
||||||
|
// structure of the packet again
|
||||||
#[test]
|
#[test]
|
||||||
fn test_player_chat_packet() {
|
fn test_player_chat_packet() {
|
||||||
let data: [u8; 295] = [
|
let data: [u8; 295] = [
|
||||||
|
|
|
@ -133,9 +133,9 @@ pub struct CriterionProgress {
|
||||||
// parent_id: None,
|
// parent_id: None,
|
||||||
// display: Some(DisplayInfo {
|
// display: Some(DisplayInfo {
|
||||||
// title: Component::from("title".to_string()),
|
// title: Component::from("title".to_string()),
|
||||||
// description: Component::from("description".to_string()),
|
// description:
|
||||||
// icon: Slot::Empty,
|
// Component::from("description".to_string()), icon:
|
||||||
// frame: FrameType::Task,
|
// Slot::Empty, frame: FrameType::Task,
|
||||||
// show_toast: true,
|
// show_toast: true,
|
||||||
// hidden: false,
|
// hidden: false,
|
||||||
// background: None,
|
// background: None,
|
||||||
|
@ -164,7 +164,7 @@ pub struct CriterionProgress {
|
||||||
// .collect(),
|
// .collect(),
|
||||||
// };
|
// };
|
||||||
// packet.write_into(&mut buf).unwrap();
|
// packet.write_into(&mut buf).unwrap();
|
||||||
// let packet = ClientboundUpdateAdvancementsPacket::read_from(&mut buf).unwrap();
|
// let packet = ClientboundUpdateAdvancementsPacket::read_from(&mut
|
||||||
// assert_eq!(packet.reset, true);
|
// buf).unwrap(); assert_eq!(packet.reset, true);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -15,7 +15,8 @@ pub struct ServerboundSetJigsawBlockPacket {
|
||||||
pub target: ResourceLocation,
|
pub target: ResourceLocation,
|
||||||
pub pool: ResourceLocation,
|
pub pool: ResourceLocation,
|
||||||
pub final_state: String,
|
pub final_state: String,
|
||||||
pub joint: String, // TODO: Does JigsawBlockEntity$JointType::getSerializedName, may not be implemented
|
pub joint: String, /* TODO: Does JigsawBlockEntity$JointType::getSerializedName, may not be
|
||||||
|
* implemented */
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum JointType {
|
pub enum JointType {
|
||||||
|
|
|
@ -7,7 +7,8 @@ use crate::read::ReadPacketError;
|
||||||
use azalea_buf::{BufReadError, McBufVarReadable, McBufVarWritable, McBufWritable};
|
use azalea_buf::{BufReadError, McBufVarReadable, McBufVarWritable, McBufWritable};
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
|
|
||||||
// TODO: rename the packet files to just like clientbound_add_entity instead of clientbound_add_entity_packet
|
// TODO: rename the packet files to just like clientbound_add_entity instead of
|
||||||
|
// clientbound_add_entity_packet
|
||||||
|
|
||||||
pub const PROTOCOL_VERSION: u32 = 761;
|
pub const PROTOCOL_VERSION: u32 = 761;
|
||||||
|
|
||||||
|
|
|
@ -261,27 +261,30 @@ where
|
||||||
// #[cfg(test)]
|
// #[cfg(test)]
|
||||||
// mod tests {
|
// mod tests {
|
||||||
// use super::*;
|
// use super::*;
|
||||||
// use crate::packets::game::{clientbound_player_chat_packet::ChatType, ClientboundGamePacket};
|
// use crate::packets::game::{clientbound_player_chat_packet::ChatType,
|
||||||
// use std::io::Cursor;
|
// ClientboundGamePacket}; use std::io::Cursor;
|
||||||
|
|
||||||
// #[tokio::test]
|
// #[tokio::test]
|
||||||
// async fn test_read_packet() {
|
// async fn test_read_packet() {
|
||||||
// let mut buf: Cursor<&[u8]> = Cursor::new(&[
|
// let mut buf: Cursor<&[u8]> = Cursor::new(&[
|
||||||
// 51, 0, 12, 177, 250, 155, 132, 106, 60, 218, 161, 217, 90, 157, 105, 57, 206, 20, 0, 5,
|
// 51, 0, 12, 177, 250, 155, 132, 106, 60, 218, 161, 217, 90, 157,
|
||||||
// 104, 101, 108, 108, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 116,
|
// 105, 57, 206, 20, 0, 5, 104, 101, 108, 108, 111, 0, 0, 0, 0, 0,
|
||||||
// 123, 34, 101, 120, 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114, 34, 58,
|
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 116, 123, 34, 101, 120,
|
||||||
// 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 91, 77, 69, 77, 66,
|
// 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114, 34, 58,
|
||||||
// 69, 82, 93, 32, 112, 108, 97, 121, 101, 114, 49, 34, 125, 44, 123, 34, 116, 101, 120,
|
// 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58,
|
||||||
// 116, 34, 58, 34, 32, 34, 125, 44, 123, 34, 99, 111, 108, 111, 114, 34, 58, 34, 103,
|
// 34, 91, 77, 69, 77, 66, 69, 82, 93, 32, 112, 108, 97, 121, 101,
|
||||||
// 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 92, 117, 48, 48, 51, 101, 32,
|
// 114, 49, 34, 125, 44, 123, 34, 116, 101, 120, 116, 34, 58, 34,
|
||||||
// 104, 101, 108, 108, 111, 34, 125, 93, 44, 34, 116, 101, 120, 116, 34, 58, 34, 34, 125,
|
// 32, 34, 125, 44, 123, 34, 99, 111, 108, 111, 114, 34, 58, 34, 103,
|
||||||
// 0, 7, 64, 123, 34, 101, 120, 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114,
|
// 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 92,
|
||||||
// 34, 58, 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 91, 77, 69,
|
// 117, 48, 48, 51, 101, 32, 104, 101, 108, 108, 111, 34, 125, 93,
|
||||||
// 77, 66, 69, 82, 93, 32, 112, 108, 97, 121, 101, 114, 49, 34, 125, 93, 44, 34, 116, 101,
|
// 44, 34, 116, 101, 120, 116, 34, 58, 34, 34, 125, 0, 7, 64, 123,
|
||||||
// 120, 116, 34, 58, 34, 34, 125, 0,
|
// 34, 101, 120, 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114,
|
||||||
// ]);
|
// 34, 58, 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116,
|
||||||
// let packet = packet_decoder::<ClientboundGamePacket>(&mut buf).unwrap();
|
// 34, 58, 34, 91, 77, 69, 77, 66, 69, 82, 93, 32, 112, 108, 97,
|
||||||
// match &packet {
|
// 121, 101, 114, 49, 34, 125, 93, 44, 34, 116, 101, 120, 116, 34,
|
||||||
|
// 58, 34, 34, 125, 0, ]);
|
||||||
|
// let packet = packet_decoder::<ClientboundGamePacket>(&mut
|
||||||
|
// buf).unwrap(); match &packet {
|
||||||
// ClientboundGamePacket::PlayerChat(m) => {
|
// ClientboundGamePacket::PlayerChat(m) => {
|
||||||
// assert_eq!(
|
// assert_eq!(
|
||||||
// m.chat_type.chat_type,
|
// m.chat_type.chat_type,
|
||||||
|
|
|
@ -26,7 +26,9 @@ pub async fn resolve_address(address: &ServerAddress) -> Result<SocketAddr, Reso
|
||||||
return Ok(SocketAddr::new(ip, address.port));
|
return Ok(SocketAddr::new(ip, address.port));
|
||||||
}
|
}
|
||||||
|
|
||||||
// we specify Cloudflare instead of the default resolver because trust_dns_resolver has an issue on Windows where it's really slow using the default resolver
|
// we specify Cloudflare instead of the default resolver because
|
||||||
|
// trust_dns_resolver has an issue on Windows where it's really slow using the
|
||||||
|
// default resolver
|
||||||
let resolver =
|
let resolver =
|
||||||
TokioAsyncResolver::tokio(ResolverConfig::cloudflare(), ResolverOpts::default()).unwrap();
|
TokioAsyncResolver::tokio(ResolverConfig::cloudflare(), ResolverOpts::default()).unwrap();
|
||||||
|
|
||||||
|
@ -35,7 +37,8 @@ pub async fn resolve_address(address: &ServerAddress) -> Result<SocketAddr, Reso
|
||||||
.srv_lookup(format!("_minecraft._tcp.{}", address.host).as_str())
|
.srv_lookup(format!("_minecraft._tcp.{}", address.host).as_str())
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// if it resolves that means it's a redirect so we call resolve_address again with the new host
|
// if it resolves that means it's a redirect so we call resolve_address again
|
||||||
|
// with the new host
|
||||||
if let Ok(redirect_result) = srv_redirect_result {
|
if let Ok(redirect_result) = srv_redirect_result {
|
||||||
let redirect_srv = redirect_result
|
let redirect_srv = redirect_result
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -50,9 +50,9 @@ pub struct ChunkStorage {
|
||||||
pub chunks: HashMap<ChunkPos, Arc<Mutex<Chunk>>>,
|
pub chunks: HashMap<ChunkPos, Arc<Mutex<Chunk>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single chunk in a world (16*?*16 blocks). This only contains the blocks and biomes. You
|
/// A single chunk in a world (16*?*16 blocks). This only contains the blocks
|
||||||
/// can derive the height of the chunk from the number of sections, but you
|
/// and biomes. You can derive the height of the chunk from the number of
|
||||||
/// need a [`ChunkStorage`] to get the minimum Y coordinate.
|
/// sections, but you need a [`ChunkStorage`] to get the minimum Y coordinate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
pub sections: Vec<Section>,
|
pub sections: Vec<Section>,
|
||||||
|
|
|
@ -53,7 +53,8 @@ impl<'d, D: DerefMut<Target = World>> Entity<'d, D> {
|
||||||
pub fn set_rotation(&mut self, y_rot: f32, x_rot: f32) {
|
pub fn set_rotation(&mut self, y_rot: f32, x_rot: f32) {
|
||||||
self.y_rot = y_rot % 360.0;
|
self.y_rot = y_rot % 360.0;
|
||||||
self.x_rot = x_rot.clamp(-90.0, 90.0) % 360.0;
|
self.x_rot = x_rot.clamp(-90.0, 90.0) % 360.0;
|
||||||
// TODO: minecraft also sets yRotO and xRotO to xRot and yRot ... but idk what they're used for so
|
// TODO: minecraft also sets yRotO and xRotO to xRot and yRot ... but
|
||||||
|
// idk what they're used for so
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_relative(&mut self, speed: f32, acceleration: &Vec3) {
|
pub fn move_relative(&mut self, speed: f32, acceleration: &Vec3) {
|
||||||
|
@ -116,8 +117,8 @@ impl<'d, D: Deref<Target = World>> Entity<'d, D> {
|
||||||
// if (this.level.getBlockState(var5).isAir()) {
|
// if (this.level.getBlockState(var5).isAir()) {
|
||||||
// BlockPos var6 = var5.below();
|
// BlockPos var6 = var5.below();
|
||||||
// BlockState var7 = this.level.getBlockState(var6);
|
// BlockState var7 = this.level.getBlockState(var6);
|
||||||
// if (var7.is(BlockTags.FENCES) || var7.is(BlockTags.WALLS) || var7.getBlock() instanceof FenceGateBlock) {
|
// if (var7.is(BlockTags.FENCES) || var7.is(BlockTags.WALLS) ||
|
||||||
// return var6;
|
// var7.getBlock() instanceof FenceGateBlock) { return var6;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// return var5;
|
// return var5;
|
||||||
|
@ -181,7 +182,8 @@ impl<D: Deref<Target = World>> Deref for Entity<'_, D> {
|
||||||
pub struct EntityData {
|
pub struct EntityData {
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
/// The position of the entity right now.
|
/// The position of the entity right now.
|
||||||
/// This can be changde with unsafe_move, but the correct way is with world.move_entity
|
/// This can be changde with unsafe_move, but the correct way is with
|
||||||
|
/// world.move_entity
|
||||||
pos: Vec3,
|
pos: Vec3,
|
||||||
/// The position of the entity last tick.
|
/// The position of the entity last tick.
|
||||||
pub last_pos: Vec3,
|
pub last_pos: Vec3,
|
||||||
|
@ -205,7 +207,8 @@ pub struct EntityData {
|
||||||
|
|
||||||
/// The width and height of the entity.
|
/// The width and height of the entity.
|
||||||
pub dimensions: EntityDimensions,
|
pub dimensions: EntityDimensions,
|
||||||
/// The bounding box of the entity. This is more than just width and height, unlike dimensions.
|
/// The bounding box of the entity. This is more than just width and height,
|
||||||
|
/// unlike dimensions.
|
||||||
pub bounding_box: AABB,
|
pub bounding_box: AABB,
|
||||||
|
|
||||||
/// Whether the entity will try to jump every tick
|
/// Whether the entity will try to jump every tick
|
||||||
|
@ -258,7 +261,8 @@ impl EntityData {
|
||||||
metadata,
|
metadata,
|
||||||
|
|
||||||
attributes: AttributeModifiers {
|
attributes: AttributeModifiers {
|
||||||
// TODO: do the correct defaults for everything, some entities have different defaults
|
// TODO: do the correct defaults for everything, some entities have different
|
||||||
|
// defaults
|
||||||
speed: AttributeInstance::new(0.1),
|
speed: AttributeInstance::new(0.1),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,20 @@ use uuid::Uuid;
|
||||||
|
|
||||||
// How entity updates are processed (to avoid issues with shared worlds)
|
// How entity updates are processed (to avoid issues with shared worlds)
|
||||||
// - each bot contains a map of { entity id: updates received }
|
// - each bot contains a map of { entity id: updates received }
|
||||||
// - the shared world also contains a canonical "true" updates received for each entity
|
// - the shared world also contains a canonical "true" updates received for each
|
||||||
// - when a client loads an entity, its "updates received" is set to the same as the global "updates received"
|
// entity
|
||||||
// - when the shared world sees an entity for the first time, the "updates received" is set to 1.
|
// - when a client loads an entity, its "updates received" is set to the same as
|
||||||
// - clients can force the shared "updates received" to 0 to make it so certain entities (i.e. other bots in our swarm) don't get confused and updated by other bots
|
// the global "updates received"
|
||||||
// - when a client gets an update to an entity, we check if our "updates received" is the same as the shared world's "updates received":
|
// - when the shared world sees an entity for the first time, the "updates
|
||||||
// if it is, then process the update and increment the client's and shared world's "updates received"
|
// received" is set to 1.
|
||||||
// if not, then we simply increment our local "updates received" and do nothing else
|
// - clients can force the shared "updates received" to 0 to make it so certain
|
||||||
|
// entities (i.e. other bots in our swarm) don't get confused and updated by
|
||||||
|
// other bots
|
||||||
|
// - when a client gets an update to an entity, we check if our "updates
|
||||||
|
// received" is the same as the shared world's "updates received": if it is,
|
||||||
|
// then process the update and increment the client's and shared world's
|
||||||
|
// "updates received" if not, then we simply increment our local "updates
|
||||||
|
// received" and do nothing else
|
||||||
|
|
||||||
/// Store a map of entities by ID. To get an iterator over all entities, use
|
/// Store a map of entities by ID. To get an iterator over all entities, use
|
||||||
/// `storage.shared.read().entities` [`WeakEntityStorage::entities`].
|
/// `storage.shared.read().entities` [`WeakEntityStorage::entities`].
|
||||||
|
@ -125,7 +132,8 @@ impl PartialEntityStorage {
|
||||||
self.shared.read().data_by_id.contains_key(id)
|
self.shared.read().data_by_id.contains_key(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to an entity by its id, if it's being loaded by this storage.
|
/// Get a reference to an entity by its id, if it's being loaded by this
|
||||||
|
/// storage.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn limited_get_by_id(&self, id: u32) -> Option<&Arc<EntityData>> {
|
pub fn limited_get_by_id(&self, id: u32) -> Option<&Arc<EntityData>> {
|
||||||
self.data_by_id.get(&id)
|
self.data_by_id.get(&id)
|
||||||
|
@ -138,10 +146,11 @@ impl PartialEntityStorage {
|
||||||
self.data_by_id.get_mut(&id)
|
self.data_by_id.get_mut(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether we're allowed to update this entity (to prevent two clients in
|
/// Returns whether we're allowed to update this entity (to prevent two
|
||||||
/// a shared world updating it twice), and acknowleges that we WILL update
|
/// clients in a shared world updating it twice), and acknowleges that
|
||||||
/// it if it's true. Don't call this unless you actually got an entity
|
/// we WILL update it if it's true. Don't call this unless you actually
|
||||||
/// update that all other clients within render distance will get too.
|
/// got an entity update that all other clients within render distance
|
||||||
|
/// will get too.
|
||||||
pub fn maybe_update(&mut self, id: u32) -> bool {
|
pub fn maybe_update(&mut self, id: u32) -> bool {
|
||||||
let this_client_updates_received = self.updates_received.get(&id).copied();
|
let this_client_updates_received = self.updates_received.get(&id).copied();
|
||||||
let shared_updates_received = self.shared.read().updates_received.get(&id).copied();
|
let shared_updates_received = self.shared.read().updates_received.get(&id).copied();
|
||||||
|
@ -302,7 +311,8 @@ impl WeakEntityStorage {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if self.updates_received.remove(&id).is_none() {
|
if self.updates_received.remove(&id).is_none() {
|
||||||
// if this happens it means we weren't tracking the updates_received for the client (bad)
|
// if this happens it means we weren't tracking the updates_received for the
|
||||||
|
// client (bad)
|
||||||
warn!(
|
warn!(
|
||||||
"Tried to remove entity with id {id} from updates_received but it was not found."
|
"Tried to remove entity with id {id} from updates_received but it was not found."
|
||||||
);
|
);
|
||||||
|
|
|
@ -83,7 +83,8 @@ impl PalettedContainer {
|
||||||
.get_and_set(self.get_index(x, y, z), paletted_value as u64) as u32
|
.get_and_set(self.get_index(x, y, z), paletted_value as u64) as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the id at the given index and return the previous id. You probably want `.set` instead.
|
/// Sets the id at the given index and return the previous id. You probably
|
||||||
|
/// want `.set` instead.
|
||||||
pub fn set_at_index(&mut self, index: usize, value: u32) {
|
pub fn set_at_index(&mut self, index: usize, value: u32) {
|
||||||
let paletted_value = self.id_for(value);
|
let paletted_value = self.id_for(value);
|
||||||
self.storage.set(index, paletted_value as u64)
|
self.storage.set(index, paletted_value as u64)
|
||||||
|
@ -110,7 +111,8 @@ impl PalettedContainer {
|
||||||
// sanity check
|
// sanity check
|
||||||
debug_assert_eq!(storage.size(), self.container_type.size());
|
debug_assert_eq!(storage.size(), self.container_type.size());
|
||||||
|
|
||||||
// let palette = new_palette_type.as_empty_palette(1usize << (bits_per_entry as usize));
|
// let palette = new_palette_type.as_empty_palette(1usize << (bits_per_entry as
|
||||||
|
// usize));
|
||||||
let palette = new_palette_type.as_empty_palette();
|
let palette = new_palette_type.as_empty_palette();
|
||||||
PalettedContainer {
|
PalettedContainer {
|
||||||
bits_per_entry,
|
bits_per_entry,
|
||||||
|
@ -197,7 +199,8 @@ pub enum PaletteType {
|
||||||
pub enum Palette {
|
pub enum Palette {
|
||||||
/// ID of the corresponding entry in its global palette
|
/// ID of the corresponding entry in its global palette
|
||||||
SingleValue(u32),
|
SingleValue(u32),
|
||||||
// in vanilla this keeps a `size` field that might be less than the length, but i'm not sure it's actually needed?
|
// in vanilla this keeps a `size` field that might be less than the length, but i'm not sure
|
||||||
|
// it's actually needed?
|
||||||
Linear(Vec<u32>),
|
Linear(Vec<u32>),
|
||||||
Hashmap(Vec<u32>),
|
Hashmap(Vec<u32>),
|
||||||
Global,
|
Global,
|
||||||
|
|
|
@ -11,7 +11,8 @@ use std::{backtrace::Backtrace, fmt::Debug};
|
||||||
use std::{fmt::Formatter, io::Cursor, sync::Arc};
|
use std::{fmt::Formatter, io::Cursor, sync::Arc};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
/// A world is a collection of chunks and entities. They're called "levels" in Minecraft's source code.
|
/// A world is a collection of chunks and entities. They're called "levels" in
|
||||||
|
/// Minecraft's source code.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct World {
|
pub struct World {
|
||||||
// we just need to keep a strong reference to `shared` so it doesn't get
|
// we just need to keep a strong reference to `shared` so it doesn't get
|
||||||
|
@ -22,7 +23,8 @@ pub struct World {
|
||||||
pub entity_storage: PartialEntityStorage,
|
pub entity_storage: PartialEntityStorage,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A world where the chunks are stored as weak pointers. This is used for shared worlds.
|
/// A world where the chunks are stored as weak pointers. This is used for
|
||||||
|
/// shared worlds.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct WeakWorld {
|
pub struct WeakWorld {
|
||||||
pub chunk_storage: Arc<RwLock<WeakChunkStorage>>,
|
pub chunk_storage: Arc<RwLock<WeakChunkStorage>>,
|
||||||
|
|
|
@ -38,7 +38,8 @@ const WALK_ONE_BLOCK_COST: f32 = 1.0;
|
||||||
|
|
||||||
pub trait Move {
|
pub trait Move {
|
||||||
fn cost(&self, world: &World, node: &Node) -> f32;
|
fn cost(&self, world: &World, node: &Node) -> f32;
|
||||||
/// Returns by how much the entity's position should be changed when this move is executed.
|
/// Returns by how much the entity's position should be changed when this
|
||||||
|
/// move is executed.
|
||||||
fn offset(&self) -> BlockPos;
|
fn offset(&self) -> BlockPos;
|
||||||
fn next_node(&self, node: &Node) -> Node {
|
fn next_node(&self, node: &Node) -> Node {
|
||||||
Node {
|
Node {
|
||||||
|
|
|
@ -20,7 +20,8 @@ pub struct MTDStarLite<
|
||||||
PredecessorsFn: Fn(&N) -> Vec<Edge<N, W>>,
|
PredecessorsFn: Fn(&N) -> Vec<Edge<N, W>>,
|
||||||
SuccessFn: Fn(&N) -> bool,
|
SuccessFn: Fn(&N) -> bool,
|
||||||
> {
|
> {
|
||||||
/// Returns a rough estimate of how close we are to the goal. Lower = closer.
|
/// Returns a rough estimate of how close we are to the goal. Lower =
|
||||||
|
/// closer.
|
||||||
pub heuristic: HeuristicFn,
|
pub heuristic: HeuristicFn,
|
||||||
/// Returns the nodes that can be reached from the given node.
|
/// Returns the nodes that can be reached from the given node.
|
||||||
pub successors: SuccessorsFn,
|
pub successors: SuccessorsFn,
|
||||||
|
@ -29,7 +30,8 @@ pub struct MTDStarLite<
|
||||||
/// can be the same as `successors`.
|
/// can be the same as `successors`.
|
||||||
pub predecessors: PredecessorsFn,
|
pub predecessors: PredecessorsFn,
|
||||||
/// Returns true if the given node is at the goal.
|
/// Returns true if the given node is at the goal.
|
||||||
/// A simple implementation is to check if the given node is equal to the goal.
|
/// A simple implementation is to check if the given node is equal to the
|
||||||
|
/// goal.
|
||||||
pub success: SuccessFn,
|
pub success: SuccessFn,
|
||||||
|
|
||||||
start: N,
|
start: N,
|
||||||
|
@ -43,7 +45,8 @@ pub struct MTDStarLite<
|
||||||
node_states: HashMap<N, NodeState<N, W>>,
|
node_states: HashMap<N, NodeState<N, W>>,
|
||||||
updated_edge_costs: Vec<ChangedEdge<N, W>>,
|
updated_edge_costs: Vec<ChangedEdge<N, W>>,
|
||||||
|
|
||||||
/// This only exists so it can be referenced by `state()` when there's no state.
|
/// This only exists so it can be referenced by `state()` when there's no
|
||||||
|
/// state.
|
||||||
default_state: NodeState<N, W>,
|
default_state: NodeState<N, W>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//! The Azalea prelude. Things that are necessary for a bare-bones bot are re-exported here.
|
//! The Azalea prelude. Things that are necessary for a bare-bones bot are
|
||||||
|
//! re-exported here.
|
||||||
|
|
||||||
pub use crate::bot::BotTrait;
|
pub use crate::bot::BotTrait;
|
||||||
pub use crate::pathfinder::Trait;
|
pub use crate::pathfinder::Trait;
|
||||||
|
|
|
@ -86,8 +86,8 @@ pub enum StartError {
|
||||||
Join(#[from] azalea_client::JoinError),
|
Join(#[from] azalea_client::JoinError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Join a server and start handling events. This function will run forever until
|
/// Join a server and start handling events. This function will run forever
|
||||||
/// it gets disconnected from the server.
|
/// until it gets disconnected from the server.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
|
@ -111,7 +111,8 @@ impl SwarmState {
|
||||||
where
|
where
|
||||||
S: Send + Sync + Clone + 'static,
|
S: Send + Sync + Clone + 'static,
|
||||||
{
|
{
|
||||||
// it should never be locked unless we reused the same plugin for two swarms (bad)
|
// it should never be locked unless we reused the same plugin for two swarms
|
||||||
|
// (bad)
|
||||||
let mut rx = self.rx.lock().await;
|
let mut rx = self.rx.lock().await;
|
||||||
while let Some(m) = rx.recv().await {
|
while let Some(m) = rx.recv().await {
|
||||||
swarm.swarm_tx.send(SwarmEvent::Chat(m)).unwrap();
|
swarm.swarm_tx.send(SwarmEvent::Chat(m)).unwrap();
|
||||||
|
|
|
@ -18,8 +18,8 @@ use std::{future::Future, net::SocketAddr, sync::Arc, time::Duration};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::mpsc::{self, UnboundedSender};
|
use tokio::sync::mpsc::{self, UnboundedSender};
|
||||||
|
|
||||||
/// A helper macro that generates a [`SwarmPlugins`] struct from a list of objects
|
/// A helper macro that generates a [`SwarmPlugins`] struct from a list of
|
||||||
/// that implement [`SwarmPlugin`].
|
/// objects that implement [`SwarmPlugin`].
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// swarm_plugins![azalea_pathfinder::Plugin];
|
/// swarm_plugins![azalea_pathfinder::Plugin];
|
||||||
|
@ -111,7 +111,8 @@ where
|
||||||
pub swarm_state: SS,
|
pub swarm_state: SS,
|
||||||
/// The function that's called every time a bot receives an [`Event`].
|
/// The function that's called every time a bot receives an [`Event`].
|
||||||
pub handle: HandleFn<Fut, S>,
|
pub handle: HandleFn<Fut, S>,
|
||||||
/// The function that's called every time the swarm receives a [`SwarmEvent`].
|
/// The function that's called every time the swarm receives a
|
||||||
|
/// [`SwarmEvent`].
|
||||||
pub swarm_handle: SwarmHandleFn<SwarmFut, S, SS>,
|
pub swarm_handle: SwarmHandleFn<SwarmFut, S, SS>,
|
||||||
|
|
||||||
/// How long we should wait between each bot joining the server. Set to
|
/// How long we should wait between each bot joining the server. Set to
|
||||||
|
@ -342,7 +343,8 @@ impl<S> Swarm<S>
|
||||||
where
|
where
|
||||||
S: Send + Sync + Clone + 'static,
|
S: Send + Sync + Clone + 'static,
|
||||||
{
|
{
|
||||||
/// Add a new account to the swarm. You can remove it later by calling [`Client::disconnect`].
|
/// Add a new account to the swarm. You can remove it later by calling
|
||||||
|
/// [`Client::disconnect`].
|
||||||
pub async fn add(&mut self, account: &Account, state: S) -> Result<Client, JoinError> {
|
pub async fn add(&mut self, account: &Account, state: S) -> Result<Client, JoinError> {
|
||||||
let conn = Connection::new(&self.resolved_address).await?;
|
let conn = Connection::new(&self.resolved_address).await?;
|
||||||
let (conn, game_profile) = Client::handshake(conn, account, &self.address.clone()).await?;
|
let (conn, game_profile) = Client::handshake(conn, account, &self.address.clone()).await?;
|
||||||
|
|
|
@ -13,7 +13,8 @@ type U64Hasher = BuildHasherDefault<NoHashHasher<u64>>;
|
||||||
/// A map of plugin ids to [`SwarmPlugin`] trait objects. The client stores
|
/// A map of plugin ids to [`SwarmPlugin`] trait objects. The client stores
|
||||||
/// this so we can keep the state for our [`Swarm`] plugins.
|
/// this so we can keep the state for our [`Swarm`] plugins.
|
||||||
///
|
///
|
||||||
/// If you're using azalea, you should generate this from the `swarm_plugins!` macro.
|
/// If you're using azalea, you should generate this from the `swarm_plugins!`
|
||||||
|
/// macro.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct SwarmPlugins<S> {
|
pub struct SwarmPlugins<S> {
|
||||||
map: Option<HashMap<TypeId, Box<dyn SwarmPlugin<S>>, U64Hasher>>,
|
map: Option<HashMap<TypeId, Box<dyn SwarmPlugin<S>>, U64Hasher>>,
|
||||||
|
|
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
wrap_comments = true
|
Loading…
Reference in a new issue