Check if player can destroy block using an tool
Prevents players to destroy blocks when holding a sword or trident in creative
This commit is contained in:
parent
cccdf53e7c
commit
e055dd740c
3285
assets/blocks.json
3285
assets/blocks.json
File diff suppressed because it is too large
Load Diff
@ -315,14 +315,15 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
serde_json::from_str(self.components.item_name.unwrap()).expect("Could not parse item name.")
|
serde_json::from_str(self.components.item_name.unwrap()).expect("Could not parse item name.")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc = r" Try to parse a Item from a resource location string"]
|
#[doc = "Try to parse a Item from a resource location string"]
|
||||||
pub fn from_registry_key(name: &str) -> Option<Self> {
|
pub fn from_registry_key(name: &str) -> Option<Self> {
|
||||||
match name {
|
match name {
|
||||||
#type_from_name
|
#type_from_name
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[doc = r" Try to parse a Item from a raw id"]
|
|
||||||
|
#[doc = "Try to parse a Item from a raw id"]
|
||||||
pub const fn from_id(id: u16) -> Option<Self> {
|
pub const fn from_id(id: u16) -> Option<Self> {
|
||||||
match id {
|
match id {
|
||||||
#type_from_raw_id_arms
|
#type_from_raw_id_arms
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use heck::{ToPascalCase, ToSnakeCase};
|
use heck::{ToPascalCase, ToSnakeCase};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use pumpkin_data::item::Item;
|
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
use syn::{self};
|
||||||
use syn::{
|
use syn::{
|
||||||
Block, Expr, Field, Fields, ItemStruct, Stmt,
|
Block, Expr, Field, Fields, ItemStruct, Stmt,
|
||||||
parse::{Nothing, Parser},
|
parse::{Nothing, Parser},
|
||||||
@ -198,29 +198,6 @@ pub fn pumpkin_block(input: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
code.into()
|
code.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn pumpkin_item(input: TokenStream, item: TokenStream) -> TokenStream {
|
|
||||||
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
|
|
||||||
let name = &ast.ident;
|
|
||||||
let (impl_generics, ty_generics, _) = ast.generics.split_for_impl();
|
|
||||||
|
|
||||||
let input_string = input.to_string();
|
|
||||||
let packet_name = input_string.trim_matches('"');
|
|
||||||
let item_id = Item::from_registry_key(packet_name).unwrap();
|
|
||||||
let id = item_id.id;
|
|
||||||
|
|
||||||
let item: proc_macro2::TokenStream = item.into();
|
|
||||||
|
|
||||||
let code = quote! {
|
|
||||||
#item
|
|
||||||
impl #impl_generics crate::item::pumpkin_item::ItemMetadata for #name #ty_generics {
|
|
||||||
const ID: u16 = #id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
code.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn block_property(input: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn block_property(input: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
|
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
|
||||||
|
|||||||
@ -19,6 +19,13 @@ impl BoundingBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expand(&self, x: f64, y: f64, z: f64) -> Self {
|
||||||
|
Self {
|
||||||
|
min: Vector3::new(self.min.x - x, self.min.y - y, self.min.z - z),
|
||||||
|
max: Vector3::new(self.max.x + x, self.max.y + y, self.max.z + z),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn offset(&self, other: Self) -> Self {
|
pub fn offset(&self, other: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
min: self.min.add(&other.min),
|
min: self.min.add(&other.min),
|
||||||
|
|||||||
@ -122,6 +122,9 @@ pub struct Block {
|
|||||||
pub experience: Option<Experience>,
|
pub experience: Option<Experience>,
|
||||||
pub blast_resistance: f32,
|
pub blast_resistance: f32,
|
||||||
pub wall_variant_id: Option<u16>,
|
pub wall_variant_id: Option<u16>,
|
||||||
|
pub slipperiness: f32,
|
||||||
|
pub velocity_multiplier: f32,
|
||||||
|
pub jump_velocity_multiplier: f32,
|
||||||
pub translation_key: String,
|
pub translation_key: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub loot_table: Option<LootTable>,
|
pub loot_table: Option<LootTable>,
|
||||||
|
|||||||
@ -12,14 +12,7 @@ impl AlternativeEntry {
|
|||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
for child in &self.children {
|
for child in &self.children {
|
||||||
if let Some(conditions) = &child.conditions {
|
if let Some(conditions) = &child.conditions {
|
||||||
let mut conditions_met = true;
|
if !conditions.iter().all(|condition| condition.test()) {
|
||||||
for condition in conditions {
|
|
||||||
if !condition.test() {
|
|
||||||
conditions_met = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !conditions_met {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,14 +41,7 @@ impl LootPool {
|
|||||||
for _ in 0..i {
|
for _ in 0..i {
|
||||||
for entry in &self.entries {
|
for entry in &self.entries {
|
||||||
if let Some(conditions) = &entry.conditions {
|
if let Some(conditions) = &entry.conditions {
|
||||||
let mut conditions_met = true;
|
if !conditions.iter().all(|condition| condition.test()) {
|
||||||
for condition in conditions {
|
|
||||||
if !condition.test() {
|
|
||||||
conditions_met = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !conditions_met {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,11 +80,8 @@ async fn drop_stack(world: &Arc<World>, pos: &BlockPos, stack: ItemStack) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let entity = world.create_entity(pos, EntityType::ITEM);
|
let entity = world.create_entity(pos, EntityType::ITEM);
|
||||||
let item_entity = Arc::new(ItemEntity::new(
|
let item_entity =
|
||||||
entity,
|
Arc::new(ItemEntity::new(entity, stack.item.id, u32::from(stack.item_count)).await);
|
||||||
stack.item.id,
|
|
||||||
u32::from(stack.item_count),
|
|
||||||
));
|
|
||||||
world.spawn_entity(item_entity.clone()).await;
|
world.spawn_entity(item_entity.clone()).await;
|
||||||
item_entity.send_meta_packet().await;
|
item_entity.send_meta_packet().await;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,7 +64,9 @@ impl ExperienceOrbEntity {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EntityBase for ExperienceOrbEntity {
|
impl EntityBase for ExperienceOrbEntity {
|
||||||
async fn tick(&self, _: &Server) {
|
async fn tick(&self, server: &Server) {
|
||||||
|
self.entity.tick(server).await;
|
||||||
|
|
||||||
let age = self
|
let age = self
|
||||||
.orb_age
|
.orb_age
|
||||||
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use pumpkin_protocol::{
|
|||||||
client::play::{CTakeItemEntity, MetaDataType, Metadata},
|
client::play::{CTakeItemEntity, MetaDataType, Metadata},
|
||||||
codec::slot::Slot,
|
codec::slot::Slot,
|
||||||
};
|
};
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
@ -24,7 +25,14 @@ pub struct ItemEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ItemEntity {
|
impl ItemEntity {
|
||||||
pub fn new(entity: Entity, item_id: u16, count: u32) -> Self {
|
pub async fn new(entity: Entity, item_id: u16, count: u32) -> Self {
|
||||||
|
entity
|
||||||
|
.set_velocity(Vector3::new(
|
||||||
|
rand::random::<f64>() * 0.2 - 0.1,
|
||||||
|
0.2,
|
||||||
|
rand::random::<f64>() * 0.2 - 0.1,
|
||||||
|
))
|
||||||
|
.await;
|
||||||
entity.yaw.store(rand::random::<f32>() * 360.0);
|
entity.yaw.store(rand::random::<f32>() * 360.0);
|
||||||
Self {
|
Self {
|
||||||
entity,
|
entity,
|
||||||
@ -44,7 +52,8 @@ impl ItemEntity {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EntityBase for ItemEntity {
|
impl EntityBase for ItemEntity {
|
||||||
async fn tick(&self, _server: &Server) {
|
async fn tick(&self, server: &Server) {
|
||||||
|
self.entity.tick(server).await;
|
||||||
{
|
{
|
||||||
let mut delay = self.pickup_delay.lock().await;
|
let mut delay = self.pickup_delay.lock().await;
|
||||||
*delay = delay.saturating_sub(1);
|
*delay = delay.saturating_sub(1);
|
||||||
|
|||||||
@ -242,7 +242,9 @@ impl LivingEntity {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EntityBase for LivingEntity {
|
impl EntityBase for LivingEntity {
|
||||||
async fn tick(&self, _server: &Server) {
|
async fn tick(&self, server: &Server) {
|
||||||
|
self.entity.tick(server).await;
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.time_until_regen
|
.time_until_regen
|
||||||
.load(std::sync::atomic::Ordering::Relaxed)
|
.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
|
|||||||
@ -427,6 +427,33 @@ impl Entity {
|
|||||||
self.invulnerable.load(std::sync::atomic::Ordering::Relaxed)
|
self.invulnerable.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
|| self.damage_immunities.contains(damage_type)
|
|| self.damage_immunities.contains(damage_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn velocity_multiplier(&self, _pos: Vector3<f64>) -> f32 {
|
||||||
|
let world = self.world.read().await;
|
||||||
|
let block = world.get_block(&self.block_pos.load()).await.unwrap();
|
||||||
|
block.velocity_multiplier
|
||||||
|
// if velo_multiplier == 1.0 {
|
||||||
|
// const VELOCITY_OFFSET: f64 = 0.500001; // Vanilla
|
||||||
|
// let pos_with_y_offset = BlockPos(Vector3::new(
|
||||||
|
// pos.x.floor() as i32,
|
||||||
|
// (pos.y - VELOCITY_OFFSET).floor() as i32,
|
||||||
|
// pos.z.floor() as i32,
|
||||||
|
// ));
|
||||||
|
// let block = world.get_block(&pos_with_y_offset).await.unwrap();
|
||||||
|
// block.velocity_multiplier
|
||||||
|
// } else {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn tick_move(&self) {
|
||||||
|
let velo = self.velocity.load();
|
||||||
|
let pos = self.pos.load();
|
||||||
|
self.pos
|
||||||
|
.store(Vector3::new(pos.x + velo.x, pos.y + velo.y, pos.z + velo.z));
|
||||||
|
let multiplier = f64::from(self.velocity_multiplier(pos).await);
|
||||||
|
self.velocity
|
||||||
|
.store(velo.multiply(multiplier, 1.0, multiplier));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -435,7 +462,9 @@ impl EntityBase for Entity {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn tick(&self, _: &Server) {}
|
async fn tick(&self, _: &Server) {
|
||||||
|
self.tick_move().await;
|
||||||
|
}
|
||||||
|
|
||||||
fn get_entity(&self) -> &Entity {
|
fn get_entity(&self) -> &Entity {
|
||||||
self
|
self
|
||||||
|
|||||||
@ -1009,7 +1009,7 @@ impl Player {
|
|||||||
.create_entity(self.living_entity.entity.pos.load(), EntityType::ITEM);
|
.create_entity(self.living_entity.entity.pos.load(), EntityType::ITEM);
|
||||||
|
|
||||||
// TODO: Merge stacks together
|
// TODO: Merge stacks together
|
||||||
let item_entity = Arc::new(ItemEntity::new(entity, item_id, count));
|
let item_entity = Arc::new(ItemEntity::new(entity, item_id, count).await);
|
||||||
self.world().await.spawn_entity(item_entity.clone()).await;
|
self.world().await.spawn_entity(item_entity.clone()).await;
|
||||||
item_entity.send_meta_packet().await;
|
item_entity.send_meta_packet().await;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,16 +2,18 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::entity::projectile::ThrownItemEntity;
|
use crate::entity::projectile::ThrownItemEntity;
|
||||||
use crate::item::pumpkin_item::PumpkinItem;
|
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use pumpkin_data::entity::EntityType;
|
use pumpkin_data::entity::EntityType;
|
||||||
use pumpkin_data::item::Item;
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::sound::Sound;
|
use pumpkin_data::sound::Sound;
|
||||||
use pumpkin_macros::pumpkin_item;
|
|
||||||
|
|
||||||
#[pumpkin_item("egg")]
|
|
||||||
pub struct EggItem;
|
pub struct EggItem;
|
||||||
|
|
||||||
|
impl ItemMetadata for EggItem {
|
||||||
|
const IDS: &'static [u16] = &[Item::EGG.id];
|
||||||
|
}
|
||||||
|
|
||||||
const POWER: f32 = 1.5;
|
const POWER: f32 = 1.5;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@ -1,2 +1,24 @@
|
|||||||
pub mod egg;
|
mod egg;
|
||||||
pub mod snowball;
|
mod snowball;
|
||||||
|
mod sword;
|
||||||
|
mod trident;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use egg::EggItem;
|
||||||
|
use snowball::SnowBallItem;
|
||||||
|
use sword::SwordItem;
|
||||||
|
use trident::TridentItem;
|
||||||
|
|
||||||
|
use super::registry::ItemRegistry;
|
||||||
|
#[must_use]
|
||||||
|
pub fn default_registry() -> Arc<ItemRegistry> {
|
||||||
|
let mut manager = ItemRegistry::default();
|
||||||
|
|
||||||
|
manager.register(SnowBallItem);
|
||||||
|
manager.register(EggItem);
|
||||||
|
manager.register(SwordItem);
|
||||||
|
manager.register(TridentItem);
|
||||||
|
|
||||||
|
Arc::new(manager)
|
||||||
|
}
|
||||||
|
|||||||
@ -2,16 +2,18 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::entity::projectile::ThrownItemEntity;
|
use crate::entity::projectile::ThrownItemEntity;
|
||||||
use crate::item::pumpkin_item::PumpkinItem;
|
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use pumpkin_data::entity::EntityType;
|
use pumpkin_data::entity::EntityType;
|
||||||
use pumpkin_data::item::Item;
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::sound::Sound;
|
use pumpkin_data::sound::Sound;
|
||||||
use pumpkin_macros::pumpkin_item;
|
|
||||||
|
|
||||||
#[pumpkin_item("snowball")]
|
|
||||||
pub struct SnowBallItem;
|
pub struct SnowBallItem;
|
||||||
|
|
||||||
|
impl ItemMetadata for SnowBallItem {
|
||||||
|
const IDS: &'static [u16] = &[Item::SNOWBALL.id];
|
||||||
|
}
|
||||||
|
|
||||||
const POWER: f32 = 1.5;
|
const POWER: f32 = 1.5;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
24
pumpkin/src/item/items/sword.rs
Normal file
24
pumpkin/src/item/items/sword.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use crate::entity::player::Player;
|
||||||
|
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
|
use pumpkin_util::GameMode;
|
||||||
|
|
||||||
|
pub struct SwordItem;
|
||||||
|
|
||||||
|
impl ItemMetadata for SwordItem {
|
||||||
|
const IDS: &'static [u16] = &[
|
||||||
|
Item::WOODEN_SWORD.id,
|
||||||
|
Item::STONE_SWORD.id,
|
||||||
|
Item::GOLDEN_SWORD.id,
|
||||||
|
Item::DIAMOND_SWORD.id,
|
||||||
|
Item::NETHERITE_SWORD.id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl PumpkinItem for SwordItem {
|
||||||
|
fn can_mine(&self, player: &Player) -> bool {
|
||||||
|
player.gamemode.load() != GameMode::Creative
|
||||||
|
}
|
||||||
|
}
|
||||||
21
pumpkin/src/item/items/trident.rs
Normal file
21
pumpkin/src/item/items/trident.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
|
use pumpkin_util::GameMode;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
entity::player::Player,
|
||||||
|
item::pumpkin_item::{ItemMetadata, PumpkinItem},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TridentItem;
|
||||||
|
|
||||||
|
impl ItemMetadata for TridentItem {
|
||||||
|
const IDS: &'static [u16] = &[Item::TRIDENT.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl PumpkinItem for TridentItem {
|
||||||
|
fn can_mine(&self, player: &Player) -> bool {
|
||||||
|
player.gamemode.load() != GameMode::Creative
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,18 +1,3 @@
|
|||||||
use items::{egg::EggItem, snowball::SnowBallItem};
|
pub mod items;
|
||||||
use registry::ItemRegistry;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
mod items;
|
|
||||||
pub mod pumpkin_item;
|
pub mod pumpkin_item;
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn default_registry() -> Arc<ItemRegistry> {
|
|
||||||
let mut manager = ItemRegistry::default();
|
|
||||||
|
|
||||||
manager.register(SnowBallItem);
|
|
||||||
manager.register(EggItem);
|
|
||||||
|
|
||||||
Arc::new(manager)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use pumpkin_util::math::position::BlockPos;
|
|||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
|
|
||||||
pub trait ItemMetadata {
|
pub trait ItemMetadata {
|
||||||
const ID: u16;
|
const IDS: &'static [u16];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -21,4 +21,8 @@ pub trait PumpkinItem: Send + Sync {
|
|||||||
_server: &Server,
|
_server: &Server,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn can_mine(&self, _player: &Player) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,12 +10,12 @@ use super::pumpkin_item::{ItemMetadata, PumpkinItem};
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ItemRegistry {
|
pub struct ItemRegistry {
|
||||||
items: HashMap<u16, Arc<dyn PumpkinItem>>,
|
items: HashMap<&'static [u16], Arc<dyn PumpkinItem>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemRegistry {
|
impl ItemRegistry {
|
||||||
pub fn register<T: PumpkinItem + ItemMetadata + 'static>(&mut self, item: T) {
|
pub fn register<T: PumpkinItem + ItemMetadata + 'static>(&mut self, item: T) {
|
||||||
self.items.insert(T::ID, Arc::new(item));
|
self.items.insert(T::IDS, Arc::new(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn on_use(&self, item: &Item, player: &Player) {
|
pub async fn on_use(&self, item: &Item, player: &Player) {
|
||||||
@ -41,8 +41,18 @@ impl ItemRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_mine(&self, item: &Item, player: &Player) -> bool {
|
||||||
|
let pumpkin_block = self.get_pumpkin_item(item.id);
|
||||||
|
if let Some(pumpkin_block) = pumpkin_block {
|
||||||
|
return pumpkin_block.can_mine(player);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_pumpkin_item(&self, item_id: u16) -> Option<&Arc<dyn PumpkinItem>> {
|
pub fn get_pumpkin_item(&self, item_id: u16) -> Option<&Arc<dyn PumpkinItem>> {
|
||||||
self.items.get(&item_id)
|
self.items
|
||||||
|
.iter()
|
||||||
|
.find_map(|(ids, item)| ids.contains(&item_id).then_some(item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ use pumpkin_inventory::player::{
|
|||||||
};
|
};
|
||||||
use pumpkin_macros::block_entity;
|
use pumpkin_macros::block_entity;
|
||||||
use pumpkin_protocol::client::play::{
|
use pumpkin_protocol::client::play::{
|
||||||
CBlockEntityData, COpenSignEditor, CSetContainerSlot, CSetHeldItem, EquipmentSlot,
|
CBlockEntityData, CBlockUpdate, COpenSignEditor, CSetContainerSlot, CSetHeldItem, EquipmentSlot,
|
||||||
};
|
};
|
||||||
use pumpkin_protocol::codec::slot::Slot;
|
use pumpkin_protocol::codec::slot::Slot;
|
||||||
use pumpkin_protocol::codec::var_int::VarInt;
|
use pumpkin_protocol::codec::var_int::VarInt;
|
||||||
@ -835,9 +835,22 @@ impl Player {
|
|||||||
let location = player_action.location;
|
let location = player_action.location;
|
||||||
let entity = &self.living_entity.entity;
|
let entity = &self.living_entity.entity;
|
||||||
let world = &entity.world.read().await;
|
let world = &entity.world.read().await;
|
||||||
let block = world.get_block(&location).await;
|
let block = world.get_block(&location).await.unwrap();
|
||||||
let state = world.get_block_state(&location).await.unwrap();
|
let state = world.get_block_state(&location).await.unwrap();
|
||||||
|
|
||||||
|
if let Some(held) = self.inventory.lock().await.held_item() {
|
||||||
|
if !server.item_registry.can_mine(&held.item, &self) {
|
||||||
|
self.client
|
||||||
|
.send_packet(&CBlockUpdate::new(
|
||||||
|
&location,
|
||||||
|
VarInt(i32::from(state.id)),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
self.update_sequence(player_action.sequence.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: do validation
|
// TODO: do validation
|
||||||
// TODO: Config
|
// TODO: Config
|
||||||
if self.gamemode.load() == GameMode::Creative {
|
if self.gamemode.load() == GameMode::Creative {
|
||||||
@ -846,37 +859,33 @@ impl Player {
|
|||||||
world
|
world
|
||||||
.break_block(&location, Some(self.clone()), false)
|
.break_block(&location, Some(self.clone()), false)
|
||||||
.await;
|
.await;
|
||||||
if let Ok(block) = block {
|
server
|
||||||
server
|
.block_registry
|
||||||
.block_registry
|
.broken(block, &self, location, server)
|
||||||
.broken(block, &self, location, server)
|
.await;
|
||||||
.await;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.start_mining_time.store(
|
self.start_mining_time.store(
|
||||||
self.tick_counter.load(std::sync::atomic::Ordering::Relaxed),
|
self.tick_counter.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
std::sync::atomic::Ordering::Relaxed,
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
);
|
);
|
||||||
if let Ok(block) = block {
|
if !state.air {
|
||||||
if !state.air {
|
let speed = block::calc_block_breaking(&self, state, &block.name).await;
|
||||||
let speed = block::calc_block_breaking(&self, state, &block.name).await;
|
// Instant break
|
||||||
// Instant break
|
if speed >= 1.0 {
|
||||||
if speed >= 1.0 {
|
world.break_block(&location, Some(self.clone()), true).await;
|
||||||
world.break_block(&location, Some(self.clone()), true).await;
|
server
|
||||||
server
|
.block_registry
|
||||||
.block_registry
|
.broken(block, &self, location, server)
|
||||||
.broken(block, &self, location, server)
|
.await;
|
||||||
.await;
|
} else {
|
||||||
} else {
|
self.mining
|
||||||
self.mining
|
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
*self.mining_pos.lock().await = location;
|
||||||
*self.mining_pos.lock().await = location;
|
let progress = (speed * 10.0) as i32;
|
||||||
let progress = (speed * 10.0) as i32;
|
world.set_block_breaking(entity, location, progress).await;
|
||||||
world.set_block_breaking(entity, location, progress).await;
|
self.current_block_destroy_stage
|
||||||
self.current_block_destroy_stage
|
.store(progress, std::sync::atomic::Ordering::Relaxed);
|
||||||
.store(progress, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.update_sequence(player_action.sequence.0);
|
self.update_sequence(player_action.sequence.0);
|
||||||
@ -1022,14 +1031,13 @@ impl Player {
|
|||||||
let Ok(block) = world.get_block(&location).await else {
|
let Ok(block) = world.get_block(&location).await else {
|
||||||
return Err(BlockPlacingError::NoBaseBlock.into());
|
return Err(BlockPlacingError::NoBaseBlock.into());
|
||||||
};
|
};
|
||||||
|
let sneaking = self
|
||||||
|
.living_entity
|
||||||
|
.entity
|
||||||
|
.sneaking
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed);
|
||||||
let Some(stack) = held_item else {
|
let Some(stack) = held_item else {
|
||||||
if !self
|
if !sneaking {
|
||||||
.living_entity
|
|
||||||
.entity
|
|
||||||
.sneaking
|
|
||||||
.load(std::sync::atomic::Ordering::Relaxed)
|
|
||||||
{
|
|
||||||
// Using block with empty hand
|
// Using block with empty hand
|
||||||
server
|
server
|
||||||
.block_registry
|
.block_registry
|
||||||
@ -1044,12 +1052,7 @@ impl Player {
|
|||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
if !self
|
if !sneaking {
|
||||||
.living_entity
|
|
||||||
.entity
|
|
||||||
.sneaking
|
|
||||||
.load(std::sync::atomic::Ordering::Relaxed)
|
|
||||||
{
|
|
||||||
let action_result = server
|
let action_result = server
|
||||||
.block_registry
|
.block_registry
|
||||||
.use_with_item(block, self, location, &stack.item, server)
|
.use_with_item(block, self, location, &stack.item, server)
|
||||||
|
|||||||
@ -121,7 +121,7 @@ impl Server {
|
|||||||
],
|
],
|
||||||
command_dispatcher,
|
command_dispatcher,
|
||||||
block_registry: super::block::default_registry(),
|
block_registry: super::block::default_registry(),
|
||||||
item_registry: super::item::default_registry(),
|
item_registry: super::item::items::default_registry(),
|
||||||
block_properties_manager: default_block_properties_manager(),
|
block_properties_manager: default_block_properties_manager(),
|
||||||
auth_client,
|
auth_client,
|
||||||
key_store: KeyStore::new(),
|
key_store: KeyStore::new(),
|
||||||
|
|||||||
@ -306,6 +306,8 @@ impl World {
|
|||||||
.entity
|
.entity
|
||||||
.bounding_box
|
.bounding_box
|
||||||
.load()
|
.load()
|
||||||
|
// This is vanilla, but TODO: change this when is in a Vehicle
|
||||||
|
.expand(1.0, 0.5, 1.0)
|
||||||
.intersects(&entity.get_entity().bounding_box.load())
|
.intersects(&entity.get_entity().bounding_box.load())
|
||||||
{
|
{
|
||||||
collied_player = Some(player.clone());
|
collied_player = Some(player.clone());
|
||||||
@ -402,7 +404,7 @@ impl World {
|
|||||||
// also send his info to everyone else
|
// also send his info to everyone else
|
||||||
log::debug!("Broadcasting player info for {}", player.gameprofile.name);
|
log::debug!("Broadcasting player info for {}", player.gameprofile.name);
|
||||||
self.broadcast_packet_all(&CPlayerInfoUpdate::new(
|
self.broadcast_packet_all(&CPlayerInfoUpdate::new(
|
||||||
0x01 | 0x08,
|
0x01 | 0x04 | 0x08,
|
||||||
&[pumpkin_protocol::client::play::Player {
|
&[pumpkin_protocol::client::play::Player {
|
||||||
uuid: gameprofile.id,
|
uuid: gameprofile.id,
|
||||||
actions: vec![
|
actions: vec![
|
||||||
@ -411,6 +413,7 @@ impl World {
|
|||||||
properties: &gameprofile.properties,
|
properties: &gameprofile.properties,
|
||||||
},
|
},
|
||||||
PlayerAction::UpdateListed(true),
|
PlayerAction::UpdateListed(true),
|
||||||
|
PlayerAction::UpdateGameMode(VarInt(gamemode as i32)),
|
||||||
],
|
],
|
||||||
}],
|
}],
|
||||||
))
|
))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user