-
-
Notifications
You must be signed in to change notification settings - Fork 180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Teleport to different world #532
Conversation
pumpkin/src/entity/player.rs
Outdated
.broadcast_packet_all(&CRemovePlayerInfo::new(1.into(), &[uuid])) | ||
.await; | ||
current_world | ||
.players | ||
.lock() | ||
.await | ||
.remove(&self.gameprofile.id); | ||
self.client |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just do world.remove_player
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well the world.remove_player
function also emits the PlayerLeaveEvent
which is meant for when the player leaves the entire server, not just a specific world. I could try to modify the remove_player
method to take a boolean argument which would decide if the event should be fired
pumpkin/src/entity/player.rs
Outdated
.send_packet(&CGameEvent::new(GameEvent::StartWaitingChunks, 0.0)) | ||
.await; | ||
*self.living_entity.entity.world.write().await = new_world.clone(); | ||
new_world.players.lock().await.insert(uuid, self.clone()); | ||
self.unload_watched_chunks(¤t_world).await; | ||
let last_pos = self.living_entity.last_pos.load(); | ||
let death_dimension = self.world().await.dimension_type.name(); | ||
let death_location = BlockPos(Vector3::new( | ||
last_pos.x.round() as i32, | ||
last_pos.y.round() as i32, | ||
last_pos.z.round() as i32, | ||
)); | ||
self.client | ||
.send_packet(&CRespawn::new( | ||
(new_world.dimension_type as u8).into(), | ||
new_world.dimension_type.name(), | ||
0, // seed | ||
self.gamemode.load() as u8, | ||
self.gamemode.load() as i8, | ||
false, | ||
false, | ||
Some((death_dimension, death_location)), | ||
0.into(), | ||
0.into(), | ||
1, | ||
)) | ||
.await; | ||
self.send_abilities_update().await; | ||
self.send_permission_lvl_update().await; | ||
let info = &new_world.level.level_info; | ||
let position = if let Some(pos) = position { | ||
pos | ||
} else { | ||
Vector3::new( | ||
f64::from(info.spawn_x), | ||
f64::from( | ||
new_world | ||
.get_top_block(Vector2::new( | ||
f64::from(info.spawn_x) as i32, | ||
f64::from(info.spawn_x) as i32, | ||
)) | ||
.await | ||
+ 1, | ||
), | ||
f64::from(info.spawn_z), | ||
) | ||
}; | ||
let yaw = yaw.unwrap_or(info.spawn_angle); | ||
let pitch = pitch.unwrap_or(10.0); | ||
self.request_teleport(position, yaw, pitch).await; | ||
self.living_entity.last_pos.store(position); | ||
new_world | ||
.worldborder | ||
.lock() | ||
.await | ||
.init_client(&self.client) | ||
.await; | ||
self.client | ||
.send_packet(&CGameEvent::new(GameEvent::StartWaitingChunks, 0.0)) | ||
.await; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why GameEvent::StartWaitingChunks
is here twice?
pumpkin/src/entity/player.rs
Outdated
.await | ||
.remove(&self.gameprofile.id); | ||
self.client | ||
.send_packet(&CGameEvent::new(GameEvent::StartWaitingChunks, 0.0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also i think we should have some kinda send_world_info
function like in vanilla which is being send on join, respawn and here. Like this
public void sendWorldInfo(ServerPlayerEntity player, ServerWorld world) {
WorldBorder worldBorder = this.server.getOverworld().getWorldBorder();
player.networkHandler.sendPacket(new WorldBorderInitializeS2CPacket(worldBorder));
player.networkHandler.sendPacket(new WorldTimeUpdateS2CPacket(world.getTime(), world.getTimeOfDay(), world.getGameRules().getBoolean(GameRules.DO_DAYLIGHT_CYCLE)));
player.networkHandler.sendPacket(new PlayerSpawnPositionS2CPacket(world.getSpawnPos(), world.getSpawnAngle()));
if (world.isRaining()) {
player.networkHandler.sendPacket(new GameStateChangeS2CPacket(GameStateChangeS2CPacket.RAIN_STARTED, GameStateChangeS2CPacket.DEMO_OPEN_SCREEN));
player.networkHandler.sendPacket(new GameStateChangeS2CPacket(GameStateChangeS2CPacket.RAIN_GRADIENT_CHANGED, world.getRainGradient(1.0f)));
player.networkHandler.sendPacket(new GameStateChangeS2CPacket(GameStateChangeS2CPacket.THUNDER_GRADIENT_CHANGED, world.getThunderGradient(1.0f)));
}
player.networkHandler.sendPacket(new GameStateChangeS2CPacket(GameStateChangeS2CPacket.INITIAL_CHUNKS_COMING, GameStateChangeS2CPacket.DEMO_OPEN_SCREEN));
this.server.getTickManager().sendPackets(player);
}
Looks good now. Thank you @vyPal 👍 |
* make entity world RwLock * Add teleport function * Mark client as not loaded before change dim * clippy * Post-merge issues * FIx post merge issues * Make world.remove_player fire event conditionally * Remove extra StartWaitingChunks packet * Add world.send_world_info()
Implements #511
Description
This PR adds one new public function to the
Player
struct:pub async fn teleport_world(self: Arc<Self>, new_world: Arc<World>, position: Option<Vector3<f64>>, yaw: Option<f32>, pitch: Option<f32>)
- Teleport player to new world, this will also teleport the player to the specific coordinates provided by the caller. It will not check the coordinates for correctness (like if the y isn't below the surface). If no coordinates are provided, it will select the default spawn coordinates for the new_world.Testing
Please follow our Coding Guidelines