This commit is contained in:
parent
21e7f1418a
commit
55219f870f
@ -35,8 +35,10 @@ pub mod resource_packs_info;
|
|||||||
pub mod scoreboard;
|
pub mod scoreboard;
|
||||||
pub mod set_actor_data;
|
pub mod set_actor_data;
|
||||||
pub mod set_actor_motion;
|
pub mod set_actor_motion;
|
||||||
|
pub mod set_difficulty;
|
||||||
pub mod set_health;
|
pub mod set_health;
|
||||||
pub mod set_player_gamemode;
|
pub mod set_player_gamemode;
|
||||||
|
pub mod set_spawn_position;
|
||||||
pub mod set_time;
|
pub mod set_time;
|
||||||
pub mod set_title;
|
pub mod set_title;
|
||||||
pub mod show_credits;
|
pub mod show_credits;
|
||||||
@ -84,8 +86,10 @@ pub use resource_packs_info::*;
|
|||||||
pub use scoreboard::*;
|
pub use scoreboard::*;
|
||||||
pub use set_actor_data::*;
|
pub use set_actor_data::*;
|
||||||
pub use set_actor_motion::*;
|
pub use set_actor_motion::*;
|
||||||
|
pub use set_difficulty::*;
|
||||||
pub use set_health::*;
|
pub use set_health::*;
|
||||||
pub use set_player_gamemode::*;
|
pub use set_player_gamemode::*;
|
||||||
|
pub use set_spawn_position::*;
|
||||||
pub use set_time::*;
|
pub use set_time::*;
|
||||||
pub use set_title::*;
|
pub use set_title::*;
|
||||||
pub use show_credits::*;
|
pub use show_credits::*;
|
||||||
|
|||||||
18
pumpkin-protocol/src/bedrock/client/set_difficulty.rs
Normal file
18
pumpkin-protocol/src/bedrock/client/set_difficulty.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use pumpkin_macros::packet;
|
||||||
|
|
||||||
|
use crate::{codec::var_uint::VarUInt, serial::PacketWrite};
|
||||||
|
|
||||||
|
#[derive(PacketWrite)]
|
||||||
|
#[packet(60)]
|
||||||
|
pub struct CSetDifficulty {
|
||||||
|
pub difficulty: VarUInt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSetDifficulty {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(difficulty: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
difficulty: VarUInt(difficulty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
pumpkin-protocol/src/bedrock/client/set_spawn_position.rs
Normal file
42
pumpkin-protocol/src/bedrock/client/set_spawn_position.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use std::io::{Error, Write};
|
||||||
|
|
||||||
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
|
||||||
|
use crate::{codec::var_int::VarInt, serial::PacketWrite};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[packet(43)]
|
||||||
|
pub struct CSetSpawnPosition {
|
||||||
|
pub spawn_type: VarInt,
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub dimension: VarInt,
|
||||||
|
pub spawn_position: BlockPos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSetSpawnPosition {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(
|
||||||
|
spawn_type: i32,
|
||||||
|
position: BlockPos,
|
||||||
|
dimension: i32,
|
||||||
|
spawn_position: BlockPos,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
spawn_type: VarInt(spawn_type),
|
||||||
|
position,
|
||||||
|
dimension: VarInt(dimension),
|
||||||
|
spawn_position,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PacketWrite for CSetSpawnPosition {
|
||||||
|
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
|
self.spawn_type.write(writer)?;
|
||||||
|
self.position.write(writer)?;
|
||||||
|
self.dimension.write(writer)?;
|
||||||
|
self.spawn_position.write(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -67,7 +67,10 @@ struct RawWeightedPoolElement {
|
|||||||
enum RawPoolElement {
|
enum RawPoolElement {
|
||||||
#[serde(rename = "minecraft:empty_pool_element")]
|
#[serde(rename = "minecraft:empty_pool_element")]
|
||||||
Empty,
|
Empty,
|
||||||
#[serde(rename = "minecraft:single_pool_element")]
|
#[serde(
|
||||||
|
rename = "minecraft:single_pool_element",
|
||||||
|
alias = "minecraft:legacy_single_pool_element"
|
||||||
|
)]
|
||||||
Single {
|
Single {
|
||||||
location: String,
|
location: String,
|
||||||
processors: RawProcessorList,
|
processors: RawProcessorList,
|
||||||
|
|||||||
@ -177,9 +177,17 @@ impl StructureTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_palette(compound: &NbtCompound) -> Result<Vec<PaletteEntry>, TemplateError> {
|
fn parse_palette(compound: &NbtCompound) -> Result<Vec<PaletteEntry>, TemplateError> {
|
||||||
let palette_list = compound
|
let palette_list = if let Some(list) = compound.get_list("palette") {
|
||||||
.get_list("palette")
|
list
|
||||||
.ok_or(TemplateError::MissingField("palette"))?;
|
} else if let Some(palettes) = compound.get_list("palettes") {
|
||||||
|
if let Some(NbtTag::List(list)) = palettes.first() {
|
||||||
|
list
|
||||||
|
} else {
|
||||||
|
return Err(TemplateError::MissingField("palette"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(TemplateError::MissingField("palette"));
|
||||||
|
};
|
||||||
|
|
||||||
let mut palette = Vec::with_capacity(palette_list.len());
|
let mut palette = Vec::with_capacity(palette_list.len());
|
||||||
|
|
||||||
|
|||||||
@ -90,8 +90,9 @@ impl FromStr for EntityFilter {
|
|||||||
|
|
||||||
match key {
|
match key {
|
||||||
"type" => {
|
"type" => {
|
||||||
|
let name = value.strip_prefix("minecraft:").unwrap_or(value);
|
||||||
let entity_type =
|
let entity_type =
|
||||||
EntityType::from_name(value).ok_or(format!("Invalid entity type {value}"))?;
|
EntityType::from_name(name).ok_or(format!("Invalid entity type {value}"))?;
|
||||||
Ok(Self::Type(if negate {
|
Ok(Self::Type(if negate {
|
||||||
ValueCondition::NotEquals(entity_type)
|
ValueCondition::NotEquals(entity_type)
|
||||||
} else {
|
} else {
|
||||||
@ -496,4 +497,13 @@ mod test {
|
|||||||
assert_eq!(translate_key, translation::java::ARGUMENT_PLAYER_ENTITIES);
|
assert_eq!(translate_key, translation::java::ARGUMENT_PLAYER_ENTITIES);
|
||||||
assert_eq!(error.context.expect("Error should have context").cursor, 4);
|
assert_eq!(error.context.expect("Error should have context").cursor, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_type_and_inverted_type() {
|
||||||
|
let s = "@e[type=!player,type=minecraft:zombie]"
|
||||||
|
.parse::<TargetSelector>()
|
||||||
|
.expect("should parse");
|
||||||
|
assert!(s.includes_entities());
|
||||||
|
assert_eq!(s.conditions.len(), 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -382,6 +382,8 @@ pub enum EntitySelectorPredicate {
|
|||||||
BoundingBox(BoundingBox),
|
BoundingBox(BoundingBox),
|
||||||
/// A predicate to check whether an entity is within a specified range from some position.
|
/// A predicate to check whether an entity is within a specified range from some position.
|
||||||
Distance(DoubleBounds, Vector3<f64>),
|
Distance(DoubleBounds, Vector3<f64>),
|
||||||
|
/// A predicate to check the entity type. This check can also be inverted.
|
||||||
|
EntityType(&'static EntityType, bool),
|
||||||
|
|
||||||
/// Used to combine sub-predicates.
|
/// Used to combine sub-predicates.
|
||||||
AllOf(Vec<Self>),
|
AllOf(Vec<Self>),
|
||||||
@ -437,6 +439,10 @@ impl EntitySelectorPredicate {
|
|||||||
Self::Distance(bounds, pos) => {
|
Self::Distance(bounds, pos) => {
|
||||||
bounds.matches_square(entity.get_entity().pos.load().squared_distance_to_vec(pos))
|
bounds.matches_square(entity.get_entity().pos.load().squared_distance_to_vec(pos))
|
||||||
}
|
}
|
||||||
|
Self::EntityType(expected_type, invert) => {
|
||||||
|
let actual_type = entity.get_entity().entity_type;
|
||||||
|
(actual_type.id == expected_type.id) ^ invert
|
||||||
|
}
|
||||||
Self::AllOf(predicates) => predicates.iter().all(|predicate| predicate.test(entity)),
|
Self::AllOf(predicates) => predicates.iter().all(|predicate| predicate.test(entity)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use crate::command::errors::command_syntax_error::CommandSyntaxError;
|
|||||||
use crate::command::errors::error_types::CommandErrorType;
|
use crate::command::errors::error_types::CommandErrorType;
|
||||||
use crate::command::string_reader::StringReader;
|
use crate::command::string_reader::StringReader;
|
||||||
use crate::command::suggestion::suggestions::SuggestionsBuilder;
|
use crate::command::suggestion::suggestions::SuggestionsBuilder;
|
||||||
|
use pumpkin_data::entity::EntityType;
|
||||||
use pumpkin_data::translation;
|
use pumpkin_data::translation;
|
||||||
use pumpkin_util::GameMode;
|
use pumpkin_util::GameMode;
|
||||||
use pumpkin_util::math::bounds::{DoubleBounds, FloatDegreeBounds, IntBounds};
|
use pumpkin_util::math::bounds::{DoubleBounds, FloatDegreeBounds, IntBounds};
|
||||||
@ -41,6 +42,10 @@ pub const GAMEMODE_INVALID_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::n
|
|||||||
translation::java::ARGUMENT_ENTITY_OPTIONS_MODE_INVALID,
|
translation::java::ARGUMENT_ENTITY_OPTIONS_MODE_INVALID,
|
||||||
translation::java::ARGUMENT_ENTITY_OPTIONS_MODE_INVALID,
|
translation::java::ARGUMENT_ENTITY_OPTIONS_MODE_INVALID,
|
||||||
);
|
);
|
||||||
|
pub const TYPE_INVALID_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::new(
|
||||||
|
translation::java::ARGUMENT_ENTITY_OPTIONS_TYPE_INVALID,
|
||||||
|
translation::java::ARGUMENT_ENTITY_OPTIONS_TYPE_INVALID,
|
||||||
|
);
|
||||||
|
|
||||||
/// Options to customize an [`EntitySelectorParser`].
|
/// Options to customize an [`EntitySelectorParser`].
|
||||||
///
|
///
|
||||||
@ -187,6 +192,7 @@ impl EntitySelectorOption {
|
|||||||
/// Any required fields will be parsed by this method using [`StringReader`]
|
/// Any required fields will be parsed by this method using [`StringReader`]
|
||||||
/// methods, and any required predicates will be added.
|
/// methods, and any required predicates will be added.
|
||||||
/// Any found errors will be returned.
|
/// Any found errors will be returned.
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn modify_parser(
|
pub fn modify_parser(
|
||||||
self,
|
self,
|
||||||
parser: &mut EntitySelectorParser,
|
parser: &mut EntitySelectorParser,
|
||||||
@ -278,6 +284,33 @@ impl EntitySelectorOption {
|
|||||||
.create(parser.reader, TextComponent::text(string)))
|
.create(parser.reader, TextComponent::text(string)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Self::Type => {
|
||||||
|
let start = parser.reader.cursor();
|
||||||
|
let invert = parser.consume_inverted_start();
|
||||||
|
if parser.has_flag(Flags::ENTITY_TYPE_INVERTED) && !invert {
|
||||||
|
parser.reader.set_cursor(start);
|
||||||
|
return Err(self.inapplicable_error(parser.reader));
|
||||||
|
}
|
||||||
|
let mut string = parser.reader.read_unquoted_string();
|
||||||
|
if let Some(stripped) = string.strip_prefix("minecraft:") {
|
||||||
|
string = stripped.to_string();
|
||||||
|
}
|
||||||
|
if let Some(entity_type) = EntityType::from_name(&string) {
|
||||||
|
if entity_type.id == EntityType::PLAYER.id && !invert {
|
||||||
|
parser.limit_to_players();
|
||||||
|
}
|
||||||
|
parser.add_predicate(EntitySelectorPredicate::EntityType(entity_type, invert));
|
||||||
|
if invert {
|
||||||
|
parser.set_flag(Flags::ENTITY_TYPE_INVERTED, true);
|
||||||
|
} else {
|
||||||
|
parser.entity_type = Some(entity_type);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
parser.reader.set_cursor(start);
|
||||||
|
Err(TYPE_INVALID_ERROR_TYPE.create(parser.reader, TextComponent::text(string)))
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
tracing::warn!("Unimplemented entity selector option: {:?}", self);
|
tracing::warn!("Unimplemented entity selector option: {:?}", self);
|
||||||
Err(UNKNOWN_OPTION_ERROR_TYPE.create_without_context(self.name_component()))
|
Err(UNKNOWN_OPTION_ERROR_TYPE.create_without_context(self.name_component()))
|
||||||
|
|||||||
@ -59,7 +59,7 @@ impl CommandExecutor for DifficultySetExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server.set_difficulty(difficulty, true);
|
server.set_difficulty(difficulty, true).await;
|
||||||
|
|
||||||
context
|
context
|
||||||
.source
|
.source
|
||||||
|
|||||||
@ -1298,13 +1298,26 @@ impl Player {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let bedrock_dimension = match dimension.minecraft_name {
|
||||||
|
"minecraft:the_nether" => 1,
|
||||||
|
"minecraft:the_end" => 2,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
self.client
|
self.client
|
||||||
.send_packet_now(&CPlayerSpawnPosition::new(
|
.send_packet_now_editioned(
|
||||||
block_pos,
|
&CPlayerSpawnPosition::new(
|
||||||
yaw,
|
block_pos,
|
||||||
pitch,
|
yaw,
|
||||||
dimension.minecraft_name.to_owned(),
|
pitch,
|
||||||
))
|
dimension.minecraft_name.to_owned(),
|
||||||
|
),
|
||||||
|
&pumpkin_protocol::bedrock::client::CSetSpawnPosition::new(
|
||||||
|
0, // Player spawn
|
||||||
|
block_pos,
|
||||||
|
bedrock_dimension,
|
||||||
|
block_pos,
|
||||||
|
),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
*self.respawn_point.lock().await = Some(RespawnPoint {
|
*self.respawn_point.lock().await = Some(RespawnPoint {
|
||||||
@ -1739,22 +1752,41 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn show_title(&self, text: &TextComponent, mode: &TitleMode) {
|
pub async fn show_title(&self, text: &TextComponent, mode: &TitleMode) {
|
||||||
match self.client.as_ref() {
|
match mode {
|
||||||
ClientPlatform::Java(client) => match mode {
|
TitleMode::Title => {
|
||||||
TitleMode::Title => client.enqueue_packet(&CTitleText::new(text)).await,
|
self.client
|
||||||
TitleMode::SubTitle => client.enqueue_packet(&CSubtitle::new(text)).await,
|
.enqueue_packet_editioned(
|
||||||
TitleMode::ActionBar => client.enqueue_packet(&CActionBar::new(text)).await,
|
&CTitleText::new(text),
|
||||||
},
|
|
||||||
ClientPlatform::Bedrock(client) => {
|
|
||||||
let action_type = match mode {
|
|
||||||
TitleMode::Title => 2,
|
|
||||||
TitleMode::SubTitle => 3,
|
|
||||||
TitleMode::ActionBar => 4,
|
|
||||||
};
|
|
||||||
client
|
|
||||||
.send_game_packet(
|
|
||||||
&pumpkin_protocol::bedrock::client::set_title::CSetTitle::new(
|
&pumpkin_protocol::bedrock::client::set_title::CSetTitle::new(
|
||||||
action_type,
|
2,
|
||||||
|
text.clone().get_text(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
TitleMode::SubTitle => {
|
||||||
|
self.client
|
||||||
|
.enqueue_packet_editioned(
|
||||||
|
&CSubtitle::new(text),
|
||||||
|
&pumpkin_protocol::bedrock::client::set_title::CSetTitle::new(
|
||||||
|
3,
|
||||||
|
text.clone().get_text(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
TitleMode::ActionBar => {
|
||||||
|
self.client
|
||||||
|
.enqueue_packet_editioned(
|
||||||
|
&CActionBar::new(text),
|
||||||
|
&pumpkin_protocol::bedrock::client::set_title::CSetTitle::new(
|
||||||
|
4,
|
||||||
text.clone().get_text(),
|
text.clone().get_text(),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -2384,10 +2416,12 @@ impl Player {
|
|||||||
let world = self.world();
|
let world = self.world();
|
||||||
let level_info = world.level_info.load();
|
let level_info = world.level_info.load();
|
||||||
self.client
|
self.client
|
||||||
.enqueue_packet(&CChangeDifficulty::new(
|
.enqueue_packet_editioned(
|
||||||
level_info.difficulty as u8,
|
&CChangeDifficulty::new(level_info.difficulty as u8, level_info.difficulty_locked),
|
||||||
level_info.difficulty_locked,
|
&pumpkin_protocol::bedrock::client::CSetDifficulty::new(
|
||||||
))
|
level_info.difficulty as u32,
|
||||||
|
),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2412,24 +2446,12 @@ impl Player {
|
|||||||
/// Sends the world time to only this player.
|
/// Sends the world time to only this player.
|
||||||
pub async fn send_time(&self, world: &World) {
|
pub async fn send_time(&self, world: &World) {
|
||||||
let l_world = world.level_time.lock().await;
|
let l_world = world.level_time.lock().await;
|
||||||
match self.client.as_ref() {
|
self.client
|
||||||
ClientPlatform::Java(java_client) => {
|
.enqueue_packet_editioned(
|
||||||
java_client
|
&CUpdateTime::new(l_world.world_age, l_world.time_of_day, true),
|
||||||
.enqueue_packet(&CUpdateTime::new(
|
&CSetTime::new(l_world.query_daytime() as _),
|
||||||
l_world.world_age,
|
)
|
||||||
l_world.time_of_day,
|
.await;
|
||||||
true,
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
ClientPlatform::Bedrock(bedrock_client) => {
|
|
||||||
bedrock_client
|
|
||||||
.send_game_packet(&CSetTime {
|
|
||||||
time: VarInt(l_world.query_daytime() as _),
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn unload_watched_chunks(&self, world: &World) {
|
pub async fn unload_watched_chunks(&self, world: &World) {
|
||||||
@ -2652,26 +2674,18 @@ impl Player {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.client.as_ref() {
|
self.client
|
||||||
ClientPlatform::Java(client) => {
|
.enqueue_packet_editioned(
|
||||||
client
|
&CSetHealth::new(
|
||||||
.enqueue_packet(&CSetHealth::new(
|
self.living_entity.health.load(),
|
||||||
self.living_entity.health.load(),
|
self.hunger_manager.level.load().into(),
|
||||||
self.hunger_manager.level.load().into(),
|
self.hunger_manager.saturation.load(),
|
||||||
self.hunger_manager.saturation.load(),
|
),
|
||||||
))
|
&pumpkin_protocol::bedrock::client::set_health::CSetHealth::new(
|
||||||
.await;
|
self.living_entity.health.load() as i32,
|
||||||
}
|
),
|
||||||
ClientPlatform::Bedrock(client) => {
|
)
|
||||||
client
|
.await;
|
||||||
.send_game_packet(
|
|
||||||
&pumpkin_protocol::bedrock::client::set_health::CSetHealth::new(
|
|
||||||
self.living_entity.health.load() as i32,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn tick_health(&self) {
|
pub async fn tick_health(&self) {
|
||||||
@ -2926,25 +2940,14 @@ impl Player {
|
|||||||
}],
|
}],
|
||||||
));
|
));
|
||||||
|
|
||||||
match self.client.as_ref() {
|
self.client
|
||||||
crate::net::ClientPlatform::Java(client) => {
|
.enqueue_packet_editioned(
|
||||||
client
|
&CGameEvent::new(GameEvent::ChangeGameMode, gamemode as i32 as f32),
|
||||||
.enqueue_packet(&CGameEvent::new(
|
&pumpkin_protocol::bedrock::client::set_player_gamemode::CSetPlayerGamemode {
|
||||||
GameEvent::ChangeGameMode,
|
gamemode,
|
||||||
gamemode as i32 as f32,
|
},
|
||||||
))
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
|
||||||
crate::net::ClientPlatform::Bedrock(client) => {
|
|
||||||
client
|
|
||||||
.send_game_packet(
|
|
||||||
&pumpkin_protocol::bedrock::client::set_player_gamemode::CSetPlayerGamemode {
|
|
||||||
gamemode,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -5134,7 +5137,18 @@ impl InventoryPlayer for Player {
|
|||||||
packet: &'a CSetSelectedSlot,
|
packet: &'a CSetSelectedSlot,
|
||||||
) -> PlayerFuture<'a, ()> {
|
) -> PlayerFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.client.enqueue_packet(packet).await;
|
self.client
|
||||||
|
.enqueue_packet_editioned(
|
||||||
|
packet,
|
||||||
|
&pumpkin_protocol::bedrock::client::CPlayerHotbar {
|
||||||
|
selected_slot: pumpkin_protocol::codec::var_uint::VarUInt(
|
||||||
|
packet.slot as u32,
|
||||||
|
),
|
||||||
|
container_id: 0,
|
||||||
|
should_select_block: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -268,6 +268,17 @@ impl ClientPlatform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_packet_now_editioned<J: ClientPacket, B: BClientPacket>(
|
||||||
|
&self,
|
||||||
|
je_packet: &J,
|
||||||
|
be_packet: &B,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
Self::Java(java) => java.send_packet_now(je_packet).await,
|
||||||
|
Self::Bedrock(bedrock) => bedrock.send_game_packet(be_packet).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn send_packet_now_data(&self, data: Bytes) {
|
pub async fn send_packet_now_data(&self, data: Bytes) {
|
||||||
match self {
|
match self {
|
||||||
Self::Java(java) => java.send_packet_now_data(data).await,
|
Self::Java(java) => java.send_packet_now_data(data).await,
|
||||||
|
|||||||
@ -681,7 +681,7 @@ impl Server {
|
|||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// This function does not handle the actual mob spawn options update, which is a TODO item for future implementation.
|
/// This function does not handle the actual mob spawn options update, which is a TODO item for future implementation.
|
||||||
pub fn set_difficulty(&self, difficulty: Difficulty, force_update: bool) {
|
pub async fn set_difficulty(&self, difficulty: Difficulty, force_update: bool) {
|
||||||
let current_info = self.level_info.load();
|
let current_info = self.level_info.load();
|
||||||
if current_info.difficulty_locked && !force_update {
|
if current_info.difficulty_locked && !force_update {
|
||||||
return;
|
return;
|
||||||
@ -701,9 +701,13 @@ impl Server {
|
|||||||
|
|
||||||
for world in self.worlds.load().iter() {
|
for world in self.worlds.load().iter() {
|
||||||
world.set_difficulty(difficulty);
|
world.set_difficulty(difficulty);
|
||||||
|
world
|
||||||
|
.broadcast_editioned(
|
||||||
|
&CChangeDifficulty::new(difficulty as u8, locked),
|
||||||
|
&pumpkin_protocol::bedrock::client::CSetDifficulty::new(difficulty as u32),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.broadcast_packet_all(&CChangeDifficulty::new(difficulty as u8, locked));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Searches for a player by their username across all worlds.
|
/// Searches for a player by their username across all worlds.
|
||||||
|
|||||||
@ -3473,14 +3473,27 @@ impl World {
|
|||||||
position.y.round() as i32,
|
position.y.round() as i32,
|
||||||
position.z.round() as i32,
|
position.z.round() as i32,
|
||||||
));
|
));
|
||||||
|
let bedrock_dimension = match target_world.dimension.minecraft_name {
|
||||||
|
"minecraft:the_nether" => 1,
|
||||||
|
"minecraft:the_end" => 2,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
player
|
player
|
||||||
.client
|
.client
|
||||||
.send_packet_now(&CPlayerSpawnPosition::new(
|
.send_packet_now_editioned(
|
||||||
spawn_block_pos,
|
&CPlayerSpawnPosition::new(
|
||||||
yaw,
|
spawn_block_pos,
|
||||||
pitch,
|
yaw,
|
||||||
target_world.dimension.minecraft_name.to_string(),
|
pitch,
|
||||||
))
|
target_world.dimension.minecraft_name.to_string(),
|
||||||
|
),
|
||||||
|
&pumpkin_protocol::bedrock::client::CSetSpawnPosition::new(
|
||||||
|
1, // World spawn
|
||||||
|
spawn_block_pos,
|
||||||
|
bedrock_dimension,
|
||||||
|
spawn_block_pos,
|
||||||
|
),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
player.living_entity.reset_state().await;
|
player.living_entity.reset_state().await;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user