mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
feat: add name tag logic
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@ pub struct EntityType {
|
||||
pub loot_table: Option<LootTableStruct>,
|
||||
pub summonable: bool,
|
||||
pub fire_immune: bool,
|
||||
pub saveable: bool,
|
||||
pub category: MobCategory,
|
||||
pub can_spawn_far_from_player: bool,
|
||||
pub dimension: [f32; 2],
|
||||
@@ -106,6 +107,7 @@ impl ToTokens for NamedEntityType<'_> {
|
||||
MobCategory::MISC => quote! { MobCategory::MISC },
|
||||
};
|
||||
|
||||
let saveable = entity.saveable;
|
||||
let summonable = entity.summonable;
|
||||
let fire_immune = entity.fire_immune;
|
||||
let eye_height = entity.eye_height;
|
||||
@@ -136,6 +138,7 @@ impl ToTokens for NamedEntityType<'_> {
|
||||
max_health: #max_health,
|
||||
attackable: #attackable,
|
||||
mob: #mob,
|
||||
saveable: #saveable,
|
||||
limit_per_chunk: #limit_per_chunk,
|
||||
summonable: #summonable,
|
||||
fire_immune: #fire_immune,
|
||||
@@ -192,6 +195,7 @@ pub(crate) fn build() -> TokenStream {
|
||||
pub max_health: Option<f32>,
|
||||
pub attackable: Option<bool>,
|
||||
pub mob: bool,
|
||||
pub saveable: bool,
|
||||
pub limit_per_chunk: i32,
|
||||
pub summonable: bool,
|
||||
pub fire_immune: bool,
|
||||
|
||||
@@ -151,7 +151,13 @@ impl DataComponentImpl for DamageImpl {
|
||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||
pub struct UnbreakableImpl;
|
||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||
pub struct CustomNameImpl;
|
||||
pub struct CustomNameImpl {
|
||||
// TODO make TextComponent const
|
||||
pub name: &'static str,
|
||||
}
|
||||
impl DataComponentImpl for CustomNameImpl {
|
||||
default_impl!(CustomName);
|
||||
}
|
||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||
pub struct ItemNameImpl {
|
||||
// TODO make TextComponent const
|
||||
|
||||
@@ -405,6 +405,16 @@ impl Entity {
|
||||
self.send_velocity().await;
|
||||
}
|
||||
|
||||
/// Sets a custom name for the entity, typically used with nametags
|
||||
pub async fn set_custon_name(&self, name: TextComponent) {
|
||||
self.send_meta_data(&[Metadata::new(
|
||||
2,
|
||||
MetaDataType::OptionalTextComponent,
|
||||
Some(name),
|
||||
)])
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn send_velocity(&self) {
|
||||
let velocity = self.velocity.load();
|
||||
self.world
|
||||
|
||||
@@ -91,4 +91,8 @@ impl EntityBase for ThrownItemEntity {
|
||||
fn as_nbt_storage(&self) -> &dyn NBTStorage {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_gravity(&self) -> f64 {
|
||||
0.03
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ impl ItemBehaviour for HoeItem {
|
||||
Uuid::new_v4(),
|
||||
world.clone(),
|
||||
location,
|
||||
&EntityType::SNOWBALL,
|
||||
&EntityType::ITEM,
|
||||
false,
|
||||
);
|
||||
// TODO: Merge stacks together
|
||||
|
||||
@@ -11,6 +11,7 @@ pub mod ignite;
|
||||
pub mod ink_sac;
|
||||
pub mod mace;
|
||||
pub mod minecart;
|
||||
pub mod name_tag;
|
||||
pub mod shovel;
|
||||
pub mod snowball;
|
||||
pub mod swords;
|
||||
@@ -18,6 +19,7 @@ pub mod trident;
|
||||
|
||||
use crate::item::items::end_crystal::EndCrystalItem;
|
||||
use crate::item::items::minecart::MinecartItem;
|
||||
use crate::item::items::name_tag::NameTagItem;
|
||||
|
||||
use super::registry::ItemRegistry;
|
||||
use axe::AxeItem;
|
||||
@@ -56,6 +58,7 @@ pub fn default_registry() -> Arc<ItemRegistry> {
|
||||
manager.register(EndCrystalItem);
|
||||
manager.register(MinecartItem);
|
||||
manager.register(HoneyCombItem);
|
||||
manager.register(NameTagItem);
|
||||
manager.register(EnderEyeItem);
|
||||
manager.register(FireChargeItem);
|
||||
manager.register(DyeItem);
|
||||
|
||||
40
pumpkin/src/item/items/name_tag.rs
Normal file
40
pumpkin/src/item/items/name_tag.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::entity::EntityBase;
|
||||
use crate::entity::player::Player;
|
||||
use crate::item::{ItemBehaviour, ItemMetadata};
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::data_component_impl::CustomNameImpl;
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_world::item::ItemStack;
|
||||
|
||||
pub struct NameTagItem;
|
||||
|
||||
impl ItemMetadata for NameTagItem {
|
||||
fn ids() -> Box<[u16]> {
|
||||
[Item::NAME_TAG.id].into()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ItemBehaviour for NameTagItem {
|
||||
async fn use_on_entity(
|
||||
&self,
|
||||
item: &mut ItemStack,
|
||||
player: &Player,
|
||||
entity: Arc<dyn EntityBase>,
|
||||
) {
|
||||
let entity = entity.get_entity();
|
||||
if entity.entity_type.saveable
|
||||
&& let Some(name) = item.get_data_component::<CustomNameImpl>()
|
||||
{
|
||||
// TODO
|
||||
entity.set_custon_name(TextComponent::text(name.name)).await;
|
||||
item.decrement_unless_creative(player.gamemode.load(), 1);
|
||||
}
|
||||
}
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@ pub mod items;
|
||||
pub mod registry;
|
||||
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::entity::EntityBase;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use async_trait::async_trait;
|
||||
@@ -32,6 +34,14 @@ pub trait ItemBehaviour: Send + Sync {
|
||||
) {
|
||||
}
|
||||
|
||||
async fn use_on_entity(
|
||||
&self,
|
||||
_item: &mut ItemStack,
|
||||
_player: &Player,
|
||||
_entity: Arc<dyn EntityBase>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn can_mine(&self, _player: &Player) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::entity::EntityBase;
|
||||
use crate::entity::player::Player;
|
||||
use crate::server::Server;
|
||||
use pumpkin_data::Block;
|
||||
@@ -48,6 +49,18 @@ impl ItemRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn use_on_entity(
|
||||
&self,
|
||||
stack: &mut ItemStack,
|
||||
player: &Player,
|
||||
entity: Arc<dyn EntityBase>,
|
||||
) {
|
||||
let pumpkin_item = self.get_pumpkin_item(stack.item);
|
||||
if let Some(pumpkin_item) = pumpkin_item {
|
||||
pumpkin_item.use_on_entity(stack, player, entity).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_mine(&self, item: &Item, player: &Player) -> bool {
|
||||
let pumpkin_block = self.get_pumpkin_item(item);
|
||||
if let Some(pumpkin_block) = pumpkin_block {
|
||||
|
||||
@@ -571,7 +571,7 @@ impl JavaClient {
|
||||
.await;
|
||||
}
|
||||
SInteract::PACKET_ID => {
|
||||
self.handle_interact(player, SInteract::read(payload)?)
|
||||
self.handle_interact(player, SInteract::read(payload)?, server)
|
||||
.await;
|
||||
}
|
||||
SKeepAlive::PACKET_ID => {
|
||||
|
||||
@@ -1065,15 +1065,21 @@ impl JavaClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_interact(&self, player: &Player, interact: SInteract) {
|
||||
pub async fn handle_interact(
|
||||
&self,
|
||||
player: &Player,
|
||||
interact: SInteract,
|
||||
server: &Arc<Server>,
|
||||
) {
|
||||
if !player.has_client_loaded() {
|
||||
return;
|
||||
}
|
||||
let entity_id = interact.entity_id;
|
||||
|
||||
let sneaking = interact.sneaking;
|
||||
let entity = &player.living_entity.entity;
|
||||
if entity.sneaking.load(Ordering::Relaxed) != sneaking {
|
||||
entity.set_sneaking(sneaking).await;
|
||||
let player_entity = &player.living_entity.entity;
|
||||
if player_entity.sneaking.load(Ordering::Relaxed) != sneaking {
|
||||
player_entity.set_sneaking(sneaking).await;
|
||||
}
|
||||
let Ok(action) = ActionType::try_from(interact.r#type.0) else {
|
||||
self.kick(TextComponent::text("Invalid action type")).await;
|
||||
@@ -1082,7 +1088,6 @@ impl JavaClient {
|
||||
|
||||
match action {
|
||||
ActionType::Attack => {
|
||||
let entity_id = interact.entity_id;
|
||||
let config = &advanced_config().pvp;
|
||||
// TODO: do validation and stuff
|
||||
if !config.enabled {
|
||||
@@ -1091,7 +1096,7 @@ impl JavaClient {
|
||||
|
||||
// TODO: set as camera entity when spectator
|
||||
|
||||
let world = &entity.world;
|
||||
let world = &player_entity.world;
|
||||
let player_victim = world.get_player_by_id(entity_id.0).await;
|
||||
if entity_id.0 == player.entity_id() {
|
||||
// This can't be triggered from a non-modded client.
|
||||
@@ -1137,7 +1142,16 @@ impl JavaClient {
|
||||
}
|
||||
}
|
||||
ActionType::Interact | ActionType::InteractAt => {
|
||||
log::debug!("todo");
|
||||
// TODO: split this up
|
||||
let entity = player.world().get_player_by_id(entity_id.0).await;
|
||||
if let Some(entity) = entity {
|
||||
let held = player.inventory.held_item();
|
||||
let mut stack = held.lock().await;
|
||||
server
|
||||
.item_registry
|
||||
.use_on_entity(&mut stack, player, entity)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1425,14 +1439,14 @@ impl JavaClient {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let mut stack = item.lock().await;
|
||||
|
||||
if item.lock().await.is_empty() {
|
||||
if stack.is_empty() {
|
||||
// TODO item cool down
|
||||
// If the hand is empty we stop here
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut stack = item.lock().await;
|
||||
server
|
||||
.item_registry
|
||||
.use_on_block(&mut stack, player, position, face, block, server)
|
||||
|
||||
Reference in New Issue
Block a user