mirror of
https://github.com/italicsjenga/valence.git
synced 2024-12-23 22:41:30 +11:00
Rewrite the entity generator
This commit is contained in:
parent
f97c67d42a
commit
2e22946ffc
|
@ -7,9 +7,9 @@ use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{ident, write_to_out_path};
|
use crate::ident;
|
||||||
|
|
||||||
pub fn build() -> anyhow::Result<()> {
|
pub fn build() -> anyhow::Result<TokenStream> {
|
||||||
let blocks = parse_blocks_json()?;
|
let blocks = parse_blocks_json()?;
|
||||||
|
|
||||||
let max_block_state = blocks.iter().map(|b| b.max_state_id).max().unwrap();
|
let max_block_state = blocks.iter().map(|b| b.max_state_id).max().unwrap();
|
||||||
|
@ -297,7 +297,7 @@ pub fn build() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let property_name_count = prop_values.len();
|
let property_name_count = prop_values.len();
|
||||||
|
|
||||||
let finished = quote! {
|
Ok(quote! {
|
||||||
/// Represents the state of a block, not including block entity data such as
|
/// Represents the state of a block, not including block entity data such as
|
||||||
/// the text on a sign, the design on a banner, or the content of a spawner.
|
/// the text on a sign, the design on a banner, or the content of a spawner.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
||||||
|
@ -551,9 +551,7 @@ pub fn build() -> anyhow::Result<()> {
|
||||||
Self::from_bool(b)
|
Self::from_bool(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
|
||||||
write_to_out_path("block.rs", &finished.to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Block {
|
struct Block {
|
||||||
|
|
2833
build/entity.rs
2833
build/entity.rs
File diff suppressed because it is too large
Load diff
66
build/entity_event.rs
Normal file
66
build/entity_event.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use heck::ToPascalCase;
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::ident;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
struct EntityData {
|
||||||
|
statuses: BTreeMap<String, u8>,
|
||||||
|
animations: BTreeMap<String, u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build() -> anyhow::Result<TokenStream> {
|
||||||
|
let entity_data: EntityData =
|
||||||
|
serde_json::from_str(include_str!("../extracted/entity_data.json"))?;
|
||||||
|
|
||||||
|
let mut statuses: Vec<_> = entity_data.statuses.into_iter().collect();
|
||||||
|
statuses.sort_by_key(|(_, id)| *id);
|
||||||
|
|
||||||
|
let mut animations: Vec<_> = entity_data.animations.into_iter().collect();
|
||||||
|
animations.sort_by_key(|(_, id)| *id);
|
||||||
|
|
||||||
|
let event_variants = statuses
|
||||||
|
.iter()
|
||||||
|
.chain(animations.iter())
|
||||||
|
.map(|(name, _)| ident(name.to_pascal_case()));
|
||||||
|
|
||||||
|
let status_arms = statuses.iter().map(|(name, code)| {
|
||||||
|
let name = ident(name.to_pascal_case());
|
||||||
|
quote! {
|
||||||
|
Self::#name => StatusOrAnimation::Status(#code),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let animation_arms = animations.iter().map(|(name, code)| {
|
||||||
|
let name = ident(name.to_pascal_case());
|
||||||
|
quote! {
|
||||||
|
Self::#name => StatusOrAnimation::Animation(#code),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(quote! {
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub enum Event {
|
||||||
|
#(#event_variants,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Event {
|
||||||
|
pub(crate) fn status_or_animation(self) -> StatusOrAnimation {
|
||||||
|
match self {
|
||||||
|
#(#status_arms)*
|
||||||
|
#(#animation_arms)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub(crate) enum StatusOrAnimation {
|
||||||
|
Status(u8),
|
||||||
|
Animation(u8),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -7,35 +7,38 @@ use proc_macro2::{Ident, Span};
|
||||||
|
|
||||||
mod block;
|
mod block;
|
||||||
mod entity;
|
mod entity;
|
||||||
|
mod entity_event;
|
||||||
|
|
||||||
pub fn main() -> anyhow::Result<()> {
|
pub fn main() -> anyhow::Result<()> {
|
||||||
for file in ["blocks.json", "entities.json"] {
|
let generators = [
|
||||||
println!("cargo:rerun-if-changed=data/{file}");
|
(entity::build as fn() -> _, "entity.rs"),
|
||||||
}
|
(entity_event::build, "entity_event.rs"),
|
||||||
|
(block::build, "block.rs"),
|
||||||
|
];
|
||||||
|
|
||||||
block::build()?;
|
let out_dir = env::var_os("OUT_DIR").context("can't get OUT_DIR env var")?;
|
||||||
entity::build()?;
|
|
||||||
|
for (g, file_name) in generators {
|
||||||
|
println!("cargo:rerun-if-changed=extracted/{file_name}");
|
||||||
|
|
||||||
|
let path = Path::new(&out_dir).join(file_name);
|
||||||
|
let code = g()?.to_string();
|
||||||
|
fs::write(&path, &code)?;
|
||||||
|
|
||||||
|
// Format the output for debugging purposes.
|
||||||
|
// Doesn't matter if rustfmt is unavailable.
|
||||||
|
let _ = Command::new("rustfmt").arg(path).output();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ident(s: impl AsRef<str>) -> Ident {
|
fn ident(s: impl AsRef<str>) -> Ident {
|
||||||
let s = s.as_ref().trim();
|
let s = s.as_ref().trim();
|
||||||
if s.starts_with(char::is_numeric) {
|
|
||||||
Ident::new(&format!("_{s}"), Span::call_site())
|
match s.as_bytes() {
|
||||||
} else {
|
// TODO: check for the other rust keywords.
|
||||||
Ident::new(s, Span::call_site())
|
[b'0'..=b'9', ..] | b"type" => Ident::new(&format!("_{s}"), Span::call_site()),
|
||||||
|
_ => Ident::new(s, Span::call_site()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_out_path(file_name: impl AsRef<str>, content: impl AsRef<str>) -> anyhow::Result<()> {
|
|
||||||
let out_dir = env::var_os("OUT_DIR").context("can't get OUT_DIR env var")?;
|
|
||||||
let path = Path::new(&out_dir).join(file_name.as_ref());
|
|
||||||
|
|
||||||
fs::write(&path, &content.as_ref())?;
|
|
||||||
|
|
||||||
// Format the output for debugging purposes.
|
|
||||||
// Doesn't matter if rustfmt is unavailable.
|
|
||||||
let _ = Command::new("rustfmt").arg(path).output();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,12 +3,11 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use valence::block::{BlockPos, BlockState};
|
use valence::block::{BlockPos, BlockState};
|
||||||
use valence::client::Event::{self};
|
use valence::client::{ClientId, Event, GameMode, Hand, InteractWithEntityKind};
|
||||||
use valence::client::{ClientId, GameMode, Hand, InteractWithEntityKind};
|
|
||||||
use valence::config::{Config, ServerListPing};
|
use valence::config::{Config, ServerListPing};
|
||||||
use valence::dimension::DimensionId;
|
use valence::dimension::DimensionId;
|
||||||
use valence::entity::state::Pose;
|
use valence::entity::data::Pose;
|
||||||
use valence::entity::{EntityId, EntityKind, EntityState};
|
use valence::entity::{EntityEnum, EntityId, EntityKind, Event as EntityEvent};
|
||||||
use valence::server::{Server, SharedServer, ShutdownResult};
|
use valence::server::{Server, SharedServer, ShutdownResult};
|
||||||
use valence::text::{Color, TextFormat};
|
use valence::text::{Color, TextFormat};
|
||||||
use valence::{async_trait, Ticks};
|
use valence::{async_trait, Ticks};
|
||||||
|
@ -37,7 +36,7 @@ struct ClientData {
|
||||||
/// The client's player entity.
|
/// The client's player entity.
|
||||||
player: EntityId,
|
player: EntityId,
|
||||||
/// The extra knockback on the first hit while sprinting.
|
/// The extra knockback on the first hit while sprinting.
|
||||||
has_extra_knockback: bool,
|
extra_knockback: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -67,7 +66,6 @@ impl Config for Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn online_mode(&self) -> bool {
|
fn online_mode(&self) -> bool {
|
||||||
// You'll want this to be true on real servers.
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +158,7 @@ impl Config for Game {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
client.data.player = player_id;
|
client.data.player = player_id;
|
||||||
client.data.has_extra_knockback = true;
|
client.data.extra_knockback = true;
|
||||||
|
|
||||||
player.data.client = client_id;
|
player.data.client = client_id;
|
||||||
player.data.last_attack_time = 0;
|
player.data.last_attack_time = 0;
|
||||||
|
@ -181,7 +179,7 @@ impl Config for Game {
|
||||||
while let Some(event) = client.pop_event() {
|
while let Some(event) = client.pop_event() {
|
||||||
match event {
|
match event {
|
||||||
Event::StartSprinting => {
|
Event::StartSprinting => {
|
||||||
client.data.has_extra_knockback = true;
|
client.data.extra_knockback = true;
|
||||||
}
|
}
|
||||||
Event::InteractWithEntity {
|
Event::InteractWithEntity {
|
||||||
id,
|
id,
|
||||||
|
@ -195,21 +193,18 @@ impl Config for Game {
|
||||||
{
|
{
|
||||||
target.data.attacked = true;
|
target.data.attacked = true;
|
||||||
target.data.attacker_pos = client.position();
|
target.data.attacker_pos = client.position();
|
||||||
target.data.extra_knockback = client.data.has_extra_knockback;
|
target.data.extra_knockback = client.data.extra_knockback;
|
||||||
target.data.last_attack_time = current_tick;
|
target.data.last_attack_time = current_tick;
|
||||||
|
|
||||||
client.data.has_extra_knockback = false;
|
client.data.extra_knockback = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::ArmSwing(hand) => {
|
Event::ArmSwing(hand) => {
|
||||||
let player = server.entities.get_mut(client.data.player).unwrap();
|
let player = server.entities.get_mut(client.data.player).unwrap();
|
||||||
|
|
||||||
if let EntityState::Player(e) = &mut player.state {
|
|
||||||
match hand {
|
match hand {
|
||||||
Hand::Main => e.trigger_swing_main_arm(),
|
Hand::Main => player.trigger_event(EntityEvent::SwingMainHand),
|
||||||
Hand::Off => e.trigger_swing_offhand(),
|
Hand::Off => player.trigger_event(EntityEvent::SwingOffHand),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -237,7 +232,7 @@ impl Config for Game {
|
||||||
player.set_pitch(client.pitch());
|
player.set_pitch(client.pitch());
|
||||||
player.set_on_ground(client.on_ground());
|
player.set_on_ground(client.on_ground());
|
||||||
|
|
||||||
if let EntityState::Player(player) = &mut player.state {
|
if let EntityEnum::Player(player) = player.view_mut() {
|
||||||
if client.is_sneaking() {
|
if client.is_sneaking() {
|
||||||
player.set_pose(Pose::Sneaking);
|
player.set_pose(Pose::Sneaking);
|
||||||
} else {
|
} else {
|
||||||
|
@ -266,12 +261,10 @@ impl Config for Game {
|
||||||
|
|
||||||
victim.set_velocity(victim.velocity() / 2.0 + vel.as_());
|
victim.set_velocity(victim.velocity() / 2.0 + vel.as_());
|
||||||
|
|
||||||
if let EntityState::Player(e) = &mut e.state {
|
e.trigger_event(EntityEvent::DamageFromGenericSource);
|
||||||
e.trigger_take_damage();
|
e.trigger_event(EntityEvent::Damage);
|
||||||
e.trigger_hurt();
|
victim.trigger_entity_event(EntityEvent::DamageFromGenericSource);
|
||||||
}
|
victim.trigger_entity_event(EntityEvent::Damage);
|
||||||
victim.player_mut().trigger_take_damage();
|
|
||||||
victim.player_mut().trigger_hurt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ use valence::block::BlockState;
|
||||||
use valence::client::{Event, Hand};
|
use valence::client::{Event, Hand};
|
||||||
use valence::config::{Config, ServerListPing};
|
use valence::config::{Config, ServerListPing};
|
||||||
use valence::dimension::{Dimension, DimensionId};
|
use valence::dimension::{Dimension, DimensionId};
|
||||||
use valence::entity::state::Pose;
|
use valence::entity::data::Pose;
|
||||||
use valence::entity::{EntityId, EntityKind, EntityState};
|
use valence::entity::{EntityEnum, EntityId, EntityKind, Event as EntityEvent};
|
||||||
use valence::server::{Server, SharedServer, ShutdownResult};
|
use valence::server::{Server, SharedServer, ShutdownResult};
|
||||||
use valence::text::{Color, TextFormat};
|
use valence::text::{Color, TextFormat};
|
||||||
use valence::{async_trait, ident};
|
use valence::{async_trait, ident};
|
||||||
|
@ -179,14 +179,10 @@ impl Config for Game {
|
||||||
true;
|
true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::ArmSwing(hand) => {
|
Event::ArmSwing(hand) => match hand {
|
||||||
if let EntityState::Player(e) = &mut player.state {
|
Hand::Main => player.trigger_event(EntityEvent::SwingMainHand),
|
||||||
match hand {
|
Hand::Off => player.trigger_event(EntityEvent::SwingOffHand),
|
||||||
Hand::Main => e.trigger_swing_main_arm(),
|
},
|
||||||
Hand::Off => e.trigger_swing_offhand(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,7 +194,7 @@ impl Config for Game {
|
||||||
player.set_pitch(client.pitch());
|
player.set_pitch(client.pitch());
|
||||||
player.set_on_ground(client.on_ground());
|
player.set_on_ground(client.on_ground());
|
||||||
|
|
||||||
if let EntityState::Player(player) = &mut player.state {
|
if let EntityEnum::Player(player) = player.view_mut() {
|
||||||
if client.is_sneaking() {
|
if client.is_sneaking() {
|
||||||
player.set_pose(Pose::Sneaking);
|
player.set_pose(Pose::Sneaking);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use valence::block::{BlockPos, BlockState};
|
||||||
use valence::client::GameMode;
|
use valence::client::GameMode;
|
||||||
use valence::config::{Config, ServerListPing};
|
use valence::config::{Config, ServerListPing};
|
||||||
use valence::dimension::DimensionId;
|
use valence::dimension::DimensionId;
|
||||||
use valence::entity::{EntityKind, EntityState};
|
use valence::entity::{EntityEnum, EntityKind};
|
||||||
use valence::server::{Server, SharedServer, ShutdownResult};
|
use valence::server::{Server, SharedServer, ShutdownResult};
|
||||||
use valence::spatial_index::RaycastHit;
|
use valence::spatial_index::RaycastHit;
|
||||||
use valence::text::{Color, TextFormat};
|
use valence::text::{Color, TextFormat};
|
||||||
|
@ -166,11 +166,12 @@ impl Config for Game {
|
||||||
});
|
});
|
||||||
|
|
||||||
for (_, e) in server.entities.iter_mut() {
|
for (_, e) in server.entities.iter_mut() {
|
||||||
if let EntityState::Sheep(sheep) = &mut e.state {
|
let intersected = e.data;
|
||||||
if e.data {
|
if let EntityEnum::Sheep(sheep) = &mut e.view_mut() {
|
||||||
sheep.set_sheep_state(5);
|
if intersected {
|
||||||
|
sheep.set_color(5);
|
||||||
} else {
|
} else {
|
||||||
sheep.set_sheep_state(0);
|
sheep.set_color(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.data = false;
|
e.data = false;
|
||||||
|
|
|
@ -117,10 +117,8 @@ impl Config for Game {
|
||||||
);
|
);
|
||||||
|
|
||||||
client.send_message("Welcome to the terrain example!".italic());
|
client.send_message("Welcome to the terrain example!".italic());
|
||||||
client.send_message(
|
client
|
||||||
"This demonstrates how to create infinite procedurally generated terrain."
|
.send_message("Explore this infinite procedurally generated terrain.".italic());
|
||||||
.italic(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.is_disconnected() {
|
if client.is_disconnected() {
|
||||||
|
|
2436
extracted/entities.json
Normal file
2436
extracted/entities.json
Normal file
File diff suppressed because it is too large
Load diff
509
extracted/entity_data.json
Normal file
509
extracted/entity_data.json
Normal file
|
@ -0,0 +1,509 @@
|
||||||
|
{
|
||||||
|
"types": {
|
||||||
|
"allay": 0,
|
||||||
|
"area_effect_cloud": 1,
|
||||||
|
"armor_stand": 2,
|
||||||
|
"arrow": 3,
|
||||||
|
"axolotl": 4,
|
||||||
|
"bat": 5,
|
||||||
|
"bee": 6,
|
||||||
|
"blaze": 7,
|
||||||
|
"boat": 8,
|
||||||
|
"chest_boat": 9,
|
||||||
|
"cat": 10,
|
||||||
|
"cave_spider": 11,
|
||||||
|
"chicken": 12,
|
||||||
|
"cod": 13,
|
||||||
|
"cow": 14,
|
||||||
|
"creeper": 15,
|
||||||
|
"dolphin": 16,
|
||||||
|
"donkey": 17,
|
||||||
|
"dragon_fireball": 18,
|
||||||
|
"drowned": 19,
|
||||||
|
"elder_guardian": 20,
|
||||||
|
"end_crystal": 21,
|
||||||
|
"ender_dragon": 22,
|
||||||
|
"enderman": 23,
|
||||||
|
"endermite": 24,
|
||||||
|
"evoker": 25,
|
||||||
|
"evoker_fangs": 26,
|
||||||
|
"experience_orb": 27,
|
||||||
|
"eye_of_ender": 28,
|
||||||
|
"falling_block": 29,
|
||||||
|
"firework_rocket": 30,
|
||||||
|
"fox": 31,
|
||||||
|
"frog": 32,
|
||||||
|
"ghast": 33,
|
||||||
|
"giant": 34,
|
||||||
|
"glow_item_frame": 35,
|
||||||
|
"glow_squid": 36,
|
||||||
|
"goat": 37,
|
||||||
|
"guardian": 38,
|
||||||
|
"hoglin": 39,
|
||||||
|
"horse": 40,
|
||||||
|
"husk": 41,
|
||||||
|
"illusioner": 42,
|
||||||
|
"iron_golem": 43,
|
||||||
|
"item": 44,
|
||||||
|
"item_frame": 45,
|
||||||
|
"fireball": 46,
|
||||||
|
"leash_knot": 47,
|
||||||
|
"lightning_bolt": 48,
|
||||||
|
"llama": 49,
|
||||||
|
"llama_spit": 50,
|
||||||
|
"magma_cube": 51,
|
||||||
|
"marker": 52,
|
||||||
|
"minecart": 53,
|
||||||
|
"chest_minecart": 54,
|
||||||
|
"command_block_minecart": 55,
|
||||||
|
"furnace_minecart": 56,
|
||||||
|
"hopper_minecart": 57,
|
||||||
|
"spawner_minecart": 58,
|
||||||
|
"tnt_minecart": 59,
|
||||||
|
"mule": 60,
|
||||||
|
"mooshroom": 61,
|
||||||
|
"ocelot": 62,
|
||||||
|
"painting": 63,
|
||||||
|
"panda": 64,
|
||||||
|
"parrot": 65,
|
||||||
|
"phantom": 66,
|
||||||
|
"pig": 67,
|
||||||
|
"piglin": 68,
|
||||||
|
"piglin_brute": 69,
|
||||||
|
"pillager": 70,
|
||||||
|
"polar_bear": 71,
|
||||||
|
"tnt": 72,
|
||||||
|
"pufferfish": 73,
|
||||||
|
"rabbit": 74,
|
||||||
|
"ravager": 75,
|
||||||
|
"salmon": 76,
|
||||||
|
"sheep": 77,
|
||||||
|
"shulker": 78,
|
||||||
|
"shulker_bullet": 79,
|
||||||
|
"silverfish": 80,
|
||||||
|
"skeleton": 81,
|
||||||
|
"skeleton_horse": 82,
|
||||||
|
"slime": 83,
|
||||||
|
"small_fireball": 84,
|
||||||
|
"snow_golem": 85,
|
||||||
|
"snowball": 86,
|
||||||
|
"spectral_arrow": 87,
|
||||||
|
"spider": 88,
|
||||||
|
"squid": 89,
|
||||||
|
"stray": 90,
|
||||||
|
"strider": 91,
|
||||||
|
"tadpole": 92,
|
||||||
|
"egg": 93,
|
||||||
|
"ender_pearl": 94,
|
||||||
|
"experience_bottle": 95,
|
||||||
|
"potion": 96,
|
||||||
|
"trident": 97,
|
||||||
|
"trader_llama": 98,
|
||||||
|
"tropical_fish": 99,
|
||||||
|
"turtle": 100,
|
||||||
|
"vex": 101,
|
||||||
|
"villager": 102,
|
||||||
|
"vindicator": 103,
|
||||||
|
"wandering_trader": 104,
|
||||||
|
"warden": 105,
|
||||||
|
"witch": 106,
|
||||||
|
"wither": 107,
|
||||||
|
"wither_skeleton": 108,
|
||||||
|
"wither_skull": 109,
|
||||||
|
"wolf": 110,
|
||||||
|
"zoglin": 111,
|
||||||
|
"zombie": 112,
|
||||||
|
"zombie_horse": 113,
|
||||||
|
"zombie_villager": 114,
|
||||||
|
"zombified_piglin": 115,
|
||||||
|
"player": 116,
|
||||||
|
"fishing_bobber": 117
|
||||||
|
},
|
||||||
|
"statuses": {
|
||||||
|
"add_sprinting_particles_or_reset_spawner_minecart_spawn_delay": 1,
|
||||||
|
"damage_from_generic_source": 2,
|
||||||
|
"play_death_sound_or_add_projectile_hit_particles": 3,
|
||||||
|
"play_attack_sound": 4,
|
||||||
|
"stop_attack": 5,
|
||||||
|
"add_negative_player_reaction_particles": 6,
|
||||||
|
"add_positive_player_reaction_particles": 7,
|
||||||
|
"shake_off_water": 8,
|
||||||
|
"consume_item": 9,
|
||||||
|
"set_sheep_eat_grass_timer_or_prime_tnt_minecart": 10,
|
||||||
|
"look_at_villager": 11,
|
||||||
|
"add_villager_heart_particles": 12,
|
||||||
|
"add_villager_angry_particles": 13,
|
||||||
|
"add_villager_happy_particles": 14,
|
||||||
|
"add_witch_particles": 15,
|
||||||
|
"play_cure_zombie_villager_sound": 16,
|
||||||
|
"explode_firework_client": 17,
|
||||||
|
"add_breeding_particles": 18,
|
||||||
|
"reset_squid_thrust_timer": 19,
|
||||||
|
"play_spawn_effects": 20,
|
||||||
|
"play_guardian_attack_sound": 21,
|
||||||
|
"use_reduced_debug_info": 22,
|
||||||
|
"use_full_debug_info": 23,
|
||||||
|
"set_op_level_0": 24,
|
||||||
|
"set_op_level_1": 25,
|
||||||
|
"set_op_level_2": 26,
|
||||||
|
"set_op_level_3": 27,
|
||||||
|
"set_op_level_4": 28,
|
||||||
|
"block_with_shield": 29,
|
||||||
|
"break_shield": 30,
|
||||||
|
"pull_hooked_entity": 31,
|
||||||
|
"hit_armor_stand": 32,
|
||||||
|
"damage_from_thorns": 33,
|
||||||
|
"stop_looking_at_villager": 34,
|
||||||
|
"use_totem_of_undying": 35,
|
||||||
|
"damage_from_drowning": 36,
|
||||||
|
"damage_from_fire": 37,
|
||||||
|
"add_dolphin_happy_villager_particles": 38,
|
||||||
|
"stun_ravager": 39,
|
||||||
|
"tame_ocelot_failed": 40,
|
||||||
|
"tame_ocelot_success": 41,
|
||||||
|
"add_splash_particles": 42,
|
||||||
|
"add_cloud_particles": 43,
|
||||||
|
"damage_from_berry_bush": 44,
|
||||||
|
"create_eating_particles": 45,
|
||||||
|
"add_portal_particles": 46,
|
||||||
|
"break_mainhand": 47,
|
||||||
|
"break_offhand": 48,
|
||||||
|
"break_head": 49,
|
||||||
|
"break_chest": 50,
|
||||||
|
"break_legs": 51,
|
||||||
|
"break_feet": 52,
|
||||||
|
"drip_honey": 53,
|
||||||
|
"drip_rich_honey": 54,
|
||||||
|
"swap_hands": 55,
|
||||||
|
"reset_wolf_shake": 56,
|
||||||
|
"damage_from_freezing": 57,
|
||||||
|
"prepare_ram": 58,
|
||||||
|
"finish_ram": 59,
|
||||||
|
"add_death_particles": 60,
|
||||||
|
"ears_twitch": 61,
|
||||||
|
"sonic_boom": 62
|
||||||
|
},
|
||||||
|
"animations": {
|
||||||
|
"swing_main_hand": 0,
|
||||||
|
"damage": 1,
|
||||||
|
"wake_up": 2,
|
||||||
|
"swing_off_hand": 3,
|
||||||
|
"crit": 4,
|
||||||
|
"enchanted_hit": 5
|
||||||
|
},
|
||||||
|
"villager_types": {
|
||||||
|
"desert": 0,
|
||||||
|
"jungle": 1,
|
||||||
|
"plains": 2,
|
||||||
|
"savanna": 3,
|
||||||
|
"snow": 4,
|
||||||
|
"swamp": 5,
|
||||||
|
"taiga": 6
|
||||||
|
},
|
||||||
|
"villager_professions": {
|
||||||
|
"none": 0,
|
||||||
|
"armorer": 1,
|
||||||
|
"butcher": 2,
|
||||||
|
"cartographer": 3,
|
||||||
|
"cleric": 4,
|
||||||
|
"farmer": 5,
|
||||||
|
"fisherman": 6,
|
||||||
|
"fletcher": 7,
|
||||||
|
"leatherworker": 8,
|
||||||
|
"librarian": 9,
|
||||||
|
"mason": 10,
|
||||||
|
"nitwit": 11,
|
||||||
|
"shepherd": 12,
|
||||||
|
"toolsmith": 13,
|
||||||
|
"weaponsmith": 14
|
||||||
|
},
|
||||||
|
"cat_variants": {
|
||||||
|
"tabby": 0,
|
||||||
|
"black": 1,
|
||||||
|
"red": 2,
|
||||||
|
"siamese": 3,
|
||||||
|
"british_shorthair": 4,
|
||||||
|
"calico": 5,
|
||||||
|
"persian": 6,
|
||||||
|
"ragdoll": 7,
|
||||||
|
"white": 8,
|
||||||
|
"jellie": 9,
|
||||||
|
"all_black": 10
|
||||||
|
},
|
||||||
|
"frog_variants": {
|
||||||
|
"temperate": 0,
|
||||||
|
"warm": 1,
|
||||||
|
"cold": 2
|
||||||
|
},
|
||||||
|
"painting_variants": {
|
||||||
|
"kebab": {
|
||||||
|
"id": 0,
|
||||||
|
"width": 16,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"aztec": {
|
||||||
|
"id": 1,
|
||||||
|
"width": 16,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"alban": {
|
||||||
|
"id": 2,
|
||||||
|
"width": 16,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"aztec2": {
|
||||||
|
"id": 3,
|
||||||
|
"width": 16,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"bomb": {
|
||||||
|
"id": 4,
|
||||||
|
"width": 16,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"plant": {
|
||||||
|
"id": 5,
|
||||||
|
"width": 16,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"wasteland": {
|
||||||
|
"id": 6,
|
||||||
|
"width": 16,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"pool": {
|
||||||
|
"id": 7,
|
||||||
|
"width": 32,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"courbet": {
|
||||||
|
"id": 8,
|
||||||
|
"width": 32,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"sea": {
|
||||||
|
"id": 9,
|
||||||
|
"width": 32,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"sunset": {
|
||||||
|
"id": 10,
|
||||||
|
"width": 32,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"creebet": {
|
||||||
|
"id": 11,
|
||||||
|
"width": 32,
|
||||||
|
"height": 16
|
||||||
|
},
|
||||||
|
"wanderer": {
|
||||||
|
"id": 12,
|
||||||
|
"width": 16,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"graham": {
|
||||||
|
"id": 13,
|
||||||
|
"width": 16,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"match": {
|
||||||
|
"id": 14,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"bust": {
|
||||||
|
"id": 15,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"stage": {
|
||||||
|
"id": 16,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"void": {
|
||||||
|
"id": 17,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"skull_and_roses": {
|
||||||
|
"id": 18,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"wither": {
|
||||||
|
"id": 19,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"fighters": {
|
||||||
|
"id": 20,
|
||||||
|
"width": 64,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"pointer": {
|
||||||
|
"id": 21,
|
||||||
|
"width": 64,
|
||||||
|
"height": 64
|
||||||
|
},
|
||||||
|
"pigscene": {
|
||||||
|
"id": 22,
|
||||||
|
"width": 64,
|
||||||
|
"height": 64
|
||||||
|
},
|
||||||
|
"burning_skull": {
|
||||||
|
"id": 23,
|
||||||
|
"width": 64,
|
||||||
|
"height": 64
|
||||||
|
},
|
||||||
|
"skeleton": {
|
||||||
|
"id": 24,
|
||||||
|
"width": 64,
|
||||||
|
"height": 48
|
||||||
|
},
|
||||||
|
"earth": {
|
||||||
|
"id": 25,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"wind": {
|
||||||
|
"id": 26,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"water": {
|
||||||
|
"id": 27,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"fire": {
|
||||||
|
"id": 28,
|
||||||
|
"width": 32,
|
||||||
|
"height": 32
|
||||||
|
},
|
||||||
|
"donkey_kong": {
|
||||||
|
"id": 29,
|
||||||
|
"width": 64,
|
||||||
|
"height": 48
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"facing": {
|
||||||
|
"down": 0,
|
||||||
|
"up": 1,
|
||||||
|
"north": 2,
|
||||||
|
"south": 3,
|
||||||
|
"west": 4,
|
||||||
|
"east": 5
|
||||||
|
},
|
||||||
|
"poses": {
|
||||||
|
"standing": 0,
|
||||||
|
"fall_flying": 1,
|
||||||
|
"sleeping": 2,
|
||||||
|
"swimming": 3,
|
||||||
|
"spin_attack": 4,
|
||||||
|
"crouching": 5,
|
||||||
|
"long_jumping": 6,
|
||||||
|
"dying": 7,
|
||||||
|
"croaking": 8,
|
||||||
|
"using_tongue": 9,
|
||||||
|
"roaring": 10,
|
||||||
|
"sniffing": 11,
|
||||||
|
"emerging": 12,
|
||||||
|
"digging": 13
|
||||||
|
},
|
||||||
|
"particle_types": {
|
||||||
|
"ambient_entity_effect": 0,
|
||||||
|
"angry_villager": 1,
|
||||||
|
"block": 2,
|
||||||
|
"block_marker": 3,
|
||||||
|
"bubble": 4,
|
||||||
|
"cloud": 5,
|
||||||
|
"crit": 6,
|
||||||
|
"damage_indicator": 7,
|
||||||
|
"dragon_breath": 8,
|
||||||
|
"dripping_lava": 9,
|
||||||
|
"falling_lava": 10,
|
||||||
|
"landing_lava": 11,
|
||||||
|
"dripping_water": 12,
|
||||||
|
"falling_water": 13,
|
||||||
|
"dust": 14,
|
||||||
|
"dust_color_transition": 15,
|
||||||
|
"effect": 16,
|
||||||
|
"elder_guardian": 17,
|
||||||
|
"enchanted_hit": 18,
|
||||||
|
"enchant": 19,
|
||||||
|
"end_rod": 20,
|
||||||
|
"entity_effect": 21,
|
||||||
|
"explosion_emitter": 22,
|
||||||
|
"explosion": 23,
|
||||||
|
"sonic_boom": 24,
|
||||||
|
"falling_dust": 25,
|
||||||
|
"firework": 26,
|
||||||
|
"fishing": 27,
|
||||||
|
"flame": 28,
|
||||||
|
"sculk_soul": 29,
|
||||||
|
"sculk_charge": 30,
|
||||||
|
"sculk_charge_pop": 31,
|
||||||
|
"soul_fire_flame": 32,
|
||||||
|
"soul": 33,
|
||||||
|
"flash": 34,
|
||||||
|
"happy_villager": 35,
|
||||||
|
"composter": 36,
|
||||||
|
"heart": 37,
|
||||||
|
"instant_effect": 38,
|
||||||
|
"item": 39,
|
||||||
|
"vibration": 40,
|
||||||
|
"item_slime": 41,
|
||||||
|
"item_snowball": 42,
|
||||||
|
"large_smoke": 43,
|
||||||
|
"lava": 44,
|
||||||
|
"mycelium": 45,
|
||||||
|
"note": 46,
|
||||||
|
"poof": 47,
|
||||||
|
"portal": 48,
|
||||||
|
"rain": 49,
|
||||||
|
"smoke": 50,
|
||||||
|
"sneeze": 51,
|
||||||
|
"spit": 52,
|
||||||
|
"squid_ink": 53,
|
||||||
|
"sweep_attack": 54,
|
||||||
|
"totem_of_undying": 55,
|
||||||
|
"underwater": 56,
|
||||||
|
"splash": 57,
|
||||||
|
"witch": 58,
|
||||||
|
"bubble_pop": 59,
|
||||||
|
"current_down": 60,
|
||||||
|
"bubble_column_up": 61,
|
||||||
|
"nautilus": 62,
|
||||||
|
"dolphin": 63,
|
||||||
|
"campfire_cosy_smoke": 64,
|
||||||
|
"campfire_signal_smoke": 65,
|
||||||
|
"dripping_honey": 66,
|
||||||
|
"falling_honey": 67,
|
||||||
|
"landing_honey": 68,
|
||||||
|
"falling_nectar": 69,
|
||||||
|
"falling_spore_blossom": 70,
|
||||||
|
"ash": 71,
|
||||||
|
"crimson_spore": 72,
|
||||||
|
"warped_spore": 73,
|
||||||
|
"spore_blossom_air": 74,
|
||||||
|
"dripping_obsidian_tear": 75,
|
||||||
|
"falling_obsidian_tear": 76,
|
||||||
|
"landing_obsidian_tear": 77,
|
||||||
|
"reverse_portal": 78,
|
||||||
|
"white_ash": 79,
|
||||||
|
"small_flame": 80,
|
||||||
|
"snowflake": 81,
|
||||||
|
"dripping_dripstone_lava": 82,
|
||||||
|
"falling_dripstone_lava": 83,
|
||||||
|
"dripping_dripstone_water": 84,
|
||||||
|
"falling_dripstone_water": 85,
|
||||||
|
"glow_squid_ink": 86,
|
||||||
|
"glow": 87,
|
||||||
|
"wax_on": 88,
|
||||||
|
"wax_off": 89,
|
||||||
|
"electric_spark": 90,
|
||||||
|
"scrape": 91,
|
||||||
|
"shriek": 92
|
||||||
|
}
|
||||||
|
}
|
|
@ -290,9 +290,16 @@ public class Entities implements Main.Extractor {
|
||||||
|
|
||||||
var parent = entityClass.getSuperclass();
|
var parent = entityClass.getSuperclass();
|
||||||
var hasParent = parent != null && Entity.class.isAssignableFrom(parent);
|
var hasParent = parent != null && Entity.class.isAssignableFrom(parent);
|
||||||
entityJson.addProperty("parent", hasParent ? parent.getSimpleName() : null);
|
|
||||||
|
|
||||||
entityJson.add("translation_key", entityType != null ? new JsonPrimitive(entityType.getTranslationKey()) : null);
|
if (hasParent) {
|
||||||
|
entityJson.addProperty("parent", parent.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityType != null) {
|
||||||
|
entityJson.addProperty("type", Registry.ENTITY_TYPE.getId(entityType).getPath());
|
||||||
|
|
||||||
|
entityJson.add("translation_key", new JsonPrimitive(entityType.getTranslationKey()));
|
||||||
|
}
|
||||||
|
|
||||||
var fieldsJson = new JsonArray();
|
var fieldsJson = new JsonArray();
|
||||||
for (var entityField : entityClass.getDeclaredFields()) {
|
for (var entityField : entityClass.getDeclaredFields()) {
|
||||||
|
|
|
@ -22,6 +22,12 @@ public class EntityData implements Main.Extractor {
|
||||||
public JsonElement extract() throws Exception {
|
public JsonElement extract() throws Exception {
|
||||||
var dataJson = new JsonObject();
|
var dataJson = new JsonObject();
|
||||||
|
|
||||||
|
var typesJson = new JsonObject();
|
||||||
|
for (var type : Registry.ENTITY_TYPE) {
|
||||||
|
typesJson.addProperty(Registry.ENTITY_TYPE.getId(type).getPath(), Registry.ENTITY_TYPE.getRawId(type));
|
||||||
|
}
|
||||||
|
dataJson.add("types", typesJson);
|
||||||
|
|
||||||
var statusesJson = new JsonObject();
|
var statusesJson = new JsonObject();
|
||||||
for (var field : EntityStatuses.class.getDeclaredFields()) {
|
for (var field : EntityStatuses.class.getDeclaredFields()) {
|
||||||
if (field.canAccess(null) && field.get(null) instanceof Byte code) {
|
if (field.canAccess(null) && field.get(null) instanceof Byte code) {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
//! Connections to the server after logging in.
|
//! Connections to the server after logging in.
|
||||||
|
|
||||||
/// Contains the [`Event`] enum and related data types.
|
|
||||||
mod event;
|
|
||||||
use std::collections::{HashSet, VecDeque};
|
use std::collections::{HashSet, VecDeque};
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -18,8 +16,11 @@ use crate::block_pos::BlockPos;
|
||||||
use crate::chunk_pos::ChunkPos;
|
use crate::chunk_pos::ChunkPos;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::dimension::DimensionId;
|
use crate::dimension::DimensionId;
|
||||||
use crate::entity::types::Player;
|
use crate::entity::kinds::Player;
|
||||||
use crate::entity::{velocity_to_packet_units, Entities, Entity, EntityId, EntityKind};
|
use crate::entity::{
|
||||||
|
velocity_to_packet_units, Entities, EntityId, EntityKind, Event as EntityEvent,
|
||||||
|
StatusOrAnimation,
|
||||||
|
};
|
||||||
use crate::player_textures::SignedPlayerTextures;
|
use crate::player_textures::SignedPlayerTextures;
|
||||||
use crate::protocol_inner::packets::play::c2s::{
|
use crate::protocol_inner::packets::play::c2s::{
|
||||||
C2sPlayPacket, DiggingStatus, InteractKind, PlayerCommandId,
|
C2sPlayPacket, DiggingStatus, InteractKind, PlayerCommandId,
|
||||||
|
@ -28,12 +29,12 @@ pub use crate::protocol_inner::packets::play::s2c::SetTitleAnimationTimes as Tit
|
||||||
use crate::protocol_inner::packets::play::s2c::{
|
use crate::protocol_inner::packets::play::s2c::{
|
||||||
Animate, BiomeRegistry, BlockChangeAck, ChatType, ChatTypeChat, ChatTypeNarration,
|
Animate, BiomeRegistry, BlockChangeAck, ChatType, ChatTypeChat, ChatTypeNarration,
|
||||||
ChatTypeRegistry, ChatTypeRegistryEntry, ClearTitles, DimensionTypeRegistry,
|
ChatTypeRegistry, ChatTypeRegistryEntry, ClearTitles, DimensionTypeRegistry,
|
||||||
DimensionTypeRegistryEntry, Disconnect, EntityEvent, ForgetLevelChunk, GameEvent,
|
DimensionTypeRegistryEntry, Disconnect, EntityStatus, ForgetLevelChunk, GameEvent,
|
||||||
GameEventReason, KeepAlive, Login, MoveEntityPosition, MoveEntityPositionAndRotation,
|
GameEventReason, KeepAlive, Login, MoveEntityPosition, MoveEntityPositionAndRotation,
|
||||||
MoveEntityRotation, PlayerPosition, PlayerPositionFlags, RegistryCodec, RemoveEntities,
|
MoveEntityRotation, PlayerPosition, PlayerPositionFlags, RegistryCodec, RemoveEntities,
|
||||||
Respawn, RotateHead, S2cPlayPacket, SetChunkCacheCenter, SetChunkCacheRadius,
|
Respawn, RotateHead, S2cPlayPacket, SetChunkCacheCenter, SetChunkCacheRadius,
|
||||||
SetEntityMetadata, SetEntityMotion, SetSubtitleText, SetTitleText, SpawnPosition, SystemChat,
|
SetEntityMetadata, SetEntityMotion, SetSubtitleText, SetTitleText, SpawnPosition, SystemChat,
|
||||||
TeleportEntity, UpdateAttributes, UpdateAttributesProperty, ENTITY_EVENT_MAX_BOUND,
|
TeleportEntity, UpdateAttributes, UpdateAttributesProperty,
|
||||||
};
|
};
|
||||||
use crate::protocol_inner::{BoundedInt, ByteAngle, Nbt, RawBytes, VarInt};
|
use crate::protocol_inner::{BoundedInt, ByteAngle, Nbt, RawBytes, VarInt};
|
||||||
use crate::server::{C2sPacketChannels, NewClientData, SharedServer};
|
use crate::server::{C2sPacketChannels, NewClientData, SharedServer};
|
||||||
|
@ -43,6 +44,9 @@ use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance};
|
||||||
use crate::world::{WorldId, Worlds};
|
use crate::world::{WorldId, Worlds};
|
||||||
use crate::{ident, Ticks, LIBRARY_NAMESPACE, STANDARD_TPS};
|
use crate::{ident, Ticks, LIBRARY_NAMESPACE, STANDARD_TPS};
|
||||||
|
|
||||||
|
/// Contains the [`Event`] enum and related data types.
|
||||||
|
mod event;
|
||||||
|
|
||||||
/// A container for all [`Client`]s on a [`Server`](crate::server::Server).
|
/// A container for all [`Client`]s on a [`Server`](crate::server::Server).
|
||||||
///
|
///
|
||||||
/// New clients are automatically inserted into this container but
|
/// New clients are automatically inserted into this container but
|
||||||
|
@ -211,6 +215,7 @@ pub struct Client<C: Config> {
|
||||||
flags: ClientFlags,
|
flags: ClientFlags,
|
||||||
/// The data for the client's own player entity.
|
/// The data for the client's own player entity.
|
||||||
player_data: Player,
|
player_data: Player,
|
||||||
|
entity_events: Vec<EntityEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield(u16)]
|
#[bitfield(u16)]
|
||||||
|
@ -280,6 +285,7 @@ impl<C: Config> Client<C> {
|
||||||
.with_modified_spawn_position(true)
|
.with_modified_spawn_position(true)
|
||||||
.with_got_keepalive(true),
|
.with_got_keepalive(true),
|
||||||
player_data: Player::new(),
|
player_data: Player::new(),
|
||||||
|
entity_events: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +528,10 @@ impl<C: Config> Client<C> {
|
||||||
self.events.pop_front()
|
self.events.pop_front()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trigger_entity_event(&mut self, event: EntityEvent) {
|
||||||
|
self.entity_events.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
/// The current view distance of this client measured in chunks.
|
/// The current view distance of this client measured in chunks.
|
||||||
pub fn view_distance(&self) -> u8 {
|
pub fn view_distance(&self) -> u8 {
|
||||||
self.settings
|
self.settings
|
||||||
|
@ -1193,7 +1203,7 @@ impl<C: Config> Client<C> {
|
||||||
if let Some(entity) = entities.get(id) {
|
if let Some(entity) = entities.get(id) {
|
||||||
debug_assert!(entity.kind() != EntityKind::Marker);
|
debug_assert!(entity.kind() != EntityKind::Marker);
|
||||||
if self.new_position.distance(entity.position()) <= view_dist as f64 * 16.0 {
|
if self.new_position.distance(entity.position()) <= view_dist as f64 * 16.0 {
|
||||||
if let Some(meta) = entity.updated_metadata_packet(id) {
|
if let Some(meta) = entity.updated_tracked_data_packet(id) {
|
||||||
send_packet(&mut self.send, meta);
|
send_packet(&mut self.send, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1273,7 +1283,7 @@ impl<C: Config> Client<C> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
send_entity_events(&mut self.send, id, entity);
|
send_entity_events(&mut self.send, id.to_network_id(), entity.events());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1291,7 +1301,7 @@ impl<C: Config> Client<C> {
|
||||||
|
|
||||||
// Update the client's own player metadata.
|
// Update the client's own player metadata.
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
self.player_data.updated_metadata(&mut data);
|
self.player_data.updated_tracked_data(&mut data);
|
||||||
|
|
||||||
if !data.is_empty() {
|
if !data.is_empty() {
|
||||||
data.push(0xff);
|
data.push(0xff);
|
||||||
|
@ -1320,29 +1330,18 @@ impl<C: Config> Client<C> {
|
||||||
.expect("should not be a marker entity"),
|
.expect("should not be a marker entity"),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(meta) = entity.initial_metadata_packet(id) {
|
if let Some(meta) = entity.initial_tracked_data_packet(id) {
|
||||||
self.send_packet(meta);
|
self.send_packet(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
send_entity_events(&mut self.send, id, entity);
|
send_entity_events(&mut self.send, id.to_network_id(), entity.events());
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
for &code in self.player_data.event_codes() {
|
send_entity_events(&mut self.send, 0, &self.entity_events);
|
||||||
if code <= ENTITY_EVENT_MAX_BOUND as u8 {
|
self.entity_events.clear();
|
||||||
send_packet(
|
|
||||||
&mut self.send,
|
|
||||||
EntityEvent {
|
|
||||||
entity_id: 0,
|
|
||||||
entity_status: BoundedInt(code),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Don't bother sending animations for self since it shouldn't have
|
|
||||||
// any effect.
|
|
||||||
}
|
|
||||||
|
|
||||||
self.player_data.clear_modifications();
|
self.player_data.clear_modifications();
|
||||||
self.old_position = self.new_position;
|
self.old_position = self.new_position;
|
||||||
|
@ -1366,24 +1365,23 @@ fn send_packet(send_opt: &mut SendOpt, pkt: impl Into<S2cPlayPacket>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_entity_events<C: Config>(send_opt: &mut SendOpt, id: EntityId, entity: &Entity<C>) {
|
fn send_entity_events(send_opt: &mut SendOpt, entity_id: i32, events: &[EntityEvent]) {
|
||||||
for &code in entity.state.event_codes() {
|
for &event in events {
|
||||||
if code <= ENTITY_EVENT_MAX_BOUND as u8 {
|
match event.status_or_animation() {
|
||||||
send_packet(
|
StatusOrAnimation::Status(code) => send_packet(
|
||||||
send_opt,
|
send_opt,
|
||||||
EntityEvent {
|
EntityStatus {
|
||||||
entity_id: id.to_network_id(),
|
entity_id,
|
||||||
entity_status: BoundedInt(code),
|
entity_status: code,
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
} else {
|
StatusOrAnimation::Animation(code) => send_packet(
|
||||||
send_packet(
|
|
||||||
send_opt,
|
send_opt,
|
||||||
Animate {
|
Animate {
|
||||||
entity_id: VarInt(id.to_network_id()),
|
entity_id: VarInt(entity_id),
|
||||||
animation: BoundedInt(code - ENTITY_EVENT_MAX_BOUND as u8 - 1),
|
animation: code,
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
317
src/entity.rs
317
src/entity.rs
|
@ -1,16 +1,13 @@
|
||||||
//! Dynamic actors in a world.
|
//! Dynamic actors in a world.
|
||||||
|
|
||||||
pub mod state;
|
|
||||||
pub mod types;
|
|
||||||
|
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
use bitfield_struct::bitfield;
|
use bitfield_struct::bitfield;
|
||||||
|
pub use kinds::{EntityEnum, EntityKind};
|
||||||
use rayon::iter::ParallelIterator;
|
use rayon::iter::ParallelIterator;
|
||||||
pub use types::{EntityKind, EntityState};
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use vek::{Aabb, Vec3};
|
use vek::{Aabb, Vec3};
|
||||||
|
|
||||||
|
@ -24,6 +21,11 @@ use crate::util::aabb_from_bottom_and_size;
|
||||||
use crate::world::WorldId;
|
use crate::world::WorldId;
|
||||||
use crate::STANDARD_TPS;
|
use crate::STANDARD_TPS;
|
||||||
|
|
||||||
|
pub mod data;
|
||||||
|
pub mod kinds;
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/entity_event.rs"));
|
||||||
|
|
||||||
/// A container for all [`Entity`]s on a [`Server`](crate::server::Server).
|
/// A container for all [`Entity`]s on a [`Server`](crate::server::Server).
|
||||||
///
|
///
|
||||||
/// # Spawning Player Entities
|
/// # Spawning Player Entities
|
||||||
|
@ -72,7 +74,8 @@ impl<C: Config> Entities<C> {
|
||||||
Entry::Vacant(ve) => {
|
Entry::Vacant(ve) => {
|
||||||
let (k, e) = self.sm.insert(Entity {
|
let (k, e) = self.sm.insert(Entity {
|
||||||
data,
|
data,
|
||||||
state: EntityState::new(kind),
|
variants: EntityEnum::new(kind),
|
||||||
|
events: Vec::new(),
|
||||||
flags: EntityFlags(0),
|
flags: EntityFlags(0),
|
||||||
world: WorldId::NULL,
|
world: WorldId::NULL,
|
||||||
new_position: Vec3::default(),
|
new_position: Vec3::default(),
|
||||||
|
@ -197,7 +200,8 @@ impl<C: Config> Entities<C> {
|
||||||
pub(crate) fn update(&mut self) {
|
pub(crate) fn update(&mut self) {
|
||||||
for (_, e) in self.iter_mut() {
|
for (_, e) in self.iter_mut() {
|
||||||
e.old_position = e.new_position;
|
e.old_position = e.new_position;
|
||||||
e.state.clear_modifications();
|
e.variants.clear_modifications();
|
||||||
|
e.events.clear();
|
||||||
|
|
||||||
e.flags.set_yaw_or_pitch_modified(false);
|
e.flags.set_yaw_or_pitch_modified(false);
|
||||||
e.flags.set_head_yaw_modified(false);
|
e.flags.set_head_yaw_modified(false);
|
||||||
|
@ -239,9 +243,9 @@ impl EntityId {
|
||||||
pub struct Entity<C: Config> {
|
pub struct Entity<C: Config> {
|
||||||
/// Custom data.
|
/// Custom data.
|
||||||
pub data: C::EntityData,
|
pub data: C::EntityData,
|
||||||
/// Kind-specific state for this entity.
|
variants: EntityEnum,
|
||||||
pub state: EntityState,
|
|
||||||
flags: EntityFlags,
|
flags: EntityFlags,
|
||||||
|
events: Vec<Event>,
|
||||||
world: WorldId,
|
world: WorldId,
|
||||||
new_position: Vec3<f64>,
|
new_position: Vec3<f64>,
|
||||||
old_position: Vec3<f64>,
|
old_position: Vec3<f64>,
|
||||||
|
@ -267,9 +271,25 @@ impl<C: Config> Entity<C> {
|
||||||
self.flags
|
self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn view(&self) -> &EntityEnum {
|
||||||
|
&self.variants
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view_mut(&mut self) -> &mut EntityEnum {
|
||||||
|
&mut self.variants
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the [`EntityKind`] of this entity.
|
/// Gets the [`EntityKind`] of this entity.
|
||||||
pub fn kind(&self) -> EntityKind {
|
pub fn kind(&self) -> EntityKind {
|
||||||
self.state.kind()
|
self.variants.kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trigger_event(&mut self, event: Event) {
|
||||||
|
self.events.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn events(&self) -> &[Event] {
|
||||||
|
&self.events
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the [`WorldId`](crate::world::WorldId) of the world this entity is
|
/// Gets the [`WorldId`](crate::world::WorldId) of the world this entity is
|
||||||
|
@ -387,18 +407,18 @@ impl<C: Config> Entity<C> {
|
||||||
///
|
///
|
||||||
/// [interact event]: crate::client::Event::InteractWithEntity
|
/// [interact event]: crate::client::Event::InteractWithEntity
|
||||||
pub fn hitbox(&self) -> Aabb<f64> {
|
pub fn hitbox(&self) -> Aabb<f64> {
|
||||||
let dims = match &self.state {
|
let dims = match &self.variants {
|
||||||
EntityState::Allay(_) => [0.6, 0.35, 0.6],
|
EntityEnum::Allay(_) => [0.6, 0.35, 0.6],
|
||||||
EntityState::ChestBoat(_) => [1.375, 0.5625, 1.375],
|
EntityEnum::ChestBoat(_) => [1.375, 0.5625, 1.375],
|
||||||
EntityState::Frog(_) => [0.5, 0.5, 0.5],
|
EntityEnum::Frog(_) => [0.5, 0.5, 0.5],
|
||||||
EntityState::Tadpole(_) => [0.4, 0.3, 0.4],
|
EntityEnum::Tadpole(_) => [0.4, 0.3, 0.4],
|
||||||
EntityState::Warden(_) => [0.9, 2.9, 0.9],
|
EntityEnum::Warden(_) => [0.9, 2.9, 0.9],
|
||||||
EntityState::AreaEffectCloud(e) => [
|
EntityEnum::AreaEffectCloud(e) => [
|
||||||
e.get_radius() as f64 * 2.0,
|
e.get_radius() as f64 * 2.0,
|
||||||
0.5,
|
0.5,
|
||||||
e.get_radius() as f64 * 2.0,
|
e.get_radius() as f64 * 2.0,
|
||||||
],
|
],
|
||||||
EntityState::ArmorStand(e) => {
|
EntityEnum::ArmorStand(e) => {
|
||||||
if e.get_marker() {
|
if e.get_marker() {
|
||||||
[0.0, 0.0, 0.0]
|
[0.0, 0.0, 0.0]
|
||||||
} else if e.get_small() {
|
} else if e.get_small() {
|
||||||
|
@ -407,160 +427,171 @@ impl<C: Config> Entity<C> {
|
||||||
[0.5, 1.975, 0.5]
|
[0.5, 1.975, 0.5]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntityState::Arrow(_) => [0.5, 0.5, 0.5],
|
EntityEnum::Arrow(_) => [0.5, 0.5, 0.5],
|
||||||
EntityState::Axolotl(_) => [1.3, 0.6, 1.3],
|
EntityEnum::Axolotl(_) => [1.3, 0.6, 1.3],
|
||||||
EntityState::Bat(_) => [0.5, 0.9, 0.5],
|
EntityEnum::Bat(_) => [0.5, 0.9, 0.5],
|
||||||
EntityState::Bee(_) => [0.7, 0.6, 0.7], // TODO: baby size?
|
EntityEnum::Bee(_) => [0.7, 0.6, 0.7], // TODO: baby size?
|
||||||
EntityState::Blaze(_) => [0.6, 1.8, 0.6],
|
EntityEnum::Blaze(_) => [0.6, 1.8, 0.6],
|
||||||
EntityState::Boat(_) => [1.375, 0.5625, 1.375],
|
EntityEnum::Boat(_) => [1.375, 0.5625, 1.375],
|
||||||
EntityState::Cat(_) => [0.6, 0.7, 0.6],
|
EntityEnum::Cat(_) => [0.6, 0.7, 0.6],
|
||||||
EntityState::CaveSpider(_) => [0.7, 0.5, 0.7],
|
EntityEnum::CaveSpider(_) => [0.7, 0.5, 0.7],
|
||||||
EntityState::Chicken(_) => [0.4, 0.7, 0.4], // TODO: baby size?
|
EntityEnum::Chicken(_) => [0.4, 0.7, 0.4], // TODO: baby size?
|
||||||
EntityState::Cod(_) => [0.5, 0.3, 0.5],
|
EntityEnum::Cod(_) => [0.5, 0.3, 0.5],
|
||||||
EntityState::Cow(_) => [0.9, 1.4, 0.9], // TODO: baby size?
|
EntityEnum::Cow(_) => [0.9, 1.4, 0.9], // TODO: baby size?
|
||||||
EntityState::Creeper(_) => [0.6, 1.7, 0.6],
|
EntityEnum::Creeper(_) => [0.6, 1.7, 0.6],
|
||||||
EntityState::Dolphin(_) => [0.9, 0.6, 0.9],
|
EntityEnum::Dolphin(_) => [0.9, 0.6, 0.9],
|
||||||
EntityState::Donkey(_) => [1.5, 1.39648, 1.5], // TODO: baby size?
|
EntityEnum::Donkey(_) => [1.5, 1.39648, 1.5], // TODO: baby size?
|
||||||
EntityState::DragonFireball(_) => [1.0, 1.0, 1.0],
|
EntityEnum::DragonFireball(_) => [1.0, 1.0, 1.0],
|
||||||
EntityState::Drowned(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
EntityEnum::Drowned(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
||||||
EntityState::ElderGuardian(_) => [1.9975, 1.9975, 1.9975],
|
EntityEnum::ElderGuardian(_) => [1.9975, 1.9975, 1.9975],
|
||||||
EntityState::EndCrystal(_) => [2.0, 2.0, 2.0],
|
EntityEnum::EndCrystal(_) => [2.0, 2.0, 2.0],
|
||||||
EntityState::EnderDragon(_) => [16.0, 8.0, 16.0],
|
EntityEnum::EnderDragon(_) => [16.0, 8.0, 16.0],
|
||||||
EntityState::Enderman(_) => [0.6, 2.9, 0.6],
|
EntityEnum::Enderman(_) => [0.6, 2.9, 0.6],
|
||||||
EntityState::Endermite(_) => [0.4, 0.3, 0.4],
|
EntityEnum::Endermite(_) => [0.4, 0.3, 0.4],
|
||||||
EntityState::Evoker(_) => [0.6, 1.95, 0.6],
|
EntityEnum::Evoker(_) => [0.6, 1.95, 0.6],
|
||||||
EntityState::EvokerFangs(_) => [0.5, 0.8, 0.5],
|
EntityEnum::EvokerFangs(_) => [0.5, 0.8, 0.5],
|
||||||
EntityState::ExperienceOrb(_) => [0.5, 0.5, 0.5],
|
EntityEnum::ExperienceOrb(_) => [0.5, 0.5, 0.5],
|
||||||
EntityState::EyeOfEnder(_) => [0.25, 0.25, 0.25],
|
EntityEnum::EyeOfEnder(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::FallingBlock(_) => [0.98, 0.98, 0.98],
|
EntityEnum::FallingBlock(_) => [0.98, 0.98, 0.98],
|
||||||
EntityState::FireworkRocket(_) => [0.25, 0.25, 0.25],
|
EntityEnum::FireworkRocket(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::Fox(_) => [0.6, 0.7, 0.6], // TODO: baby size?
|
EntityEnum::Fox(_) => [0.6, 0.7, 0.6], // TODO: baby size?
|
||||||
EntityState::Ghast(_) => [4.0, 4.0, 4.0],
|
EntityEnum::Ghast(_) => [4.0, 4.0, 4.0],
|
||||||
EntityState::Giant(_) => [3.6, 12.0, 3.6],
|
EntityEnum::Giant(_) => [3.6, 12.0, 3.6],
|
||||||
EntityState::GlowItemFrame(_) => todo!("account for rotation"),
|
EntityEnum::GlowItemFrame(_) => todo!("account for rotation"),
|
||||||
EntityState::GlowSquid(_) => [0.8, 0.8, 0.8],
|
EntityEnum::GlowSquid(_) => [0.8, 0.8, 0.8],
|
||||||
EntityState::Goat(_) => [1.3, 0.9, 1.3], // TODO: baby size?
|
EntityEnum::Goat(_) => [1.3, 0.9, 1.3], // TODO: baby size?
|
||||||
EntityState::Guardian(_) => [0.85, 0.85, 0.85],
|
EntityEnum::Guardian(_) => [0.85, 0.85, 0.85],
|
||||||
EntityState::Hoglin(_) => [1.39648, 1.4, 1.39648], // TODO: baby size?
|
EntityEnum::Hoglin(_) => [1.39648, 1.4, 1.39648], // TODO: baby size?
|
||||||
EntityState::Horse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
|
EntityEnum::Horse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
|
||||||
EntityState::Husk(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
EntityEnum::Husk(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
||||||
EntityState::Illusioner(_) => [0.6, 1.95, 0.6],
|
EntityEnum::Illusioner(_) => [0.6, 1.95, 0.6],
|
||||||
EntityState::IronGolem(_) => [1.4, 2.7, 1.4],
|
EntityEnum::IronGolem(_) => [1.4, 2.7, 1.4],
|
||||||
EntityState::Item(_) => [0.25, 0.25, 0.25],
|
EntityEnum::Item(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::ItemFrame(_) => todo!("account for rotation"),
|
EntityEnum::ItemFrame(_) => todo!("account for rotation"),
|
||||||
EntityState::Fireball(_) => [1.0, 1.0, 1.0],
|
EntityEnum::Fireball(_) => [1.0, 1.0, 1.0],
|
||||||
EntityState::LeashKnot(_) => [0.375, 0.5, 0.375],
|
EntityEnum::LeashKnot(_) => [0.375, 0.5, 0.375],
|
||||||
EntityState::LightningBolt(_) => [0.0, 0.0, 0.0],
|
EntityEnum::Lightning(_) => [0.0, 0.0, 0.0],
|
||||||
EntityState::Llama(_) => [0.9, 1.87, 0.9], // TODO: baby size?
|
EntityEnum::Llama(_) => [0.9, 1.87, 0.9], // TODO: baby size?
|
||||||
EntityState::LlamaSpit(_) => [0.25, 0.25, 0.25],
|
EntityEnum::LlamaSpit(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::MagmaCube(e) => {
|
EntityEnum::MagmaCube(e) => {
|
||||||
let s = e.get_size() as f64 * 0.51000005;
|
let s = e.get_slime_size() as f64 * 0.51000005;
|
||||||
[s, s, s]
|
[s, s, s]
|
||||||
}
|
}
|
||||||
EntityState::Marker(_) => [0.0, 0.0, 0.0],
|
EntityEnum::Marker(_) => [0.0, 0.0, 0.0],
|
||||||
EntityState::Minecart(_) => [0.98, 0.7, 0.98],
|
EntityEnum::Minecart(_) => [0.98, 0.7, 0.98],
|
||||||
EntityState::ChestMinecart(_) => [0.98, 0.7, 0.98],
|
EntityEnum::ChestMinecart(_) => [0.98, 0.7, 0.98],
|
||||||
EntityState::CommandBlockMinecart(_) => [0.98, 0.7, 0.98],
|
EntityEnum::CommandBlockMinecart(_) => [0.98, 0.7, 0.98],
|
||||||
EntityState::FurnaceMinecart(_) => [0.98, 0.7, 0.98],
|
EntityEnum::FurnaceMinecart(_) => [0.98, 0.7, 0.98],
|
||||||
EntityState::HopperMinecart(_) => [0.98, 0.7, 0.98],
|
EntityEnum::HopperMinecart(_) => [0.98, 0.7, 0.98],
|
||||||
EntityState::SpawnerMinecart(_) => [0.98, 0.7, 0.98],
|
EntityEnum::SpawnerMinecart(_) => [0.98, 0.7, 0.98],
|
||||||
EntityState::TntMinecart(_) => [0.98, 0.7, 0.98],
|
EntityEnum::TntMinecart(_) => [0.98, 0.7, 0.98],
|
||||||
EntityState::Mule(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
|
EntityEnum::Mule(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
|
||||||
EntityState::Mooshroom(_) => [0.9, 1.4, 0.9], // TODO: baby size?
|
EntityEnum::Mooshroom(_) => [0.9, 1.4, 0.9], // TODO: baby size?
|
||||||
EntityState::Ocelot(_) => [0.6, 0.7, 0.6], // TODO: baby size?
|
EntityEnum::Ocelot(_) => [0.6, 0.7, 0.6], // TODO: baby size?
|
||||||
EntityState::Painting(_) => todo!("account for rotation and type"),
|
EntityEnum::Painting(_) => todo!("account for rotation and type"),
|
||||||
EntityState::Panda(_) => [0.6, 0.7, 0.6], // TODO: baby size?
|
EntityEnum::Panda(_) => [0.6, 0.7, 0.6], // TODO: baby size?
|
||||||
EntityState::Parrot(_) => [0.5, 0.9, 0.5],
|
EntityEnum::Parrot(_) => [0.5, 0.9, 0.5],
|
||||||
EntityState::Phantom(_) => [0.9, 0.5, 0.9],
|
EntityEnum::Phantom(_) => [0.9, 0.5, 0.9],
|
||||||
EntityState::Pig(_) => [0.9, 0.9, 0.9], // TODO: baby size?
|
EntityEnum::Pig(_) => [0.9, 0.9, 0.9], // TODO: baby size?
|
||||||
EntityState::Piglin(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
EntityEnum::Piglin(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
||||||
EntityState::PiglinBrute(_) => [0.6, 1.95, 0.6],
|
EntityEnum::PiglinBrute(_) => [0.6, 1.95, 0.6],
|
||||||
EntityState::Pillager(_) => [0.6, 1.95, 0.6],
|
EntityEnum::Pillager(_) => [0.6, 1.95, 0.6],
|
||||||
EntityState::PolarBear(_) => [1.4, 1.4, 1.4], // TODO: baby size?
|
EntityEnum::PolarBear(_) => [1.4, 1.4, 1.4], // TODO: baby size?
|
||||||
EntityState::Tnt(_) => [0.98, 0.98, 0.98],
|
EntityEnum::Tnt(_) => [0.98, 0.98, 0.98],
|
||||||
EntityState::Pufferfish(_) => [0.7, 0.7, 0.7],
|
EntityEnum::Pufferfish(_) => [0.7, 0.7, 0.7],
|
||||||
EntityState::Rabbit(_) => [0.4, 0.5, 0.4], // TODO: baby size?
|
EntityEnum::Rabbit(_) => [0.4, 0.5, 0.4], // TODO: baby size?
|
||||||
EntityState::Ravager(_) => [1.95, 2.2, 1.95],
|
EntityEnum::Ravager(_) => [1.95, 2.2, 1.95],
|
||||||
EntityState::Salmon(_) => [0.7, 0.4, 0.7],
|
EntityEnum::Salmon(_) => [0.7, 0.4, 0.7],
|
||||||
EntityState::Sheep(_) => [0.9, 1.3, 0.9], // TODO: baby size?
|
EntityEnum::Sheep(_) => [0.9, 1.3, 0.9], // TODO: baby size?
|
||||||
EntityState::Shulker(_) => [1.0, 1.0, 1.0], // TODO: how is height calculated?
|
EntityEnum::Shulker(_) => [1.0, 1.0, 1.0], // TODO: how is height calculated?
|
||||||
EntityState::ShulkerBullet(_) => [0.3125, 0.3125, 0.3125],
|
EntityEnum::ShulkerBullet(_) => [0.3125, 0.3125, 0.3125],
|
||||||
EntityState::Silverfish(_) => [0.4, 0.3, 0.4],
|
EntityEnum::Silverfish(_) => [0.4, 0.3, 0.4],
|
||||||
EntityState::Skeleton(_) => [0.6, 1.99, 0.6],
|
EntityEnum::Skeleton(_) => [0.6, 1.99, 0.6],
|
||||||
EntityState::SkeletonHorse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
|
EntityEnum::SkeletonHorse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
|
||||||
EntityState::Slime(e) => {
|
EntityEnum::Slime(e) => {
|
||||||
let s = 0.51000005 * e.get_size() as f64;
|
let s = 0.51000005 * e.get_slime_size() as f64;
|
||||||
[s, s, s]
|
[s, s, s]
|
||||||
}
|
}
|
||||||
EntityState::SmallFireball(_) => [0.3125, 0.3125, 0.3125],
|
EntityEnum::SmallFireball(_) => [0.3125, 0.3125, 0.3125],
|
||||||
EntityState::SnowGolem(_) => [0.7, 1.9, 0.7],
|
EntityEnum::SnowGolem(_) => [0.7, 1.9, 0.7],
|
||||||
EntityState::Snowball(_) => [0.25, 0.25, 0.25],
|
EntityEnum::Snowball(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::SpectralArrow(_) => [0.5, 0.5, 0.5],
|
EntityEnum::SpectralArrow(_) => [0.5, 0.5, 0.5],
|
||||||
EntityState::Spider(_) => [1.4, 0.9, 1.4],
|
EntityEnum::Spider(_) => [1.4, 0.9, 1.4],
|
||||||
EntityState::Squid(_) => [0.8, 0.8, 0.8],
|
EntityEnum::Squid(_) => [0.8, 0.8, 0.8],
|
||||||
EntityState::Stray(_) => [0.6, 1.99, 0.6],
|
EntityEnum::Stray(_) => [0.6, 1.99, 0.6],
|
||||||
EntityState::Strider(_) => [0.9, 1.7, 0.9], // TODO: baby size?
|
EntityEnum::Strider(_) => [0.9, 1.7, 0.9], // TODO: baby size?
|
||||||
EntityState::Egg(_) => [0.25, 0.25, 0.25],
|
EntityEnum::Egg(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::EnderPearl(_) => [0.25, 0.25, 0.25],
|
EntityEnum::EnderPearl(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::ExperienceBottle(_) => [0.25, 0.25, 0.25],
|
EntityEnum::ExperienceBottle(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::Potion(_) => [0.25, 0.25, 0.25],
|
EntityEnum::Potion(_) => [0.25, 0.25, 0.25],
|
||||||
EntityState::Trident(_) => [0.5, 0.5, 0.5],
|
EntityEnum::Trident(_) => [0.5, 0.5, 0.5],
|
||||||
EntityState::TraderLlama(_) => [0.9, 1.87, 0.9],
|
EntityEnum::TraderLlama(_) => [0.9, 1.87, 0.9],
|
||||||
EntityState::TropicalFish(_) => [0.5, 0.4, 0.5],
|
EntityEnum::TropicalFish(_) => [0.5, 0.4, 0.5],
|
||||||
EntityState::Turtle(_) => [1.2, 0.4, 1.2], // TODO: baby size?
|
EntityEnum::Turtle(_) => [1.2, 0.4, 1.2], // TODO: baby size?
|
||||||
EntityState::Vex(_) => [0.4, 0.8, 0.4],
|
EntityEnum::Vex(_) => [0.4, 0.8, 0.4],
|
||||||
EntityState::Villager(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
EntityEnum::Villager(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
||||||
EntityState::Vindicator(_) => [0.6, 1.95, 0.6],
|
EntityEnum::Vindicator(_) => [0.6, 1.95, 0.6],
|
||||||
EntityState::WanderingTrader(_) => [0.6, 1.95, 0.6],
|
EntityEnum::WanderingTrader(_) => [0.6, 1.95, 0.6],
|
||||||
EntityState::Witch(_) => [0.6, 1.95, 0.6],
|
EntityEnum::Witch(_) => [0.6, 1.95, 0.6],
|
||||||
EntityState::Wither(_) => [0.9, 3.5, 0.9],
|
EntityEnum::Wither(_) => [0.9, 3.5, 0.9],
|
||||||
EntityState::WitherSkeleton(_) => [0.7, 2.4, 0.7],
|
EntityEnum::WitherSkeleton(_) => [0.7, 2.4, 0.7],
|
||||||
EntityState::WitherSkull(_) => [0.3125, 0.3125, 0.3125],
|
EntityEnum::WitherSkull(_) => [0.3125, 0.3125, 0.3125],
|
||||||
EntityState::Wolf(_) => [0.6, 0.85, 0.6], // TODO: baby size?
|
EntityEnum::Wolf(_) => [0.6, 0.85, 0.6], // TODO: baby size?
|
||||||
EntityState::Zoglin(_) => [1.39648, 1.4, 1.39648], // TODO: baby size?
|
EntityEnum::Zoglin(_) => [1.39648, 1.4, 1.39648], // TODO: baby size?
|
||||||
EntityState::Zombie(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
EntityEnum::Zombie(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
||||||
EntityState::ZombieHorse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
|
EntityEnum::ZombieHorse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
|
||||||
EntityState::ZombieVillager(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
EntityEnum::ZombieVillager(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
||||||
EntityState::ZombifiedPiglin(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
EntityEnum::ZombifiedPiglin(_) => [0.6, 1.95, 0.6], // TODO: baby size?
|
||||||
EntityState::Player(_) => [0.6, 1.8, 0.6], // TODO: changes depending on the pose.
|
EntityEnum::Player(_) => [0.6, 1.8, 0.6], // TODO: changes depending on the pose.
|
||||||
EntityState::FishingBobber(_) => [0.25, 0.25, 0.25],
|
EntityEnum::FishingBobber(_) => [0.25, 0.25, 0.25],
|
||||||
};
|
};
|
||||||
|
|
||||||
aabb_from_bottom_and_size(self.new_position, dims.into())
|
aabb_from_bottom_and_size(self.new_position, dims.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the metadata packet to send to clients after this entity has been
|
/// Gets the tracked data packet to send to clients after this entity has
|
||||||
/// spawned.
|
/// been spawned.
|
||||||
///
|
///
|
||||||
/// Is `None` if there is no initial metadata.
|
/// Returns `None` if all the tracked data is at its default values.
|
||||||
pub(crate) fn initial_metadata_packet(&self, this_id: EntityId) -> Option<SetEntityMetadata> {
|
pub(crate) fn initial_tracked_data_packet(
|
||||||
self.state.initial_metadata().map(|meta| SetEntityMetadata {
|
&self,
|
||||||
|
this_id: EntityId,
|
||||||
|
) -> Option<SetEntityMetadata> {
|
||||||
|
self.variants
|
||||||
|
.initial_tracked_data()
|
||||||
|
.map(|meta| SetEntityMetadata {
|
||||||
entity_id: VarInt(this_id.to_network_id()),
|
entity_id: VarInt(this_id.to_network_id()),
|
||||||
metadata: RawBytes(meta),
|
metadata: RawBytes(meta),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the metadata packet to send to clients when the entity is modified.
|
/// Gets the tracked data packet to send to clients when the entity is
|
||||||
|
/// modified.
|
||||||
///
|
///
|
||||||
/// Is `None` if this entity's metadata has not been modified.
|
/// Returns `None` if this entity's tracked data has not been modified.
|
||||||
pub(crate) fn updated_metadata_packet(&self, this_id: EntityId) -> Option<SetEntityMetadata> {
|
pub(crate) fn updated_tracked_data_packet(
|
||||||
self.state.updated_metadata().map(|meta| SetEntityMetadata {
|
&self,
|
||||||
|
this_id: EntityId,
|
||||||
|
) -> Option<SetEntityMetadata> {
|
||||||
|
self.variants
|
||||||
|
.updated_tracked_data()
|
||||||
|
.map(|meta| SetEntityMetadata {
|
||||||
entity_id: VarInt(this_id.to_network_id()),
|
entity_id: VarInt(this_id.to_network_id()),
|
||||||
metadata: RawBytes(meta),
|
metadata: RawBytes(meta),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn spawn_packet(&self, this_id: EntityId) -> Option<EntitySpawnPacket> {
|
pub(crate) fn spawn_packet(&self, this_id: EntityId) -> Option<EntitySpawnPacket> {
|
||||||
match &self.state {
|
match &self.variants {
|
||||||
EntityState::Marker(_) => None,
|
EntityEnum::Marker(_) => None,
|
||||||
EntityState::ExperienceOrb(_) => {
|
EntityEnum::ExperienceOrb(_) => {
|
||||||
Some(EntitySpawnPacket::ExperienceOrb(AddExperienceOrb {
|
Some(EntitySpawnPacket::ExperienceOrb(AddExperienceOrb {
|
||||||
entity_id: VarInt(this_id.to_network_id()),
|
entity_id: VarInt(this_id.to_network_id()),
|
||||||
position: self.new_position,
|
position: self.new_position,
|
||||||
count: 0, // TODO
|
count: 0, // TODO
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
EntityState::Player(_) => Some(EntitySpawnPacket::Player(AddPlayer {
|
EntityEnum::Player(_) => Some(EntitySpawnPacket::Player(AddPlayer {
|
||||||
entity_id: VarInt(this_id.to_network_id()),
|
entity_id: VarInt(this_id.to_network_id()),
|
||||||
player_uuid: self.uuid,
|
player_uuid: self.uuid,
|
||||||
position: self.new_position,
|
position: self.new_position,
|
||||||
|
|
|
@ -1,35 +1,63 @@
|
||||||
//! Types used in [`EntityData`](crate::entity::EntityData).
|
//! Primitive types used in getters and setters on entities.
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
use crate::protocol_inner::{Encode, VarInt};
|
use crate::protocol_inner::{Decode, Encode, VarInt};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Debug)]
|
/// Represents an optional `u32` value excluding [`u32::MAX`].
|
||||||
pub struct ArmorStandRotations {
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
|
||||||
/// Rotation on the X axis in degrees.
|
pub struct OptionalInt(u32);
|
||||||
pub x: f32,
|
|
||||||
/// Rotation on the Y axis in degrees.
|
|
||||||
pub y: f32,
|
|
||||||
/// Rotation on the Z axis in degrees.
|
|
||||||
pub z: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArmorStandRotations {
|
impl OptionalInt {
|
||||||
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
/// Returns `None` iff `n` is Some(u32::MAX).
|
||||||
Self { x, y, z }
|
pub fn new(n: impl Into<Option<u32>>) -> Option<Self> {
|
||||||
|
match n.into() {
|
||||||
|
None => Some(Self(0)),
|
||||||
|
Some(u32::MAX) => None,
|
||||||
|
Some(n) => Some(Self(n + 1)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for ArmorStandRotations {
|
pub fn get(self) -> Option<u32> {
|
||||||
|
self.0.checked_sub(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encode for OptionalInt {
|
||||||
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
||||||
self.x.encode(w)?;
|
VarInt(self.0 as i32).encode(w)
|
||||||
self.y.encode(w)?;
|
}
|
||||||
self.z.encode(w)
|
}
|
||||||
|
|
||||||
|
impl Decode for OptionalInt {
|
||||||
|
fn decode(r: &mut impl Read) -> anyhow::Result<Self> {
|
||||||
|
Ok(Self(VarInt::decode(r)?.0 as u32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||||
|
pub struct EulerAngle {
|
||||||
|
pub pitch: f32,
|
||||||
|
pub yaw: f32,
|
||||||
|
pub roll: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EulerAngle {
|
||||||
|
pub fn new(pitch: f32, yaw: f32, roll: f32) -> Self {
|
||||||
|
Self { pitch, yaw, roll }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encode for EulerAngle {
|
||||||
|
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
||||||
|
self.pitch.encode(w)?;
|
||||||
|
self.yaw.encode(w)?;
|
||||||
|
self.roll.encode(w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
pub enum Direction {
|
pub enum Facing {
|
||||||
Down,
|
Down,
|
||||||
Up,
|
Up,
|
||||||
North,
|
North,
|
||||||
|
@ -38,7 +66,7 @@ pub enum Direction {
|
||||||
East,
|
East,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for Direction {
|
impl Encode for Facing {
|
||||||
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
||||||
VarInt(*self as i32).encode(w)
|
VarInt(*self as i32).encode(w)
|
||||||
}
|
}
|
||||||
|
@ -206,7 +234,7 @@ impl Encode for FrogKind {
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
|
||||||
pub enum PaintingKind {
|
pub enum PaintingKind {
|
||||||
#[default]
|
#[default]
|
||||||
Default, // TODO
|
Kebab, // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for PaintingKind {
|
impl Encode for PaintingKind {
|
||||||
|
@ -214,3 +242,15 @@ impl Encode for PaintingKind {
|
||||||
VarInt(*self as i32).encode(w)
|
VarInt(*self as i32).encode(w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub enum Particle {
|
||||||
|
EntityEffect = 21,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encode for Particle {
|
||||||
|
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
||||||
|
VarInt(*self as i32).encode(w)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,9 @@
|
||||||
//! Contains a struct for each variant in [`EntityKind`].
|
//! Contains the [`EntityEnum`] and the types for each variant.
|
||||||
|
|
||||||
#![allow(clippy::all, missing_docs)]
|
#![allow(clippy::all, missing_docs, trivial_numeric_casts)]
|
||||||
|
|
||||||
use crate::block::{BlockPos, BlockState};
|
use crate::block::{BlockPos, BlockState};
|
||||||
use crate::entity::state::*;
|
use crate::entity::data::*;
|
||||||
use crate::entity::EntityId;
|
|
||||||
use crate::protocol_inner::{Encode, VarInt};
|
use crate::protocol_inner::{Encode, VarInt};
|
||||||
use crate::text::Text;
|
use crate::text::Text;
|
||||||
use crate::uuid::Uuid;
|
use crate::uuid::Uuid;
|
|
@ -618,7 +618,7 @@ pub mod play {
|
||||||
def_struct! {
|
def_struct! {
|
||||||
Animate 0x03 {
|
Animate 0x03 {
|
||||||
entity_id: VarInt,
|
entity_id: VarInt,
|
||||||
animation: BoundedInt<u8, 0, 5>,
|
animation: u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,12 +735,10 @@ pub mod play {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ENTITY_EVENT_MAX_BOUND: i64 = 62;
|
|
||||||
|
|
||||||
def_struct! {
|
def_struct! {
|
||||||
EntityEvent 0x18 {
|
EntityStatus 0x18 {
|
||||||
entity_id: i32,
|
entity_id: i32,
|
||||||
entity_status: BoundedInt<u8, 1, ENTITY_EVENT_MAX_BOUND>,
|
entity_status: u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1270,7 +1268,7 @@ pub mod play {
|
||||||
BossEvent,
|
BossEvent,
|
||||||
ClearTitles,
|
ClearTitles,
|
||||||
Disconnect,
|
Disconnect,
|
||||||
EntityEvent,
|
EntityStatus,
|
||||||
ForgetLevelChunk,
|
ForgetLevelChunk,
|
||||||
GameEvent,
|
GameEvent,
|
||||||
KeepAlive,
|
KeepAlive,
|
||||||
|
|
Loading…
Reference in a new issue