Implement Game Mode Swapping (#922)

* feat: f3+f4 gamemode swapping

* fix: satisfy clippy

* fix: check permissions

* fix: move ChangeGameMode packet handling into its own function

* fix: imports

* fix: cargo fmt

---------

Co-authored-by: arrow <arrow.tsx@gmail.com>
This commit is contained in:
Arrow
2025-06-26 11:16:40 -07:00
committed by GitHub
parent 03c71fc9f4
commit be21e1381c
4 changed files with 39 additions and 9 deletions

View File

@@ -0,0 +1,10 @@
use pumpkin_data::packet::serverbound::PLAY_CHANGE_GAME_MODE;
use pumpkin_macros::packet;
use pumpkin_util::GameMode;
use serde::Serialize;
#[derive(serde::Deserialize, Serialize)]
#[packet(PLAY_CHANGE_GAME_MODE)]
pub struct SChangeGameMode {
pub game_mode: GameMode,
}

View File

@@ -1,3 +1,4 @@
mod change_game_mode;
mod chat_command;
mod chat_message;
mod chunk_batch;
@@ -31,6 +32,7 @@ mod update_sign;
mod use_item;
mod use_item_on;
pub use change_game_mode::*;
pub use chat_command::*;
pub use chat_message::*;
pub use chunk_batch::*;

View File

@@ -48,8 +48,8 @@ use pumpkin_protocol::client::play::{
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::ser::packet::Packet;
use pumpkin_protocol::server::play::{
SChatCommand, SChatMessage, SChunkBatch, SClickSlot, SClientCommand, SClientInformationPlay,
SClientTickEnd, SCloseContainer, SCommandSuggestion, SConfirmTeleport,
SChangeGameMode, SChatCommand, SChatMessage, SChunkBatch, SClickSlot, SClientCommand,
SClientInformationPlay, SClientTickEnd, SCloseContainer, SCommandSuggestion, SConfirmTeleport,
SCookieResponse as SPCookieResponse, SInteract, SKeepAlive, SPickItemFromBlock,
SPlayPingRequest, SPlayerAbilities, SPlayerAction, SPlayerCommand, SPlayerInput, SPlayerLoaded,
SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SPlayerSession, SSetCommandBlock,
@@ -2074,6 +2074,10 @@ impl Player {
self.handle_confirm_teleport(SConfirmTeleport::read(payload)?)
.await;
}
SChangeGameMode::PACKET_ID => {
self.handle_change_game_mode(SChangeGameMode::read(payload)?)
.await;
}
SChatCommand::PACKET_ID => {
self.handle_chat_command(server, &(SChatCommand::read(payload)?))
.await;

View File

@@ -3,6 +3,7 @@ use std::sync::Arc;
use std::sync::atomic::Ordering;
use std::time::{SystemTime, UNIX_EPOCH};
use pumpkin_util::PermissionLvl;
use rsa::pkcs1v15::{Signature as RsaPkcs1v15Signature, VerifyingKey};
use rsa::signature::Verifier;
use sha1::Sha1;
@@ -29,13 +30,13 @@ use pumpkin_protocol::client::play::{
};
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::server::play::{
Action, ActionType, CommandBlockMode, FLAG_ON_GROUND, SChatCommand, SChatMessage, SChunkBatch,
SClientCommand, SClientInformationPlay, SCloseContainer, SCommandSuggestion, SConfirmTeleport,
SCookieResponse as SPCookieResponse, SInteract, SKeepAlive, SPickItemFromBlock,
SPlayPingRequest, SPlayerAbilities, SPlayerAction, SPlayerCommand, SPlayerInput,
SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SPlayerSession, SSetCommandBlock,
SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, SSwingArm, SUpdateSign, SUseItem, SUseItemOn,
Status,
Action, ActionType, CommandBlockMode, FLAG_ON_GROUND, SChangeGameMode, SChatCommand,
SChatMessage, SChunkBatch, SClientCommand, SClientInformationPlay, SCloseContainer,
SCommandSuggestion, SConfirmTeleport, SCookieResponse as SPCookieResponse, SInteract,
SKeepAlive, SPickItemFromBlock, SPlayPingRequest, SPlayerAbilities, SPlayerAction,
SPlayerCommand, SPlayerInput, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation,
SPlayerSession, SSetCommandBlock, SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, SSwingArm,
SUpdateSign, SUseItem, SUseItemOn, Status,
};
use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::math::{polynomial_rolling_hash, position::BlockPos, wrap_degrees};
@@ -189,6 +190,19 @@ impl Player {
}
}
pub async fn handle_change_game_mode(self: &Arc<Self>, change_game_mode: SChangeGameMode) {
if self.permission_lvl.load() >= PermissionLvl::Two {
self.set_gamemode(change_game_mode.game_mode).await;
let gamemode_string = format!("{:?}", change_game_mode.game_mode).to_lowercase();
let gamemode_string = format!("gameMode.{gamemode_string}");
self.send_system_message(&TextComponent::translate(
"commands.gamemode.success.self",
[TextComponent::translate(gamemode_string, [])],
))
.await;
}
}
fn clamp_horizontal(pos: f64) -> f64 {
pos.clamp(-3.0E7, 3.0E7)
}