Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Splash Potion Implementation #523

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions pumpkin-protocol/src/client/play/spawn_entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct CSpawnEntity {
entity_id: VarInt,
#[serde(with = "uuid::serde::compact")]
entity_uuid: uuid::Uuid,
typ: VarInt,
entity_type: VarInt,
position: Vector3<f64>,
pitch: u8, // angle
yaw: u8, // angle
Expand All @@ -25,7 +25,7 @@ impl CSpawnEntity {
pub fn new(
entity_id: VarInt,
entity_uuid: uuid::Uuid,
typ: VarInt,
entity_type: VarInt,
position: Vector3<f64>,
pitch: f32, // angle
yaw: f32, // angle
Expand All @@ -36,16 +36,16 @@ impl CSpawnEntity {
Self {
entity_id,
entity_uuid,
typ,
entity_type,
position,
pitch: (pitch * 256.0 / 360.0).floor() as u8,
yaw: (yaw * 256.0 / 360.0).floor() as u8,
head_yaw: (head_yaw * 256.0 / 360.0).floor() as u8,
data,
velocity: Vector3::new(
(velocity.x.clamp(-3.9, 3.9) * 8000.0) as i16,
(velocity.x.clamp(-3.9, 3.9) * 8000.0) as i16,
(velocity.x.clamp(-3.9, 3.9) * 8000.0) as i16,
(velocity.y.clamp(-3.9, 3.9) * 8000.0) as i16,
(velocity.z.clamp(-3.9, 3.9) * 8000.0) as i16,
),
}
}
Expand Down
1 change: 1 addition & 0 deletions pumpkin-protocol/src/codec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use thiserror::Error;
pub mod bit_set;
pub mod identifier;
pub mod slot;
pub mod slot_components;
pub mod var_int;
pub mod var_long;

Expand Down
70 changes: 66 additions & 4 deletions pumpkin-protocol/src/codec/slot.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::VarInt;
use crate::codec::slot_components::PotionContents;
use pumpkin_data::item::Item;
use pumpkin_world::item::ItemStack;
use serde::ser::SerializeSeq;
Expand All @@ -17,6 +18,36 @@ pub struct Slot {
components_to_remove: Option<Vec<VarInt>>,
}

macro_rules! back_to_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident {
$($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
}) => {
$(#[$meta])*
$vis enum $name {
$($(#[$vmeta])* $vname $(= $val)?,)*
}

impl std::convert::TryFrom<i32> for $name {
type Error = ();

fn try_from(v: i32) -> Result<Self, Self::Error> {
match v {
$(x if x == $name::$vname as i32 => Ok($name::$vname),)*
_ => Err(()),
}
}
}
}
}
back_to_enum! {
pub enum StructuredComponentType {
CustomData,
// TODO: Implement all
PotionContents = 41,

}
}

impl<'de> Deserialize<'de> for Slot {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand Down Expand Up @@ -56,12 +87,43 @@ impl<'de> Deserialize<'de> for Slot {
let num_components_to_remove = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("Failed to decode VarInt"))?;
if num_components_to_add.0 != 0 || num_components_to_remove.0 != 0 {
return Err(de::Error::custom(
"Slot components are currently unsupported",
));

for _ in 0..num_components_to_add.0 {
let component_type = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("Failed to decode VarInt!!"))?;
log::info!("dat: {:?}", component_type);
// let s: StructuredComponentType = component_type.into();
match component_type.0.try_into() {
Ok(StructuredComponentType::PotionContents) => {
log::info!("yesir");
let _has_potion_id = seq
.next_element::<PotionContents>()?
.ok_or(de::Error::custom("Failed to decode potion"))?;
// let potion_id = seq
// .next_element::<VarInt>()?
// .ok_or(de::Error::custom("Failed to decode VarInt"))?;
}
Ok(StructuredComponentType::CustomData) => {
log::info!("uhhuh")
}
Err(_) => log::error!("nooooo"),
// _ => {
// log::error!("nooooo")
// }
}
// let component_data = seq
// .next_element::<Slot>()?
// .ok_or(de::Error::custom("Unable to parse item"))?;
// array_of_changed_slots.push((slot_number, slot));
}

// if num_components_to_add.0 != 0 || num_components_to_remove.0 != 0 {
// return Err(de::Error::custom(
// "Slot components are currently unsupported",
// ));
// }

Ok(Slot {
item_count,
item_id: Some(item_id),
Expand Down
3 changes: 3 additions & 0 deletions pumpkin-protocol/src/codec/slot_components/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod potion_contents;

pub use potion_contents::*;
148 changes: 148 additions & 0 deletions pumpkin-protocol/src/codec/slot_components/potion_contents.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
use crate::VarInt;
use crate::codec::slot::StructuredComponentType;
use serde::{
Deserialize,
de::{self, SeqAccess},
};

#[derive(serde::Serialize, Debug, Clone)]
pub struct PotionContents {
has_potion_id: bool,
potion_id: Option<VarInt>,
has_custom_color: bool,
custom_color: Option<u32>,
number_of_custom_effects: VarInt,
custom_effects: Vec<PotionEffect>,
custom_name: String,
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct PotionEffect {
type_id: VarInt, // todo: enum
detail: Detail,
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct Detail {
amplifier: VarInt,
duration: VarInt,
ambient: bool,
show_particles: bool,
show_icon: bool,
has_hidden_effect: bool,
hidden_effect: Option<Box<Detail>>, // only if prev is true
}

impl<'de> Deserialize<'de> for PotionContents {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = PotionContents;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid PotionContents encoded in a byte sequence")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let has_potion_id = seq
.next_element::<bool>()?
.ok_or(de::Error::custom("Failed to decode bool"))?;

let potion_id: Option<VarInt> = if has_potion_id {
Some(
seq.next_element::<VarInt>()?
.ok_or(de::Error::custom("Failed to decode VarInt"))?,
)
} else {
None
};

let has_custom_color = seq
.next_element::<bool>()?
.ok_or(de::Error::custom("Failed to decode bool"))?;
let custom_color: Option<u32> = if has_custom_color {
Some(
seq.next_element::<u32>()?
.ok_or(de::Error::custom("Failed to decode bool"))?,
)
} else {
None
};

let number_of_custom_effects = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("Failed to decode VarInt"))?;

for _ in 0..number_of_custom_effects.0 {
let component_type = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("Failed to decode VarInt!!"))?;
log::info!("dat: {:?}", component_type);
// let s: StructuredComponentType = component_type.into();
match component_type.0.try_into() {
Ok(StructuredComponentType::PotionContents) => {
log::info!("yesir");
let _has_potion_id = seq
.next_element::<PotionContents>()?
.ok_or(de::Error::custom("Failed to decode potion"))?;
// let potion_id = seq
// .next_element::<VarInt>()?
// .ok_or(de::Error::custom("Failed to decode VarInt"))?;
}
Ok(StructuredComponentType::CustomData) => {
log::info!("uhhuh")
}
Err(_) => log::error!("nooooo"),
// _ => {
// log::error!("nooooo")
// }
}
// let component_data = seq
// .next_element::<Slot>()?
// .ok_or(de::Error::custom("Unable to parse item"))?;
// array_of_changed_slots.push((slot_number, slot));
}

let custom_name = seq
.next_element::<String>()?
.ok_or(de::Error::custom("Failed to decode VarInt"))?;

// if num_components_to_add.0 != 0 || num_components_to_remove.0 != 0 {
// return Err(de::Error::custom(
// "Slot components are currently unsupported",
// ));
// }

log::info!("has_potion: {}", has_potion_id);
if let Some(s) = potion_id.clone() {
log::info!("potion: {}", s.0);
}
log::info!("has_color: {}", has_custom_color);
if let Some(s) = custom_color {
log::info!("custom_color: {}", s);
}
log::info!("num_effects: {}", number_of_custom_effects.0);

log::info!("num_effects: {}", custom_name);

Ok(PotionContents {
has_potion_id,
potion_id,
has_custom_color,
custom_color,
number_of_custom_effects,
custom_effects: vec![],
custom_name,
})
}
}

deserializer.deserialize_seq(Visitor)
}
}
4 changes: 3 additions & 1 deletion pumpkin/src/entity/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use pumpkin_protocol::{
};
use pumpkin_world::item::ItemStack;

use crate::server::Server;

use super::{Entity, EntityBase, living::LivingEntity, player::Player};

pub struct ItemEntity {
Expand Down Expand Up @@ -40,7 +42,7 @@ impl ItemEntity {

#[async_trait]
impl EntityBase for ItemEntity {
async fn tick(&self) {
async fn tick(&self, _server: &Server) {
if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) > 0 {
self.pickup_delay
.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/entity/mob/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct MobEntity {

#[async_trait]
impl EntityBase for MobEntity {
async fn tick(&self) {
async fn tick(&self, _server: &Server) {
let mut goals = self.goals.lock().await;
for (goal, running) in goals.iter_mut() {
if *running {
Expand Down
11 changes: 8 additions & 3 deletions pumpkin/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use pumpkin_util::math::{
use serde::Serialize;
use tokio::sync::RwLock;

use crate::world::World;
use crate::{server::Server, world::World};

pub mod ai;
pub mod hunger;
Expand All @@ -46,17 +46,20 @@ pub type EntityId = i32;
#[async_trait]
pub trait EntityBase: Send + Sync {
/// Gets Called every tick
async fn tick(&self) {}
async fn tick(&self, _server: &Server) {}
/// Called when a player collides with the entity
async fn on_player_collision(&self, _player: Arc<Player>) {}
fn get_entity(&self) -> &Entity;
fn get_living_entity(&self) -> Option<&LivingEntity>;
async fn on_entity_destroy(&self, _entity: &Entity, _world: &World) {}
}

/// Represents a not living Entity (e.g. Item, Egg, Snowball...)
pub struct Entity {
/// A unique identifier for the entity
pub entity_id: EntityId,
/// The potential owner for this entity (e.g. the player who threw a snowball)
pub owner_id: Option<EntityId>,
/// A persistent, unique identifier for the entity
pub entity_uuid: uuid::Uuid,
/// The type of entity (e.g., player, zombie, item)
Expand Down Expand Up @@ -103,6 +106,7 @@ impl Entity {
#[expect(clippy::too_many_arguments)]
pub fn new(
entity_id: EntityId,
owner_id: Option<EntityId>,
entity_uuid: uuid::Uuid,
world: Arc<World>,
position: Vector3<f64>,
Expand All @@ -118,6 +122,7 @@ impl Entity {

Self {
entity_id,
owner_id,
entity_uuid,
entity_type,
on_ground: AtomicBool::new(false),
Expand Down Expand Up @@ -383,7 +388,7 @@ impl Entity {

#[async_trait]
impl EntityBase for Entity {
async fn tick(&self) {}
async fn tick(&self, _server: &Server) {}

fn get_entity(&self) -> &Entity {
self
Expand Down
Loading