Skip to content

Commit

Permalink
Make worlds field mutable using RwLock (Pumpkin-MC#493)
Browse files Browse the repository at this point in the history
  • Loading branch information
vyPal authored Jan 24, 2025
1 parent 43af1ea commit 4ac2db5
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 48 deletions.
3 changes: 2 additions & 1 deletion pumpkin/src/command/commands/cmd_seed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ impl CommandExecutor for PumpkinExecutor {
) -> Result<(), CommandError> {
let seed = match sender {
CommandSender::Player(player) => player.living_entity.entity.world.level.seed.0,
_ => match server.worlds.first() {
// TODO: Maybe ask player for world, or get the current world
_ => match server.worlds.read().await.first() {
Some(world) => world.level.seed.0,
None => {
return Err(CommandError::GeneralCommandIssue(
Expand Down
10 changes: 6 additions & 4 deletions pumpkin/src/command/commands/cmd_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ impl CommandExecutor for TimeQueryExecutor {
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let mode = self.0;
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be at least one world");
let level_time = world.level_time.lock().await;
Expand Down Expand Up @@ -121,8 +122,9 @@ impl CommandExecutor for TimeChangeExecutor {
}
};
let mode = self.0;
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be at least one world");
let mut level_time = world.level_time.lock().await;
Expand Down
70 changes: 40 additions & 30 deletions pumpkin/src/command/commands/cmd_worldborder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ impl CommandExecutor for WorldborderGetExecutor {
server: &Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let border = world.worldborder.lock().await;

let diameter = border.new_diameter.round() as i32;
Expand All @@ -86,10 +87,11 @@ impl CommandExecutor for WorldborderSetExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Ok(distance) = distance_consumer().find_arg_default_name(args)? else {
Expand Down Expand Up @@ -137,10 +139,11 @@ impl CommandExecutor for WorldborderSetTimeExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Ok(distance) = distance_consumer().find_arg_default_name(args)? else {
Expand Down Expand Up @@ -223,10 +226,11 @@ impl CommandExecutor for WorldborderAddExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Ok(distance) = distance_consumer().find_arg_default_name(args)? else {
Expand Down Expand Up @@ -276,10 +280,11 @@ impl CommandExecutor for WorldborderAddTimeExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Ok(distance) = distance_consumer().find_arg_default_name(args)? else {
Expand Down Expand Up @@ -364,10 +369,11 @@ impl CommandExecutor for WorldborderCenterExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Vector2 { x, z } = Position2DArgumentConsumer.find_arg_default_name(args)?;
Expand Down Expand Up @@ -397,10 +403,11 @@ impl CommandExecutor for WorldborderDamageAmountExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Ok(damage_per_block) = damage_per_block_consumer().find_arg_default_name(args)? else {
Expand Down Expand Up @@ -451,10 +458,11 @@ impl CommandExecutor for WorldborderDamageBufferExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Ok(buffer) = damage_buffer_consumer().find_arg_default_name(args)? else {
Expand Down Expand Up @@ -505,10 +513,11 @@ impl CommandExecutor for WorldborderWarningDistanceExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Ok(distance) = warning_distance_consumer().find_arg_default_name(args)? else {
Expand Down Expand Up @@ -558,10 +567,11 @@ impl CommandExecutor for WorldborderWarningTimeExecutor {
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let world = server
.worlds
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
.first()
.expect("There should always be atleast one world");
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;

let Ok(time) = time_consumer().find_arg_default_name(args)? else {
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/net/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ async fn handle_packet(
if packet.is_full_request {
// Get 4 players
let mut players: Vec<CString> = Vec::new();
for world in &server.worlds {
for world in server.worlds.read().await.iter() {
let mut world_players = world
.current_players
.lock()
Expand Down
24 changes: 12 additions & 12 deletions pumpkin/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub struct Server {
/// Saves and calls blocks blocks
pub block_manager: Arc<BlockManager>,
/// Manages multiple worlds within the server.
pub worlds: Vec<Arc<World>>,
pub worlds: RwLock<Vec<Arc<World>>>,
// All the dimensions that exists on the server,
pub dimensions: Vec<DimensionType>,
/// Caches game registries for efficient access.
Expand Down Expand Up @@ -124,7 +124,7 @@ impl Server {
// 0 is invalid
entity_id: 2.into(),
container_id: 0.into(),
worlds: vec![Arc::new(world)],
worlds: RwLock::new(vec![Arc::new(world)]),
dimensions: vec![
DimensionType::Overworld,
DimensionType::OverworldCaves,
Expand Down Expand Up @@ -174,7 +174,7 @@ impl Server {
};
// Basically the default world
// TODO: select default from config
let world = &self.worlds[0];
let world = &self.worlds.read().await[0];

let player = Arc::new(Player::new(client, world.clone(), entity_id, gamemode).await);
world
Expand All @@ -197,7 +197,7 @@ impl Server {
}

pub async fn save(&self) {
for world in &self.worlds {
for world in self.worlds.read().await.iter() {
world.save().await;
}
}
Expand Down Expand Up @@ -331,7 +331,7 @@ impl Server {
where
P: ClientPacket,
{
for world in &self.worlds {
for world in self.worlds.read().await.iter() {
world.broadcast_packet_all(packet).await;
}
}
Expand All @@ -343,7 +343,7 @@ impl Server {
chat_type: u32,
target_name: Option<&TextComponent>,
) {
for world in &self.worlds {
for world in self.worlds.read().await.iter() {
world
.broadcast_message(message, sender_name, chat_type, target_name)
.await;
Expand All @@ -363,7 +363,7 @@ impl Server {
///
/// An `Option<Arc<Player>>` containing the player if found, or `None` if not found.
pub async fn get_player_by_name(&self, name: &str) -> Option<Arc<Player>> {
for world in &self.worlds {
for world in self.worlds.read().await.iter() {
if let Some(player) = world.get_player_by_name(name).await {
return Some(player);
}
Expand All @@ -375,7 +375,7 @@ impl Server {
pub async fn get_all_players(&self) -> Vec<Arc<Player>> {
let mut players = Vec::<Arc<Player>>::new();

for world in &self.worlds {
for world in self.worlds.read().await.iter() {
for (_, player) in world.current_players.lock().await.iter() {
players.push(player.clone());
}
Expand Down Expand Up @@ -404,7 +404,7 @@ impl Server {
///
/// An `Option<Arc<Player>>` containing the player if found, or `None` if not found.
pub async fn get_player_by_uuid(&self, id: uuid::Uuid) -> Option<Arc<Player>> {
for world in &self.worlds {
for world in self.worlds.read().await.iter() {
if let Some(player) = world.get_player_by_uuid(id).await {
return Some(player);
}
Expand All @@ -421,7 +421,7 @@ impl Server {
/// The total number of players connected to the server.
pub async fn get_player_count(&self) -> usize {
let mut count = 0;
for world in &self.worlds {
for world in self.worlds.read().await.iter() {
count += world.current_players.lock().await.len();
}
count
Expand All @@ -430,7 +430,7 @@ impl Server {
/// Similar to [`Server::get_player_count`] >= n, but may be more efficient since it stops it's iteration through all worlds as soon as n players were found.
pub async fn has_n_players(&self, n: usize) -> bool {
let mut count = 0;
for world in &self.worlds {
for world in self.worlds.read().await.iter() {
count += world.current_players.lock().await.len();
if count >= n {
return true;
Expand Down Expand Up @@ -476,7 +476,7 @@ impl Server {
}

async fn tick(&self) {
for world in &self.worlds {
for world in self.worlds.read().await.iter() {
world.tick().await;
}
}
Expand Down

0 comments on commit 4ac2db5

Please sign in to comment.