Skip to content

Commit

Permalink
Added Spawn Egg Functionality (#350)
Browse files Browse the repository at this point in the history
* Added spawn egg functionality

* Readd changes from before merge

* Added basic attacks on mobs

* Fixed spawn rotation and position

* Updated entities.json

* Fixed entity registry

* Added correct bounding boxes per entity

* Various fixes

* use right data types in entity registry

* fix: clippy

---------

Co-authored-by: Alexander Medvedev <[email protected]>
  • Loading branch information
OfficialKris and Snowiiii authored Dec 29, 2024
1 parent 02cec58 commit 6f7433e
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 82 deletions.
4 changes: 4 additions & 0 deletions pumpkin-inventory/src/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ impl PlayerInventory {
self.selected = slot;
}

pub fn get_selected(&self) -> usize {
self.selected + 36
}

pub fn held_item(&self) -> Option<&ItemStack> {
debug_assert!((0..9).contains(&self.selected));
self.items[self.selected + 36 - 9].as_ref()
Expand Down
35 changes: 35 additions & 0 deletions pumpkin-world/src/entity/entity_registry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use std::{collections::HashMap, sync::LazyLock};

use serde::Deserialize;

const ENTITIES_JSON: &str = include_str!("../../../assets/entities.json");

pub static ENTITIES: LazyLock<HashMap<String, Entity>> = LazyLock::new(|| {
serde_json::from_str(ENTITIES_JSON).expect("Could not parse entity.json registry.")
});

pub static ENTITIES_BY_ID: LazyLock<HashMap<String, u16>> = LazyLock::new(|| {
let mut map = HashMap::new();
for (entity_name, entity) in ENTITIES.iter() {
map.insert(entity_name.clone(), entity.id);
}
map
});

pub fn get_entity_id(name: &str) -> Option<&u16> {
ENTITIES_BY_ID.get(&name.replace("minecraft:", ""))
}

pub fn get_entity_by_id<'a>(entity_id: u16) -> Option<&'a Entity> {
ENTITIES.values().find(|&entity| entity.id == entity_id)
}

#[derive(Deserialize, Clone, Debug)]
pub struct Entity {
pub id: u16,
pub max_health: Option<f32>,
pub attackable: bool,
pub summonable: bool,
pub fire_immune: bool,
pub dimension: [f32; 2],
}
1 change: 1 addition & 0 deletions pumpkin-world/src/entity/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod entity_registry;
25 changes: 20 additions & 5 deletions pumpkin-world/src/item/item_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,30 @@ pub static ITEMS: LazyLock<HashMap<String, Item>> = LazyLock::new(|| {
serde_json::from_str(ITEMS_JSON).expect("Could not parse items.json registry.")
});

pub static ITEMS_REGISTRY_NAME_BY_ID: LazyLock<HashMap<u16, String>> = LazyLock::new(|| {
let mut map = HashMap::new();
for item in ITEMS.clone() {
map.insert(item.1.id, item.0.clone());
}
map
});

pub fn get_item(name: &str) -> Option<&Item> {
ITEMS.get(&name.replace("minecraft:", ""))
}

pub fn get_item_by_id<'a>(id: u16) -> Option<&'a Item> {
let item = ITEMS.iter().find(|item| item.1.id == id);
if let Some(item) = item {
return Some(item.1);
}
pub fn get_item_by_id<'a>(item_id: u16) -> Option<&'a Item> {
ITEMS.values().find(|&item| item.id == item_id)
}

pub fn get_spawn_egg(item_id: u16) -> Option<String> {
if let Some(item_name) = ITEMS_REGISTRY_NAME_BY_ID.get(&item_id) {
if item_name.ends_with("_spawn_egg") {
if let Some(res) = item_name.strip_suffix("_spawn_egg") {
return Some(res.to_owned());
}
}
};
None
}

Expand Down
1 change: 1 addition & 0 deletions pumpkin-world/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod chunk;
pub mod coordinates;
pub mod cylindrical_chunk_iterator;
pub mod dimension;
pub mod entity;
mod generation;
pub mod item;
pub mod level;
Expand Down
5 changes: 5 additions & 0 deletions pumpkin/src/entity/living.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::sync::atomic::AtomicI32;

use crossbeam::atomic::AtomicCell;
use pumpkin_core::math::vector3::Vector3;
use pumpkin_entity::EntityId;
use pumpkin_inventory::{Container, EmptyContainer};
use pumpkin_protocol::client::play::{CDamageEvent, CEntityStatus, CSetEntityMetadata, Metadata};
use tokio::sync::Mutex;
Expand Down Expand Up @@ -85,6 +86,10 @@ impl<C: Container> LivingEntity<C> {
.await;
}

pub const fn entity_id(&self) -> EntityId {
self.entity.entity_id
}

// TODO add damage_type enum
pub async fn damage(&self, amount: f32, damage_type: u8) {
self.entity
Expand Down
4 changes: 4 additions & 0 deletions pumpkin/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub mod player;
pub struct Entity {
/// A unique identifier for the entity
pub entity_id: EntityId,
/// A persistant, unique identifier for the entity
pub entity_uuid: uuid::Uuid,
/// The type of entity (e.g., player, zombie, item)
pub entity_type: EntityType,
/// The world in which the entity exists.
Expand Down Expand Up @@ -63,6 +65,7 @@ pub struct Entity {
impl Entity {
pub fn new(
entity_id: EntityId,
entity_uuid: uuid::Uuid,
world: Arc<World>,
entity_type: EntityType,
standing_eye_height: f32,
Expand All @@ -71,6 +74,7 @@ impl Entity {
) -> Self {
Self {
entity_id,
entity_uuid,
entity_type,
on_ground: AtomicBool::new(false),
pos: AtomicCell::new(Vector3::new(0.0, 0.0, 0.0)),
Expand Down
4 changes: 3 additions & 1 deletion pumpkin/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,12 @@ impl Player {
entity_id: EntityId,
gamemode: GameMode,
) -> Self {
let player_uuid = uuid::Uuid::new_v4();
let gameprofile = client.gameprofile.lock().await.clone().map_or_else(
|| {
log::error!("Client {} has no game profile!", client.id);
GameProfile {
id: uuid::Uuid::new_v4(),
id: player_uuid,
name: String::new(),
properties: vec![],
profile_actions: None,
Expand All @@ -157,6 +158,7 @@ impl Player {
living_entity: LivingEntity::new_with_container(
Entity::new(
entity_id,
player_uuid,
world,
EntityType::Player,
1.62,
Expand Down
16 changes: 16 additions & 0 deletions pumpkin/src/net/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,22 @@ impl Player {
Ok(())
}

pub async fn handle_decrease_item(
&self,
_server: &Server,
slot_index: usize,
item_stack: Option<&ItemStack>,
state_id: &mut u32,
) -> Result<(), InventoryError> {
// TODO: this will not update hotbar when server admin is peeking
// TODO: check and iterate over all players in player inventory
let slot = Slot::from(item_stack);
*state_id += 1;
let packet = CSetContainerSlot::new(0, *state_id as i32, slot_index, &slot);
self.client.send_packet(&packet).await;
Ok(())
}

async fn match_click_behaviour(
&self,
opened_container: Option<&mut Box<dyn Container>>,
Expand Down
Loading

0 comments on commit 6f7433e

Please sign in to comment.