fix: unix rlimit
This commit is contained in:
parent
f8d1627697
commit
9258bb9023
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -3475,6 +3475,7 @@ dependencies = [
|
||||
"hyper",
|
||||
"image",
|
||||
"indexmap",
|
||||
"libc",
|
||||
"libloading",
|
||||
"notify",
|
||||
"num-bigint 0.5.1",
|
||||
|
||||
@ -163,6 +163,7 @@ heck = { version = "0.5", default-features = false }
|
||||
hmac = { version = "=0.13.0", default-features = false }
|
||||
indexmap = { version = "2.14", default-features = false, features = ["std"] }
|
||||
itertools = { version = "0.15.0", default-features = false, features = ["use_std"] }
|
||||
libc = { version = "0.2", default-features = false }
|
||||
libloading = { version = "0.9", default-features = false, features = ["std"] }
|
||||
lru = { version = "0.18.3", default-features = false }
|
||||
lz4-java-wrc = { version = "0.2.0", default-features = false, features = ["lz4_flex"] }
|
||||
|
||||
@ -17,7 +17,7 @@ pub struct QueryConfig {
|
||||
impl Default for QueryConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
address: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 25565),
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,4 +379,3 @@ impl ClientPacket for CSpawnLivingEntity {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -100,6 +100,7 @@ rustc-hash.workspace = true
|
||||
tokio-util = { workspace = true, features = ["rt"] }
|
||||
|
||||
# System details & Rustc version
|
||||
libc = { workspace = true }
|
||||
sysinfo.workspace = true
|
||||
rustc_version_runtime.workspace = true
|
||||
|
||||
|
||||
@ -59,7 +59,8 @@ impl BlockBehaviour for FarmlandBlock {
|
||||
let mut props = FarmlandProperties::default(args.block);
|
||||
let mut new_moisture = 7;
|
||||
if let Some(server) = args.world.server.upgrade() {
|
||||
let mut event = crate::plugin::api::events::block::moisture_change::MoistureChangeEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::block::moisture_change::MoistureChangeEvent::new(
|
||||
*args.position,
|
||||
args.world.clone(),
|
||||
new_moisture,
|
||||
|
||||
@ -102,7 +102,8 @@ impl BlockBehaviour for LeavesBlock {
|
||||
let props = OakLeavesLikeProperties::from_state_id(state_id);
|
||||
if !props.persistent && props.distance == DECAY_DISTANCE {
|
||||
if let Some(server) = args.world.server.upgrade() {
|
||||
let mut event = crate::plugin::api::events::block::leaves_decay::LeavesDecayEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::block::leaves_decay::LeavesDecayEvent::new(
|
||||
*args.position,
|
||||
args.world.clone(),
|
||||
);
|
||||
|
||||
@ -74,7 +74,8 @@ trait CropBlockBase: PlantBlockBase {
|
||||
if rand::rng().random_range(0..=(25.0 / f).floor() as i64) == 0 {
|
||||
let new_state_id = self.state_with_age(block, state, age + 1);
|
||||
if let Some(server) = world.server.upgrade() {
|
||||
let mut event = crate::plugin::api::events::block::block_grow::BlockGrowEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::block::block_grow::BlockGrowEvent::new(
|
||||
world.clone(),
|
||||
block,
|
||||
state,
|
||||
|
||||
@ -56,10 +56,7 @@ impl BlockBehaviour for SweetBerryBushBlock {
|
||||
}
|
||||
props.age = 1;
|
||||
for stack in drops {
|
||||
args.world.drop_stack(
|
||||
args.position,
|
||||
stack,
|
||||
);
|
||||
args.world.drop_stack(args.position, stack);
|
||||
}
|
||||
args.world.set_block_state(
|
||||
args.position,
|
||||
|
||||
@ -134,7 +134,8 @@ impl CrafterBlock {
|
||||
|
||||
let mut result_stack = ItemStack::new(recipe_result.count, item);
|
||||
if let Some(server) = world.server.upgrade() {
|
||||
let mut event = crate::plugin::api::events::block::crafter_craft::CrafterCraftEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::block::crafter_craft::CrafterCraftEvent::new(
|
||||
*pos,
|
||||
world.clone(),
|
||||
result_stack.clone(),
|
||||
|
||||
@ -465,7 +465,8 @@ impl crate::block::entities::BlockEntity for BrewingStandBlockEntity {
|
||||
if fuel_event.cancelled {
|
||||
false
|
||||
} else {
|
||||
self.fuel.store(fuel_event.fuel_power as i32, Ordering::Relaxed);
|
||||
self.fuel
|
||||
.store(fuel_event.fuel_power as i32, Ordering::Relaxed);
|
||||
items[4].decrement(1);
|
||||
true
|
||||
}
|
||||
@ -506,12 +507,15 @@ impl crate::block::entities::BlockEntity for BrewingStandBlockEntity {
|
||||
}
|
||||
} else if brewable && self.fuel.load(Ordering::Relaxed) > 0 {
|
||||
let brew_time = if let Some(server) = world.server.upgrade() {
|
||||
let mut start_event = crate::plugin::api::events::block::brewing_start::BrewingStartEvent::new(
|
||||
let mut start_event =
|
||||
crate::plugin::api::events::block::brewing_start::BrewingStartEvent::new(
|
||||
self.position,
|
||||
world.clone(),
|
||||
400,
|
||||
);
|
||||
server.plugin_manager.fire_blocking(&server, &mut start_event);
|
||||
server
|
||||
.plugin_manager
|
||||
.fire_blocking(&server, &mut start_event);
|
||||
if start_event.cancelled {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -527,7 +527,8 @@ impl BlockRegistry {
|
||||
}
|
||||
if behaviour.is_bonemeal_success(args) {
|
||||
if let Some(server) = world.server.upgrade() {
|
||||
let mut event = crate::plugin::api::events::block::block_fertilize::BlockFertilizeEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::block::block_fertilize::BlockFertilizeEvent::new(
|
||||
*position,
|
||||
world.clone(),
|
||||
None,
|
||||
|
||||
@ -8,6 +8,7 @@ use crate::command::string_reader::StringReader;
|
||||
use crate::command::suggestion::suggestions::{Suggestions, SuggestionsBuilder};
|
||||
use pumpkin_data::entity::EntityType;
|
||||
use pumpkin_data::translation;
|
||||
use pumpkin_protocol::java::client::play::SuggestionProviders;
|
||||
use pumpkin_util::identifier::Identifier;
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use std::any::Any;
|
||||
@ -144,6 +145,7 @@ impl ArgumentType for ResourceArgument {
|
||||
if self.0 == ENTITY_TYPE_REGISTRY {
|
||||
let entity_types = EntityType::ALL
|
||||
.iter()
|
||||
.filter(|entity_type| entity_type.summonable)
|
||||
.map(|entity_type| format!("minecraft:{}", entity_type.resource_name));
|
||||
suggestions_builder
|
||||
.filter_and_suggest_iter(entity_types)
|
||||
@ -216,6 +218,10 @@ impl ArgumentType for ResourceArgument {
|
||||
identifier: self.0.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn override_suggestion_providers(&self) -> Option<SuggestionProviders> {
|
||||
(self.0 == ENTITY_TYPE_REGISTRY).then_some(SuggestionProviders::SummonableEntities)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceArgument {
|
||||
@ -228,9 +234,20 @@ impl ResourceArgument {
|
||||
TextComponent::text(format!("Could not find argument with name '{name}'")),
|
||||
);
|
||||
let node = context
|
||||
.tree
|
||||
.nodes
|
||||
.iter()
|
||||
.find_map(|node| {
|
||||
.rev()
|
||||
.find_map(|parsed| {
|
||||
if let AttachedNode::Argument(cur) = &context.tree[parsed.node]
|
||||
&& cur.meta.name == name
|
||||
{
|
||||
Some(cur)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.or_else(|| {
|
||||
context.tree.iter().find_map(|node| {
|
||||
if let AttachedNode::Argument(cur) = node
|
||||
&& cur.meta.name == name
|
||||
{
|
||||
@ -239,6 +256,7 @@ impl ResourceArgument {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.ok_or(missing_argument.clone())?;
|
||||
let invalid_argument =
|
||||
DISPATCHER_PARSE_EXCEPTION.create_without_context(TextComponent::text(format!(
|
||||
|
||||
@ -1,22 +1,41 @@
|
||||
use pumpkin_data::translation;
|
||||
use pumpkin_util::PermissionLvl;
|
||||
use pumpkin_util::difficulty::Difficulty;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry};
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::command::argument_builder::{ArgumentBuilder, argument, command};
|
||||
use crate::command::argument_types::coordinates::vec3::Vec3ArgumentType;
|
||||
use crate::command::argument_types::nbt::NbtCompoundArgumentType;
|
||||
use crate::command::argument_types::resource::{ENTITY_TYPE_ARGUMENT, ResourceArgument};
|
||||
use crate::command::context::command_context::CommandContext;
|
||||
use crate::command::errors::error_types::CommandErrorType;
|
||||
use crate::command::node::dispatcher::CommandDispatcher;
|
||||
use crate::command::node::{CommandExecutor, CommandExecutorResult};
|
||||
use crate::entity::r#type::from_type;
|
||||
use crate::world::World;
|
||||
|
||||
const DESCRIPTION: &str = "Spawns an entity at position.";
|
||||
const PERMISSION: &str = "minecraft:command.summon";
|
||||
|
||||
const ERROR_FAILED_PEACEFUL: CommandErrorType<0> = CommandErrorType::new(
|
||||
translation::java::COMMANDS_SUMMON_FAILED_PEACEFUL,
|
||||
translation::bedrock::COMMANDS_SUMMON_FAILED,
|
||||
);
|
||||
const ERROR_DUPLICATE_UUID: CommandErrorType<0> = CommandErrorType::new(
|
||||
translation::java::COMMANDS_SUMMON_FAILED_UUID,
|
||||
translation::bedrock::COMMANDS_SUMMON_FAILED,
|
||||
);
|
||||
const INVALID_POSITION: CommandErrorType<0> = CommandErrorType::new(
|
||||
translation::java::COMMANDS_SUMMON_INVALIDPOSITION,
|
||||
translation::bedrock::COMMANDS_SUMMON_OUTOFWORLD,
|
||||
);
|
||||
|
||||
struct SummonExecutor {
|
||||
has_pos: bool,
|
||||
has_nbt: bool,
|
||||
}
|
||||
|
||||
impl CommandExecutor for SummonExecutor {
|
||||
@ -28,8 +47,42 @@ impl CommandExecutor for SummonExecutor {
|
||||
context.source.position
|
||||
};
|
||||
|
||||
let block_pos = BlockPos::floored_v(pos);
|
||||
if !World::is_valid(block_pos) {
|
||||
return Err(INVALID_POSITION.create_without_context());
|
||||
}
|
||||
|
||||
let world = context.source.world();
|
||||
let entity = from_type(entity_type, pos, world, Uuid::new_v4());
|
||||
let difficulty = world.level_info.load().difficulty;
|
||||
if difficulty == Difficulty::Peaceful && !entity_type.category.is_friendly {
|
||||
return Err(ERROR_FAILED_PEACEFUL.create_without_context());
|
||||
}
|
||||
|
||||
let nbt = if self.has_nbt {
|
||||
Some(NbtCompoundArgumentType::get(context, "nbt")?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let uuid = nbt
|
||||
.and_then(|nbt| nbt.get_uuid("UUID"))
|
||||
.unwrap_or_else(Uuid::new_v4);
|
||||
|
||||
let entity = from_type(entity_type, pos, world, uuid);
|
||||
if let Some(nbt) = nbt {
|
||||
entity.read_nbt_non_mut(nbt);
|
||||
entity.get_entity().set_pos(pos);
|
||||
}
|
||||
|
||||
if world
|
||||
.entities
|
||||
.load()
|
||||
.iter()
|
||||
.any(|e| e.get_entity().entity_uuid == entity.get_entity().entity_uuid)
|
||||
{
|
||||
return Err(ERROR_DUPLICATE_UUID.create_without_context());
|
||||
}
|
||||
|
||||
let name = entity.get_display_name();
|
||||
world.spawn_entity(entity);
|
||||
|
||||
@ -56,11 +109,69 @@ pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistr
|
||||
dispatcher.register(
|
||||
command("summon", DESCRIPTION).requires(PERMISSION).then(
|
||||
argument("entity", ENTITY_TYPE_ARGUMENT.clone())
|
||||
.executes(SummonExecutor { has_pos: false })
|
||||
.executes(SummonExecutor {
|
||||
has_pos: false,
|
||||
has_nbt: false,
|
||||
})
|
||||
.then(
|
||||
argument("pos", Vec3ArgumentType::Default)
|
||||
.executes(SummonExecutor { has_pos: true }),
|
||||
.executes(SummonExecutor {
|
||||
has_pos: true,
|
||||
has_nbt: false,
|
||||
})
|
||||
.then(
|
||||
argument("nbt", NbtCompoundArgumentType).executes(SummonExecutor {
|
||||
has_pos: true,
|
||||
has_nbt: true,
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::command::commands::fetchprofile;
|
||||
use crate::command::context::command_source::CommandSource;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn parse_summon_cat() {
|
||||
let mut dispatcher = CommandDispatcher::new();
|
||||
let registry = PermissionRegistry::default();
|
||||
|
||||
// Register fetchprofile first to ensure its "entity" argument doesn't collide
|
||||
fetchprofile::register(&mut dispatcher, ®istry);
|
||||
register(&mut dispatcher, ®istry);
|
||||
|
||||
let source = Arc::new(CommandSource::dummy());
|
||||
let result = dispatcher.parse_input("summon cat", &source);
|
||||
assert!(result.errors.is_empty());
|
||||
let context = result.context.build("summon cat");
|
||||
let entity_type = ResourceArgument::get_summonable_entity_type(&context, "entity")
|
||||
.expect("Should resolve summonable cat entity type");
|
||||
assert_eq!(entity_type.resource_name, "cat");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_summon_cat_with_pos_and_nbt() {
|
||||
let mut dispatcher = CommandDispatcher::new();
|
||||
let registry = PermissionRegistry::default();
|
||||
|
||||
fetchprofile::register(&mut dispatcher, ®istry);
|
||||
register(&mut dispatcher, ®istry);
|
||||
|
||||
let source = Arc::new(CommandSource::dummy());
|
||||
let result = dispatcher.parse_input("summon cat ~ ~ ~ {NoAI:1b}", &source);
|
||||
assert!(result.errors.is_empty());
|
||||
let context = result.context.build("summon cat ~ ~ ~ {NoAI:1b}");
|
||||
let entity_type = ResourceArgument::get_summonable_entity_type(&context, "entity")
|
||||
.expect("Should resolve summonable cat entity type");
|
||||
assert_eq!(entity_type.resource_name, "cat");
|
||||
let nbt =
|
||||
NbtCompoundArgumentType::get(&context, "nbt").expect("Should resolve NBT argument");
|
||||
assert_eq!(nbt.get_byte("NoAI"), Some(1));
|
||||
}
|
||||
}
|
||||
|
||||
@ -480,7 +480,15 @@ impl CommandSource {
|
||||
/// server (i.e. this is a dummy [`CommandSource`].)
|
||||
#[must_use]
|
||||
pub fn has_permission(&self, permission: &str) -> bool {
|
||||
self.output.has_permission(self.server(), permission)
|
||||
self.server.as_ref().map_or(
|
||||
matches!(
|
||||
self.output,
|
||||
crate::command::CommandSender::Console
|
||||
| crate::command::CommandSender::Rcon(_)
|
||||
| crate::command::CommandSender::Dummy
|
||||
),
|
||||
|server| self.output.has_permission(server, permission),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether this source has the permission provided.
|
||||
|
||||
@ -606,7 +606,8 @@ impl CombatTracker {
|
||||
)
|
||||
}
|
||||
} else if let Some(killer_name) = kill_credit_name.or_else(|| {
|
||||
self.get_killer_entry().and_then(|k| k.attacker_name.clone())
|
||||
self.get_killer_entry()
|
||||
.and_then(|k| k.attacker_name.clone())
|
||||
}) {
|
||||
pumpkin_util::text::TextComponent::translate_cross(
|
||||
format!("death.attack.{msg_id}.player"),
|
||||
|
||||
@ -1666,9 +1666,7 @@ impl LivingEntity {
|
||||
source: Option<&dyn EntityBase>,
|
||||
cause: Option<&dyn EntityBase>,
|
||||
) -> TextComponent {
|
||||
let kill_credit = dyn_self
|
||||
.get_living_entity()
|
||||
.and_then(Self::get_kill_credit);
|
||||
let kill_credit = dyn_self.get_living_entity().and_then(Self::get_kill_credit);
|
||||
let kill_credit_name = kill_credit.as_ref().map(|c| c.get_display_name());
|
||||
|
||||
if let Some(living) = dyn_self.get_living_entity() {
|
||||
@ -1687,7 +1685,11 @@ impl LivingEntity {
|
||||
format!("death.attack.{}", damage_type.message_id),
|
||||
[dyn_self.get_display_name(), cause.get_display_name()],
|
||||
)
|
||||
} else if let Some(killer) = cause.or(source).map(|c| c.get_display_name()).or(kill_credit_name) {
|
||||
} else if let Some(killer) = cause
|
||||
.or(source)
|
||||
.map(|c| c.get_display_name())
|
||||
.or(kill_credit_name)
|
||||
{
|
||||
TextComponent::translate_cross(
|
||||
format!("death.attack.{}.player", damage_type.message_id),
|
||||
format!("death.attack.{}.player", damage_type.message_id),
|
||||
@ -1887,7 +1889,8 @@ impl LivingEntity {
|
||||
if let Some(player_arc) = world.get_player_by_uuid(player.gameprofile.id)
|
||||
&& let Some(server) = world.server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::entity::entity_death::PlayerDeathEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::entity::entity_death::PlayerDeathEvent::new(
|
||||
player_arc,
|
||||
final_death_message.clone(),
|
||||
0,
|
||||
@ -1902,9 +1905,7 @@ impl LivingEntity {
|
||||
player.handle_killed(&final_death_message);
|
||||
}
|
||||
|
||||
if show_death_messages
|
||||
&& let Some(server) = world.server.upgrade()
|
||||
{
|
||||
if show_death_messages && let Some(server) = world.server.upgrade() {
|
||||
for player in server.get_all_players() {
|
||||
player.send_system_message(&final_death_message);
|
||||
}
|
||||
@ -2639,7 +2640,13 @@ impl LivingEntity {
|
||||
| DamageType::STALAGMITE
|
||||
)
|
||||
{
|
||||
let damager_pos = position.map(|p| BlockPos(Vector3::new(p.x.floor() as i32, p.y.floor() as i32, p.z.floor() as i32)));
|
||||
let damager_pos = position.map(|p| {
|
||||
BlockPos(Vector3::new(
|
||||
p.x.floor() as i32,
|
||||
p.y.floor() as i32,
|
||||
p.z.floor() as i32,
|
||||
))
|
||||
});
|
||||
let mut by_block_event =
|
||||
crate::plugin::api::events::entity::entity_damage_by_block::EntityDamageByBlockEvent {
|
||||
entity_id: self.entity.entity_id,
|
||||
@ -2897,8 +2904,7 @@ impl LivingEntity {
|
||||
|
||||
if let Some(attacker) = cause.or(source) {
|
||||
let attacker_id = attacker.get_entity().entity_id;
|
||||
self.last_attacker_id
|
||||
.store(attacker_id, Relaxed);
|
||||
self.last_attacker_id.store(attacker_id, Relaxed);
|
||||
self.last_attacked_time
|
||||
.store(self.entity.age.load(Relaxed), Relaxed);
|
||||
|
||||
|
||||
@ -3371,7 +3371,8 @@ impl Entity {
|
||||
&& let Some(player) = holder.get_player()
|
||||
&& let Some(player_arc) = world.get_player_by_uuid(player.gameprofile.id)
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_leash_entity::PlayerLeashEntityEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_leash_entity::PlayerLeashEntityEvent {
|
||||
player: player_arc,
|
||||
entity_id: self.entity_id,
|
||||
holder_id: holder_entity_id,
|
||||
@ -3416,7 +3417,8 @@ impl Entity {
|
||||
pub fn unleash(&self) {
|
||||
let world = self.world.load();
|
||||
if let Some(server) = world.server.upgrade() {
|
||||
let mut event = crate::plugin::api::events::entity::entity_unleash::EntityUnleashEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::entity::entity_unleash::EntityUnleashEvent::new(
|
||||
self.entity_id,
|
||||
"unleashed".to_string(),
|
||||
);
|
||||
|
||||
@ -1607,7 +1607,8 @@ impl Player {
|
||||
if let Some(player_arc) = self.world().get_player_by_uuid(self.gameprofile.id)
|
||||
&& let Some(server) = self.world().server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_spawn_change::PlayerSpawnChangeEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_spawn_change::PlayerSpawnChangeEvent {
|
||||
player: player_arc,
|
||||
new_spawn: Some(block_pos),
|
||||
forced,
|
||||
@ -1628,7 +1629,12 @@ impl Player {
|
||||
_ => 0,
|
||||
};
|
||||
self.client.try_enqueue_packet_editioned(
|
||||
&CPlayerSpawnPosition::new(final_block_pos, yaw, pitch, dimension.minecraft_name.to_owned()),
|
||||
&CPlayerSpawnPosition::new(
|
||||
final_block_pos,
|
||||
yaw,
|
||||
pitch,
|
||||
dimension.minecraft_name.to_owned(),
|
||||
),
|
||||
&pumpkin_protocol::bedrock::client::CSetSpawnPosition {
|
||||
spawn_position_type:
|
||||
pumpkin_protocol::bedrock::client::SpawnPositionType::PlayerRespawn,
|
||||
@ -2315,7 +2321,8 @@ impl Player {
|
||||
if let Some(player_arc) = self.world().get_player_by_uuid(self.gameprofile.id)
|
||||
&& let Some(server) = self.world().server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_open_sign::PlayerOpenSignEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_open_sign::PlayerOpenSignEvent {
|
||||
player: player_arc,
|
||||
block_pos: location,
|
||||
is_front: is_front_text,
|
||||
@ -2334,7 +2341,8 @@ impl Player {
|
||||
if let Some(player_arc) = self.world().get_player_by_uuid(self.gameprofile.id)
|
||||
&& let Some(server) = self.world().server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_velocity::PlayerVelocityEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_velocity::PlayerVelocityEvent {
|
||||
player: player_arc,
|
||||
velocity,
|
||||
cancelled: false,
|
||||
@ -2391,7 +2399,8 @@ impl Player {
|
||||
&& let Some(server) = self.world().server.upgrade()
|
||||
{
|
||||
let link_strings = links.iter().map(|l| l.url.clone()).collect();
|
||||
let mut event = crate::plugin::api::events::player::player_links_send::PlayerLinksSendEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_links_send::PlayerLinksSendEvent::new(
|
||||
player_arc,
|
||||
link_strings,
|
||||
);
|
||||
@ -3089,7 +3098,8 @@ impl Player {
|
||||
}
|
||||
|
||||
pub fn increment_stat(&self, category: statistics::StatisticCategory, stat: i32, amount: i32) {
|
||||
let final_amount = if let Some(player_arc) = self.world().get_player_by_uuid(self.gameprofile.id)
|
||||
let final_amount = if let Some(player_arc) =
|
||||
self.world().get_player_by_uuid(self.gameprofile.id)
|
||||
&& let Some(server) = self.world().server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_statistic_increment::PlayerStatisticIncrementEvent {
|
||||
@ -5228,7 +5238,8 @@ impl Player {
|
||||
if let Some(player_arc) = self.world().get_player_by_uuid(self.gameprofile.id)
|
||||
&& let Some(server) = self.world().server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_item_mend::PlayerItemMendEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_item_mend::PlayerItemMendEvent {
|
||||
player: player_arc,
|
||||
item_name: stack.item.registry_key.to_string(),
|
||||
repair_amount: repaired,
|
||||
|
||||
@ -71,7 +71,8 @@ impl FireworkRocketEntity {
|
||||
pub fn explode_and_remove(&self, world: &World) {
|
||||
let entity = self.get_entity();
|
||||
if let Some(server) = world.server.upgrade() {
|
||||
let mut event = crate::plugin::api::events::entity::firework_explode::FireworkExplodeEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::entity::firework_explode::FireworkExplodeEvent {
|
||||
entity_id: entity.entity_id,
|
||||
cancelled: false,
|
||||
};
|
||||
|
||||
@ -244,9 +244,13 @@ impl EntityBase for SplashPotionEntity {
|
||||
}
|
||||
}
|
||||
|
||||
let affected_ids: Vec<i32> = affected.iter().map(|(c, _)| c.get_entity().entity_id).collect();
|
||||
let affected_ids: Vec<i32> = affected
|
||||
.iter()
|
||||
.map(|(c, _)| c.get_entity().entity_id)
|
||||
.collect();
|
||||
if let Some(server) = world.server.upgrade() {
|
||||
let mut event = crate::plugin::api::events::entity::potion_splash::PotionSplashEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::entity::potion_splash::PotionSplashEvent::new(
|
||||
self.get_entity().entity_id,
|
||||
block_pos,
|
||||
stack.item.registry_key.to_string(),
|
||||
|
||||
@ -120,7 +120,8 @@ impl ItemBehaviour for BrushItem {
|
||||
if let Some(player_arc) = player.world().get_player_by_uuid(player.gameprofile.id)
|
||||
&& let Some(server) = player.world().server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::block::block_brush::BlockBrushEvent::new(
|
||||
let mut event =
|
||||
crate::plugin::api::events::block::block_brush::BlockBrushEvent::new(
|
||||
location,
|
||||
world.clone(),
|
||||
player_arc,
|
||||
|
||||
@ -194,7 +194,8 @@ fn handle_beehive(
|
||||
if let Some(player_arc) = player.world().get_player_by_uuid(player.gameprofile.id)
|
||||
&& let Some(server) = player.world().server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_harvest_block::PlayerHarvestBlockEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_harvest_block::PlayerHarvestBlockEvent {
|
||||
player: player_arc,
|
||||
block_pos: *location,
|
||||
harvested_items: drops.clone(),
|
||||
|
||||
@ -68,7 +68,8 @@ impl ItemBehaviour for TridentItem {
|
||||
if let Some(player_arc) = world.get_player_by_uuid(player.gameprofile.id)
|
||||
&& let Some(server) = world.server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_riptide::PlayerRiptideEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_riptide::PlayerRiptideEvent {
|
||||
player: player_arc,
|
||||
item_name: "trident".to_string(),
|
||||
cancelled: false,
|
||||
|
||||
@ -251,6 +251,9 @@ impl PumpkinServer {
|
||||
) -> Self {
|
||||
let server = Server::new(basic_config, advanced_config, vanilla_data).await;
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
adjust_file_descriptor_limit();
|
||||
|
||||
let rcon = server.advanced_config.networking.rcon.clone();
|
||||
|
||||
if rcon.enabled {
|
||||
@ -615,6 +618,15 @@ impl PumpkinServer {
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
#[cfg(target_family = "unix")]
|
||||
if e.raw_os_error() == Some(libc::EMFILE) {
|
||||
error!(
|
||||
"Too many open files! Server reached file descriptor limit. \
|
||||
New connections cannot be accepted until existing connections close or `ulimit -n` is increased."
|
||||
);
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
return true;
|
||||
}
|
||||
error!("Failed to accept Java client connection: {e}");
|
||||
sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
@ -826,3 +838,58 @@ fn scrub_address(ip: &str) -> String {
|
||||
.map(|ch| if ch == '.' || ch == ':' { ch } else { 'x' })
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
fn adjust_file_descriptor_limit() {
|
||||
let mut rlim = libc::rlimit {
|
||||
rlim_cur: 0,
|
||||
rlim_max: 0,
|
||||
};
|
||||
|
||||
// SAFETY: Passing a valid mutable pointer to a stack-allocated `rlimit` struct.
|
||||
if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &raw mut rlim) } != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let max_target = if rlim.rlim_max == libc::RLIM_INFINITY {
|
||||
1_048_576
|
||||
} else {
|
||||
rlim.rlim_max
|
||||
};
|
||||
|
||||
if rlim.rlim_cur < max_target {
|
||||
let old_limit = rlim.rlim_cur;
|
||||
rlim.rlim_cur = max_target;
|
||||
|
||||
// SAFETY: Calling `setrlimit` with a valid resource and valid pointer to initialized `rlimit`.
|
||||
let res = unsafe { libc::setrlimit(libc::RLIMIT_NOFILE, &raw const rlim) };
|
||||
if res == 0 {
|
||||
debug!("Increased open file descriptor limit from {old_limit} to {max_target}");
|
||||
} else {
|
||||
// Fallback: try setting to a reasonable high value (65,536) if max_target was rejected by the OS.
|
||||
let fallback = 65_536.min(max_target);
|
||||
if fallback > old_limit {
|
||||
rlim.rlim_cur = fallback;
|
||||
// SAFETY: Calling `setrlimit` with a valid resource and valid pointer to initialized `rlimit`.
|
||||
if unsafe { libc::setrlimit(libc::RLIMIT_NOFILE, &raw const rlim) } == 0 {
|
||||
debug!("Increased open file descriptor limit from {old_limit} to {fallback}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut current_rlim = libc::rlimit {
|
||||
rlim_cur: 0,
|
||||
rlim_max: 0,
|
||||
};
|
||||
// SAFETY: Passing a valid mutable pointer to a stack-allocated `rlimit` struct.
|
||||
if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &raw mut current_rlim) } == 0
|
||||
&& current_rlim.rlim_cur < 4096
|
||||
{
|
||||
warn!(
|
||||
"Open file descriptor limit is low ({}). Supporting >1000 concurrent players may fail with 'Too many open files'. \
|
||||
Consider increasing the limit with `ulimit -n 65535` or setting `LimitNOFILE=65535` in systemd.",
|
||||
current_rlim.rlim_cur
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,8 +160,7 @@ impl ChunkSender {
|
||||
epoch: u32,
|
||||
version: JavaMinecraftVersion,
|
||||
) -> Option<PreparedBatch> {
|
||||
if version >= JavaMinecraftVersion::V_1_20_2
|
||||
&& self.in_flight_batches >= self.max_in_flight
|
||||
if version >= JavaMinecraftVersion::V_1_20_2 && self.in_flight_batches >= self.max_in_flight
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -149,14 +149,18 @@ impl PendingConnection {
|
||||
server: &Arc<Server>,
|
||||
profile: &GameProfile,
|
||||
) -> Option<PacketHandlerResult> {
|
||||
let mut pre_login_event = crate::plugin::api::events::player::async_player_pre_login::AsyncPlayerPreLoginEvent {
|
||||
let mut pre_login_event =
|
||||
crate::plugin::api::events::player::async_player_pre_login::AsyncPlayerPreLoginEvent {
|
||||
player_name: profile.name.clone(),
|
||||
player_uuid: profile.id,
|
||||
ip_address: self.address,
|
||||
kick_message: TextComponent::text("Disconnected"),
|
||||
cancelled: false,
|
||||
};
|
||||
server.plugin_manager.fire(server, &mut pre_login_event).await;
|
||||
server
|
||||
.plugin_manager
|
||||
.fire(server, &mut pre_login_event)
|
||||
.await;
|
||||
if pre_login_event.cancelled {
|
||||
self.kick(pre_login_event.kick_message).await;
|
||||
return Some(PacketHandlerResult::Stop);
|
||||
|
||||
@ -1183,7 +1183,9 @@ impl JavaClient {
|
||||
player.clone(),
|
||||
ch.to_string(),
|
||||
);
|
||||
server.plugin_manager.fire_blocking(server, &mut unreg_event);
|
||||
server
|
||||
.plugin_manager
|
||||
.fire_blocking(server, &mut unreg_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,8 @@ impl JavaClient {
|
||||
if let Some(player_arc) = player.world().get_player_by_uuid(player.gameprofile.id)
|
||||
&& let Some(server) = player.world().server.upgrade()
|
||||
{
|
||||
let mut event = crate::plugin::api::events::player::player_edit_book::PlayerEditBookEvent {
|
||||
let mut event =
|
||||
crate::plugin::api::events::player::player_edit_book::PlayerEditBookEvent {
|
||||
player: player_arc,
|
||||
slot,
|
||||
pages: pages.clone(),
|
||||
|
||||
@ -169,7 +169,9 @@ impl JavaClient {
|
||||
world.clone(),
|
||||
player.inventory().held_item(),
|
||||
);
|
||||
server_arc.plugin_manager.fire_blocking(&server_arc, &mut abort_event);
|
||||
server_arc
|
||||
.plugin_manager
|
||||
.fire_blocking(&server_arc, &mut abort_event);
|
||||
}
|
||||
|
||||
player.mining.store(false, Ordering::Relaxed);
|
||||
|
||||
@ -930,4 +930,3 @@ pub(crate) fn from_wit_entity_type(
|
||||
.copied()
|
||||
.ok_or_else(|| wasmtime::Error::msg(format!("Invalid entity type index: {index}")))
|
||||
}
|
||||
|
||||
|
||||
@ -1024,8 +1024,7 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
||||
let world_ref = self.get_world_res(&world)?;
|
||||
let world_provider = world_ref.provider.clone();
|
||||
|
||||
let internal_type =
|
||||
super::entity::from_wit_entity_type(entity_type)?;
|
||||
let internal_type = super::entity::from_wit_entity_type(entity_type)?;
|
||||
|
||||
let internal_pos = pumpkin_util::math::vector3::Vector3::new(pos.0, pos.1, pos.2);
|
||||
let entity = crate::entity::r#type::from_type(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user