Don't require server when spawning a entity

Makes it much simpler
This commit is contained in:
Alexander Medvedev
2025-03-02 16:05:31 +01:00
parent 52e48ec0bd
commit be44ccc8df
20 changed files with 86 additions and 199 deletions

View File

@@ -29,14 +29,14 @@ impl PumpkinBlock for TNTBlock {
player: &Player,
location: BlockPos,
item: &Item,
server: &Server,
_server: &Server,
) -> BlockActionResult {
if *item != Item::FLINT_AND_STEEL || *item == Item::FIRE_CHARGE {
return BlockActionResult::Continue;
}
let world = player.world().await;
world.set_block_state(&location, 0).await;
let entity = server.add_entity(location.to_f64(), EntityType::TNT, &world);
let entity = world.create_entity(location.to_f64(), EntityType::TNT);
let pos = entity.pos.load();
let tnt = Arc::new(TNTEntity::new(entity, DEFAULT_POWER, DEFAULT_FUSE));
world.spawn_entity(tnt.clone()).await;
@@ -50,14 +50,8 @@ impl PumpkinBlock for TNTBlock {
.await;
BlockActionResult::Consume
}
async fn explode(
&self,
_block: &Block,
world: &Arc<World>,
location: BlockPos,
server: &Server,
) {
let entity = server.add_entity(location.to_f64(), EntityType::TNT, world);
async fn explode(&self, _block: &Block, world: &Arc<World>, location: BlockPos) {
let entity = world.create_entity(location.to_f64(), EntityType::TNT);
let fuse = rand::thread_rng().gen_range(0..DEFAULT_FUSE / 4) + DEFAULT_FUSE / 8;
let tnt = Arc::new(TNTEntity::new(entity, DEFAULT_POWER, fuse));
world.spawn_entity(tnt.clone()).await;

View File

@@ -28,7 +28,6 @@ use rand::Rng;
use crate::block::registry::BlockRegistry;
use crate::entity::item::ItemEntity;
use crate::server::Server;
use crate::world::World;
use crate::{block::blocks::crafting_table::CraftingTableBlock, entity::player::Player};
use crate::{block::blocks::jukebox::JukeboxBlock, entity::experience_orb::ExperienceOrbEntity};
@@ -53,17 +52,11 @@ pub fn default_registry() -> Arc<BlockRegistry> {
Arc::new(manager)
}
pub async fn drop_loot(
server: &Server,
world: &Arc<World>,
block: &Block,
pos: &BlockPos,
experience: bool,
) {
pub async fn drop_loot(world: &Arc<World>, block: &Block, pos: &BlockPos, experience: bool) {
if let Some(table) = &block.loot_table {
let loot = table.get_loot();
for item in loot {
drop_stack(server, world, pos, item).await;
drop_stack(world, pos, item).await;
}
}
@@ -72,13 +65,13 @@ pub async fn drop_loot(
let amount = experience.experience.get();
// TODO: Silk touch gives no exp
if amount > 0 {
ExperienceOrbEntity::spawn(world, server, pos.to_f64(), amount as u32).await;
ExperienceOrbEntity::spawn(world, pos.to_f64(), amount as u32).await;
}
}
}
}
async fn drop_stack(server: &Server, world: &Arc<World>, pos: &BlockPos, stack: ItemStack) {
async fn drop_stack(world: &Arc<World>, pos: &BlockPos, stack: ItemStack) {
let height = EntityType::ITEM.dimension[1] / 2.0;
let pos = Vector3::new(
f64::from(pos.0.x) + 0.5 + rand::thread_rng().gen_range(-0.25..0.25),
@@ -86,7 +79,7 @@ async fn drop_stack(server: &Server, world: &Arc<World>, pos: &BlockPos, stack:
f64::from(pos.0.z) + 0.5 + rand::thread_rng().gen_range(-0.25..0.25),
);
let entity = server.add_entity(pos, EntityType::ITEM, world);
let entity = world.create_entity(pos, EntityType::ITEM);
let item_entity = Arc::new(ItemEntity::new(
entity,
stack.item.id,

View File

@@ -34,14 +34,7 @@ pub trait PumpkinBlock: Send + Sync {
fn should_drop_items_on_explosion(&self) -> bool {
true
}
async fn explode(
&self,
_block: &Block,
_world: &Arc<World>,
_location: BlockPos,
_server: &Server,
) {
}
async fn explode(&self, _block: &Block, _world: &Arc<World>, _location: BlockPos) {}
async fn use_with_item(
&self,
_block: &Block,

View File

@@ -45,16 +45,10 @@ impl BlockRegistry {
}
}
pub async fn explode(
&self,
block: &Block,
world: &Arc<World>,
location: BlockPos,
server: &Server,
) {
pub async fn explode(&self, block: &Block, world: &Arc<World>, location: BlockPos) {
let pumpkin_block = self.get_pumpkin_block(block);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block.explode(block, world, location, server).await;
pumpkin_block.explode(block, world, location).await;
}
}

View File

@@ -41,7 +41,7 @@ impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender<'a>,
server: &crate::server::Server,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
@@ -70,9 +70,7 @@ impl CommandExecutor for Executor {
for y in start_y..=end_y {
for z in start_z..=end_z {
let block_position = BlockPos(Vector3 { x, y, z });
world
.break_block(server, &block_position, None, false)
.await;
world.break_block(&block_position, None, false).await;
world.set_block_state(&block_position, block_state_id).await;
placed_blocks += 1;
}

View File

@@ -34,7 +34,7 @@ impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender<'a>,
server: &crate::server::Server,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
@@ -49,7 +49,7 @@ impl CommandExecutor for Executor {
let success = match mode {
Mode::Destroy => {
world.clone().break_block(server, &pos, None, false).await;
world.clone().break_block(&pos, None, false).await;
world.set_block_state(&pos, block_state_id).await;
true
}

View File

@@ -28,7 +28,7 @@ impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender<'a>,
server: &crate::server::Server,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let entity = SummonableEntitiesArgumentConsumer::find_arg(args, ARG_ENTITY)?;
@@ -37,7 +37,7 @@ impl CommandExecutor for Executor {
// TODO: Make this work in console
if let Some(player) = sender.as_player() {
let pos = pos.unwrap_or(player.living_entity.entity.pos.load());
let mob = mob::from_type(entity, server, pos, &player.world().await).await;
let mob = mob::from_type(entity, pos, &player.world().await).await;
player.world().await.spawn_entity(mob).await;
sender
.send_message(TextComponent::translate(

View File

@@ -24,12 +24,12 @@ impl ExperienceOrbEntity {
}
}
pub async fn spawn(world: &Arc<World>, server: &Server, position: Vector3<f64>, amount: u32) {
pub async fn spawn(world: &Arc<World>, position: Vector3<f64>, amount: u32) {
let mut amount = amount;
while amount > 0 {
let i = Self::round_to_orb_size(amount);
amount -= i;
let entity = server.add_entity(position, EntityType::EXPERIENCE_ORB, world);
let entity = world.create_entity(position, EntityType::EXPERIENCE_ORB);
let orb = Arc::new(Self::new(entity, i));
world.spawn_entity(orb).await;
}

View File

@@ -53,11 +53,10 @@ impl EntityBase for MobEntity {
pub async fn from_type(
entity_type: EntityType,
server: &Server,
position: Vector3<f64>,
world: &Arc<World>,
) -> Arc<dyn EntityBase> {
let entity = server.add_entity(position, entity_type, world);
let entity = world.create_entity(position, entity_type);
let mob = MobEntity {
living_entity: LivingEntity::new(entity),
goals: Mutex::new(vec![]),

View File

@@ -28,7 +28,10 @@ use pumpkin_util::math::{
wrap_degrees,
};
use serde::Serialize;
use std::sync::{Arc, atomic::AtomicBool};
use std::sync::{
Arc,
atomic::{AtomicBool, AtomicI32},
};
use tokio::sync::RwLock;
use crate::world::World;
@@ -74,6 +77,8 @@ pub trait EntityBase: Send + Sync {
fn get_living_entity(&self) -> Option<&LivingEntity>;
}
static CURRENT_ID: AtomicI32 = AtomicI32::new(0);
/// Represents a not living Entity (e.g. Item, Egg, Snowball...)
pub struct Entity {
/// A unique identifier for the entity
@@ -121,24 +126,24 @@ pub struct Entity {
}
impl Entity {
#[expect(clippy::too_many_arguments)]
pub fn new(
entity_id: EntityId,
entity_uuid: uuid::Uuid,
world: Arc<World>,
position: Vector3<f64>,
entity_type: EntityType,
standing_eye_height: f32,
bounding_box: AtomicCell<BoundingBox>,
bounding_box_size: AtomicCell<EntityDimensions>,
invulnerable: bool,
) -> Self {
let floor_x = position.x.floor() as i32;
let floor_y = position.y.floor() as i32;
let floor_z = position.z.floor() as i32;
let bounding_box_size = EntityDimensions {
width: entity_type.dimension[0],
height: entity_type.dimension[1],
};
Self {
entity_id,
entity_id: CURRENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
entity_uuid,
entity_type,
on_ground: AtomicBool::new(false),
@@ -154,10 +159,15 @@ impl Entity {
head_yaw: AtomicCell::new(0.0),
pitch: AtomicCell::new(0.0),
velocity: AtomicCell::new(Vector3::new(0.0, 0.0, 0.0)),
standing_eye_height,
standing_eye_height: entity_type.eye_height,
pose: AtomicCell::new(EntityPose::Standing),
bounding_box,
bounding_box_size,
bounding_box: AtomicCell::new(BoundingBox::new_from_pos(
position.x,
position.y,
position.z,
&bounding_box_size,
)),
bounding_box_size: AtomicCell::new(bounding_box_size),
invulnerable: AtomicBool::new(invulnerable),
damage_immunities: Vec::new(),
}

View File

@@ -51,10 +51,7 @@ use pumpkin_protocol::{
use pumpkin_util::{
GameMode,
math::{
boundingbox::{BoundingBox, EntityDimensions},
experience,
position::BlockPos,
vector2::Vector2,
boundingbox::BoundingBox, experience, position::BlockPos, vector2::Vector2,
vector3::Vector3,
},
permission::PermissionLvl,
@@ -151,12 +148,7 @@ pub struct Player {
}
impl Player {
pub async fn new(
client: Arc<Client>,
world: Arc<World>,
entity_id: EntityId,
gamemode: GameMode,
) -> Self {
pub async fn new(client: Arc<Client>, world: Arc<World>, gamemode: GameMode) -> Self {
let gameprofile = client.gameprofile.lock().await.clone().map_or_else(
|| {
log::error!("Client {} has no game profile!", client.id);
@@ -173,21 +165,13 @@ impl Player {
let gameprofile_clone = gameprofile.clone();
let config = client.config.lock().await.clone().unwrap_or_default();
let bounding_box_size = EntityDimensions {
width: EntityType::PLAYER.dimension[0],
height: EntityType::PLAYER.dimension[1],
};
Self {
living_entity: LivingEntity::new(Entity::new(
entity_id,
player_uuid,
world,
Vector3::new(0.0, 0.0, 0.0),
EntityType::PLAYER,
EntityType::PLAYER.eye_height,
AtomicCell::new(BoundingBox::new_default(&bounding_box_size)),
AtomicCell::new(bounding_box_size),
matches!(gamemode, GameMode::Creative | GameMode::Spectator),
)),
config: Mutex::new(config),
@@ -1018,12 +1002,11 @@ impl Player {
.await;
}
pub async fn drop_item(&self, server: &Server, item_id: u16, count: u32) {
let entity = server.add_entity(
self.living_entity.entity.pos.load(),
EntityType::ITEM,
&self.world().await,
);
pub async fn drop_item(&self, item_id: u16, count: u32) {
let entity = self
.world()
.await
.create_entity(self.living_entity.entity.pos.load(), EntityType::ITEM);
// TODO: Merge stacks together
let item_entity = Arc::new(ItemEntity::new(entity, item_id, count));
@@ -1031,11 +1014,11 @@ impl Player {
item_entity.send_meta_packet().await;
}
pub async fn drop_held_item(&self, server: &Server, drop_stack: bool) {
pub async fn drop_held_item(&self, drop_stack: bool) {
let mut inv = self.inventory.lock().await;
if let Some(item_stack) = inv.held_item_mut() {
let drop_amount = if drop_stack { item_stack.item_count } else { 1 };
self.drop_item(server, item_stack.item.id, u32::from(drop_amount))
self.drop_item(item_stack.item.id, u32::from(drop_amount))
.await;
inv.decrease_current_stack(drop_amount);
}
@@ -1323,7 +1306,7 @@ impl Player {
.await;
}
SSetCreativeSlot::PACKET_ID => {
self.handle_set_creative_slot(server, SSetCreativeSlot::read(bytebuf)?)
self.handle_set_creative_slot(SSetCreativeSlot::read(bytebuf)?)
.await?;
}
SSwingArm::PACKET_ID => {

View File

@@ -3,7 +3,6 @@ use std::sync::Arc;
use crate::entity::player::Player;
use crate::entity::projectile::ThrownItemEntity;
use crate::item::pumpkin_item::PumpkinItem;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_data::entity::EntityType;
use pumpkin_data::item::Item;
@@ -17,7 +16,7 @@ const POWER: f32 = 1.5;
#[async_trait]
impl PumpkinItem for EggItem {
async fn normal_use(&self, _block: &Item, player: &Player, server: &Server) {
async fn normal_use(&self, _block: &Item, player: &Player) {
let position = player.position();
let world = player.world().await;
world
@@ -28,7 +27,7 @@ impl PumpkinItem for EggItem {
)
.await;
// TODO: Implement eggs the right way, so there is a chance of spawning chickens
let entity = server.add_entity(position, EntityType::EGG, &world);
let entity = world.create_entity(position, EntityType::EGG);
let snowball = ThrownItemEntity::new(entity, &player.living_entity.entity);
let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.load();

View File

@@ -3,7 +3,6 @@ use std::sync::Arc;
use crate::entity::player::Player;
use crate::entity::projectile::ThrownItemEntity;
use crate::item::pumpkin_item::PumpkinItem;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_data::entity::EntityType;
use pumpkin_data::item::Item;
@@ -17,7 +16,7 @@ const POWER: f32 = 1.5;
#[async_trait]
impl PumpkinItem for SnowBallItem {
async fn normal_use(&self, _block: &Item, player: &Player, server: &Server) {
async fn normal_use(&self, _block: &Item, player: &Player) {
let position = player.position();
let world = player.world().await;
world
@@ -27,7 +26,7 @@ impl PumpkinItem for SnowBallItem {
&position,
)
.await;
let entity = server.add_entity(position, EntityType::SNOWBALL, &world);
let entity = world.create_entity(position, EntityType::SNOWBALL);
let snowball = ThrownItemEntity::new(entity, &player.living_entity.entity);
let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.load();

View File

@@ -11,7 +11,7 @@ pub trait ItemMetadata {
#[async_trait]
pub trait PumpkinItem: Send + Sync {
async fn normal_use(&self, _block: &Item, _player: &Player, _server: &Server) {}
async fn normal_use(&self, _block: &Item, _player: &Player) {}
async fn use_on_block(
&self,
_item: &Item,

View File

@@ -18,10 +18,10 @@ impl ItemRegistry {
self.items.insert(T::ID, Arc::new(item));
}
pub async fn on_use(&self, item: &Item, player: &Player, server: &Server) {
pub async fn on_use(&self, item: &Item, player: &Player) {
let pumpkin_block = self.get_pumpkin_item(item.id);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block.normal_use(item, player, server).await;
pumpkin_block.normal_use(item, player).await;
}
}

View File

@@ -158,7 +158,6 @@ impl Player {
let click_slot = click.slot;
self.match_click_behaviour(
server,
opened_container.as_deref_mut(),
click,
drag_handler,
@@ -221,7 +220,6 @@ impl Player {
async fn match_click_behaviour(
&self,
server: &Server,
opened_container: Option<&mut Box<dyn Container>>,
click: Click,
drag_handler: &DragHandler,
@@ -231,7 +229,6 @@ impl Player {
match click.click_type {
ClickType::MouseClick(mouse_click) => {
self.mouse_click(
server,
opened_container,
mouse_click,
click.slot,
@@ -288,7 +285,6 @@ impl Player {
match drop_type {
DropType::FullStack => {
self.drop_item(
server,
item_stack.item.id,
u32::from(item_stack.item_count),
)
@@ -296,7 +292,7 @@ impl Player {
*slots[slot] = None;
}
DropType::SingleItem => {
self.drop_item(server, item_stack.item.id, 1).await;
self.drop_item(item_stack.item.id, 1).await;
item_stack.item_count -= 1;
if item_stack.item_count == 0 {
*slots[slot] = None;
@@ -312,7 +308,6 @@ impl Player {
async fn mouse_click(
&self,
server: &Server,
opened_container: Option<&mut Box<dyn Container>>,
mouse_click: MouseClick,
slot: container_click::Slot,
@@ -329,16 +324,12 @@ impl Player {
if let Some(item_stack) = carried_item.as_mut() {
match mouse_click {
MouseClick::Left => {
self.drop_item(
server,
item_stack.item.id,
u32::from(item_stack.item_count),
)
.await;
self.drop_item(item_stack.item.id, u32::from(item_stack.item_count))
.await;
*carried_item = None;
}
MouseClick::Right => {
self.drop_item(server, item_stack.item.id, 1).await;
self.drop_item(item_stack.item.id, 1).await;
item_stack.item_count -= 1;
if item_stack.item_count == 0 {
*carried_item = None;

View File

@@ -844,7 +844,7 @@ impl Player {
// Block break & block break sound
world
.break_block(server, &location, Some(self.clone()), false)
.break_block(&location, Some(self.clone()), false)
.await;
if let Ok(block) = block {
server
@@ -863,9 +863,7 @@ impl Player {
let speed = block::calc_block_breaking(&self, state, &block.name).await;
// Instant break
if speed >= 1.0 {
world
.break_block(server, &location, Some(self.clone()), true)
.await;
world.break_block(&location, Some(self.clone()), true).await;
server
.block_registry
.broken(block, &self, location, server)
@@ -924,9 +922,7 @@ impl Player {
if let Ok(state) = state {
let drop = self.gamemode.load() != GameMode::Creative
&& self.can_harvest(state, &block.name).await;
world
.break_block(server, &location, Some(self.clone()), drop)
.await;
world.break_block(&location, Some(self.clone()), drop).await;
}
server
.block_registry
@@ -936,10 +932,10 @@ impl Player {
self.update_sequence(player_action.sequence.0);
}
Status::DropItem => {
self.drop_held_item(server, false).await;
self.drop_held_item(false).await;
}
Status::DropItemStack => {
self.drop_held_item(server, true).await;
self.drop_held_item(true).await;
}
Status::ShootArrowOrFinishEating | Status::SwapItem => {
log::debug!("todo");
@@ -1079,8 +1075,7 @@ impl Player {
}
// check if item is a spawn egg
if let Some(entity) = entity_from_egg(stack.item.id) {
self.spawn_entity_from_egg(entity, server, location, &face)
.await;
self.spawn_entity_from_egg(entity, location, &face).await;
should_try_decrement = true;
};
@@ -1137,7 +1132,7 @@ impl Player {
return;
}
if let Some(held) = self.inventory().lock().await.held_item() {
server.item_registry.on_use(&held.item, self, server).await;
server.item_registry.on_use(&held.item, self).await;
}
}
@@ -1157,7 +1152,6 @@ impl Player {
pub async fn handle_set_creative_slot(
&self,
server: &Server,
packet: SSetCreativeSlot,
) -> Result<(), InventoryError> {
if self.gamemode.load() != GameMode::Creative {
@@ -1173,7 +1167,7 @@ impl Player {
.set_slot(packet.slot as usize, item_stack, true)?;
} else if let Some(item_stack) = item_stack {
// Item drop
self.drop_item(server, item_stack.item.id, u32::from(item_stack.item_count))
self.drop_item(item_stack.item.id, u32::from(item_stack.item_count))
.await;
};
Ok(())
@@ -1258,7 +1252,6 @@ impl Player {
async fn spawn_entity_from_egg(
&self,
entity_type: EntityType,
server: &Server,
location: BlockPos,
face: &BlockDirection,
) {
@@ -1274,13 +1267,7 @@ impl Player {
let world = self.world().await;
// create new mob and uuid based on spawn egg id
let mob = mob::from_type(
EntityType::from_raw(entity_type.id).unwrap(),
server,
pos,
&world,
)
.await;
let mob = mob::from_type(EntityType::from_raw(entity_type.id).unwrap(), pos, &world).await;
// set the rotation
mob.get_entity().set_rotation(yaw, 0.0);

View File

@@ -3,7 +3,7 @@ use crate::block::properties::BlockPropertiesManager;
use crate::block::registry::BlockRegistry;
use crate::command::commands::default_dispatcher;
use crate::command::commands::defaultgamemode::DefaultGamemode;
use crate::entity::{Entity, EntityId};
use crate::entity::EntityId;
use crate::item::registry::ItemRegistry;
use crate::net::EncryptionError;
use crate::world::custom_bossbar::CustomBossbars;
@@ -11,19 +11,15 @@ use crate::{
command::dispatcher::CommandDispatcher, entity::player::Player, net::Client, world::World,
};
use connection_cache::{CachedBranding, CachedStatus};
use crossbeam::atomic::AtomicCell;
use key_store::KeyStore;
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
use pumpkin_data::entity::EntityType;
use pumpkin_inventory::drag_handler::DragHandler;
use pumpkin_inventory::{Container, OpenContainer};
use pumpkin_protocol::client::login::CEncryptionRequest;
use pumpkin_protocol::{ClientPacket, client::config::CPluginMessage};
use pumpkin_registry::{DimensionType, Registry};
use pumpkin_util::math::boundingbox::{BoundingBox, EntityDimensions};
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector2::Vector2;
use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::text::TextComponent;
use pumpkin_world::block::registry::Block;
use pumpkin_world::dimension::Dimension;
@@ -32,10 +28,7 @@ use std::collections::HashMap;
use std::net::IpAddr;
use std::sync::atomic::AtomicU32;
use std::{
sync::{
Arc,
atomic::{AtomicI32, Ordering},
},
sync::{Arc, atomic::Ordering},
time::Duration,
};
use tokio::sync::{Mutex, RwLock};
@@ -72,8 +65,6 @@ pub struct Server {
// TODO: should have per player open_containers
pub open_containers: RwLock<HashMap<u64, OpenContainer>>,
pub drag_handler: DragHandler,
/// Assigns unique IDs to entities.
entity_id: AtomicI32,
/// Assigns unique IDs to containers.
container_id: AtomicU32,
/// Manages authentication with a authentication server, if enabled.
@@ -120,8 +111,6 @@ impl Server {
cached_registry: Registry::get_synced(),
open_containers: RwLock::new(HashMap::new()),
drag_handler: DragHandler::new(),
// 0 is invalid
entity_id: 2.into(),
container_id: 0.into(),
worlds: RwLock::new(vec![Arc::new(world)]),
dimensions: vec![
@@ -179,13 +168,12 @@ impl Server {
///
/// You still have to spawn the Player in the World to make then to let them Join and make them Visible
pub async fn add_player(&self, client: Arc<Client>) -> (Arc<Player>, Arc<World>) {
let entity_id = self.new_entity_id();
let gamemode = self.defaultgamemode.lock().await.gamemode;
// Basically the default world
// TODO: select default from config
let world = &self.worlds.read().await[0];
let player = Arc::new(Player::new(client, world.clone(), entity_id, gamemode).await);
let player = Arc::new(Player::new(client, world.clone(), gamemode).await);
world
.add_player(player.gameprofile.id, player.clone())
.await;
@@ -213,49 +201,6 @@ impl Server {
log::info!("Completed world save");
}
/// Adds a new living entity to the server. This does not Spawn the entity
///
/// # Returns
///
/// A tuple containing:
///
/// - `Arc<LivingEntity>`: A reference to the newly created living entity.
/// - `Arc<World>`: A reference to the world that the living entity was added to.
/// - `Uuid`: The uuid of the newly created living entity to be used to send to the client.
pub fn add_entity(
&self,
position: Vector3<f64>,
entity_type: EntityType,
world: &Arc<World>,
) -> Entity {
let entity_id = self.new_entity_id();
// TODO: this should be resolved to a integer using a macro when calling this function
let bounding_box_size = EntityDimensions {
width: entity_type.dimension[0],
height: entity_type.dimension[1],
};
// TODO: standing eye height should be per mob
let new_uuid = uuid::Uuid::new_v4();
Entity::new(
entity_id,
new_uuid,
world.clone(),
position,
entity_type,
entity_type.eye_height,
AtomicCell::new(BoundingBox::new_from_pos(
position.x,
position.y,
position.z,
&bounding_box_size,
)),
AtomicCell::new(bounding_box_size),
false,
)
}
pub async fn try_get_container(
&self,
player_id: EntityId,
@@ -446,12 +391,6 @@ impl Server {
false
}
/// Generates a new entity id
/// This should be global
pub fn new_entity_id(&self) -> EntityId {
self.entity_id.fetch_add(1, Ordering::SeqCst)
}
/// Generates a new container id
pub fn new_container_id(&self) -> u32 {
self.container_id.fetch_add(1, Ordering::SeqCst)

View File

@@ -82,10 +82,10 @@ impl Explosion {
let block = world.get_block(&pos).await.unwrap();
let pumpkin_block = server.block_registry.get_pumpkin_block(block);
if pumpkin_block.is_none_or(|s| s.should_drop_items_on_explosion()) {
drop_loot(server, world, block, &pos, false).await;
drop_loot(world, block, &pos, false).await;
}
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block.explode(block, world, pos, server).await;
pumpkin_block.explode(block, world, pos).await;
}
}
}

View File

@@ -1003,6 +1003,15 @@ impl World {
}
}
pub fn create_entity(
self: &Arc<Self>,
position: Vector3<f64>,
entity_type: EntityType,
) -> Entity {
let uuid = uuid::Uuid::new_v4();
Entity::new(uuid, self.clone(), position, entity_type, false)
}
/// Adds a entity to the world.
pub async fn spawn_entity(&self, entity: Arc<dyn EntityBase>) {
let base_entity = entity.get_entity();
@@ -1087,7 +1096,6 @@ impl World {
pub async fn break_block(
self: &Arc<Self>,
server: &Server,
position: &BlockPos,
cause: Option<Arc<Player>>,
drop: bool,
@@ -1112,7 +1120,7 @@ impl World {
);
if drop {
block::drop_loot(server, self, block, position, true).await;
block::drop_loot(self, block, position, true).await;
}
match cause {