Skip to content

Commit

Permalink
feat: vanish 💨 (#670)
Browse files Browse the repository at this point in the history
added `/vanish` command for admins.

---------

Co-authored-by: Andrew Gazelka <andrew.gazelka@gmail.com>
  • Loading branch information
Tebarem and andrewgazelka authored Dec 9, 2024
1 parent e272fa0 commit 37ad0fd
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 29 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 0 additions & 11 deletions crates/hyperion/src/egress/player_join/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,17 +258,6 @@ pub fn player_join_world(

metadata.encode(*flags);

if let Some(view) = metadata.get_and_clear() {
let pkt = play::EntityTrackerUpdateS2c {
entity_id: VarInt(query_entity.minecraft_id()),
tracked_values: RawBytes(&view),
};

bundle
.add_packet(&pkt)
.context("failed to send player spawn packet")?;
}

Ok(())
};

Expand Down
13 changes: 10 additions & 3 deletions crates/hyperion/src/egress/sync_entity_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ use glam::Vec3;
use hyperion_inventory::PlayerInventory;
use hyperion_utils::EntityExt;
use tracing::error;
use valence_protocol::{RawBytes, VarInt, packets::play};
use valence_protocol::{
RawBytes, VarInt,
packets::play::{self},
};

use crate::{
Prev,
net::{Compose, ConnectionId},
simulation::{Position, Velocity, Xp, animation::ActiveAnimation, metadata::MetadataChanges},
simulation::{
Position, Velocity, Xp,
animation::ActiveAnimation,
metadata::{MetadataChanges, get_and_clear_metadata},
},
};

#[derive(Component)]
Expand Down Expand Up @@ -115,7 +122,7 @@ impl Module for EntityStateSyncModule {
let entity = it.entity(row);
let entity_id = VarInt(entity.minecraft_id());

let metadata = metadata_changes.get_and_clear();
let metadata = get_and_clear_metadata(metadata_changes);

if let Some(view) = metadata {
let pkt = play::EntityTrackerUpdateS2c {
Expand Down
21 changes: 11 additions & 10 deletions crates/hyperion/src/simulation/metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,16 +233,6 @@ impl MetadataChanges {
let r#type = metadata.to_type();
r#type.encode(&mut self.0).unwrap();
}

pub fn get_and_clear(&mut self) -> Option<MetadataView<'_>> {
if self.is_empty() {
return None;
}
// denote end of metadata
self.0.push(0xff);

Some(MetadataView(self))
}
}

#[derive(Debug)]
Expand All @@ -261,3 +251,14 @@ impl Drop for MetadataView<'_> {
self.0.0.clear();
}
}

/// This is only meant to be called from egress systems
pub(crate) fn get_and_clear_metadata(metadata: &mut MetadataChanges) -> Option<MetadataView<'_>> {
if metadata.is_empty() {
return None;
}
// denote end of metadata
metadata.0.push(0xff);

Some(MetadataView(metadata))
}
3 changes: 2 additions & 1 deletion events/tag/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ tracing = { workspace = true }
tracing-subscriber = { workspace = true }
tracing-tracy = { workspace = true }
uuid = { version = "1.11.0", features = ["v4"] }

valence_protocol = { workspace = true }
valence_server = { workspace = true }

[dev-dependencies]
tracing = {workspace = true, features = ["release_max_level_info"]}
Expand Down
8 changes: 5 additions & 3 deletions events/tag/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use hyperion_clap::{MinecraftCommand, hyperion_command::CommandRegistry};
use crate::command::{
bow::BowCommand, class::ClassCommand, fly::FlyCommand, gui::GuiCommand,
raycast::RaycastCommand, replace::ReplaceCommand, shoot::ShootCommand, spawn::SpawnCommand,
speed::SpeedCommand, xp::XpCommand,
speed::SpeedCommand, vanish::VanishCommand, xp::XpCommand,
};

mod bow;
Expand All @@ -16,17 +16,19 @@ mod replace;
mod shoot;
mod spawn;
mod speed;
mod vanish;
mod xp;

pub fn register(registry: &mut CommandRegistry, world: &World) {
BowCommand::register(registry, world);
ClassCommand::register(registry, world);
FlyCommand::register(registry, world);
GuiCommand::register(registry, world);
RaycastCommand::register(registry, world);
ReplaceCommand::register(registry, world);
ShootCommand::register(registry, world);
SpawnCommand::register(registry, world);
SpeedCommand::register(registry, world);
VanishCommand::register(registry, world);
XpCommand::register(registry, world);
SpawnCommand::register(registry, world);
GuiCommand::register(registry, world);
}
44 changes: 44 additions & 0 deletions events/tag/src/command/vanish.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use clap::Parser;
use flecs_ecs::{
core::{Entity, EntityView, EntityViewGet, WorldProvider},
prelude::*,
};
use hyperion::net::{Compose, ConnectionId};
use hyperion_clap::{CommandPermission, MinecraftCommand};

use crate::module::vanish::Vanished;

#[derive(Parser, CommandPermission, Debug)]
#[command(name = "vanish")]
#[command_permission(group = "Admin")]
pub struct VanishCommand;

impl MinecraftCommand for VanishCommand {
fn execute(self, system: EntityView<'_>, caller: Entity) {
let world = system.world();

world.get::<&Compose>(|compose| {
caller.entity_view(world).get::<(
Option<&Vanished>,
&ConnectionId,
&hyperion::simulation::Name,
)>(|(vanished, stream, name)| {
let is_vanished = vanished.is_some_and(Vanished::is_vanished);
let caller = caller.entity_view(world);
if is_vanished {
caller.set(Vanished::new(false));
let packet = hyperion::net::agnostic::chat(format!(
"§7[Admin] §f{name} §7is now visible",
));
compose.unicast(&packet, *stream, system).unwrap();
} else {
caller.set(Vanished::new(true));
let packet = hyperion::net::agnostic::chat(format!(
"§7[Admin] §f{name} §7is now vanished",
));
compose.unicast(&packet, *stream, system).unwrap();
}
});
});
}
}
3 changes: 2 additions & 1 deletion events/tag/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use hyperion::{
simulation::{Player, blocks::Blocks},
};
use hyperion_clap::hyperion_command::CommandRegistry;
use module::block::BlockModule;
use module::{block::BlockModule, vanish::VanishModule};

mod module;

Expand Down Expand Up @@ -97,6 +97,7 @@ impl Module for TagModule {
world.import::<hyperion_utils::HyperionUtilsModule>();
world.import::<hyperion_clap::ClapCommandModule>();
world.import::<SkinModule>();
world.import::<VanishModule>();

world.get::<&mut CommandRegistry>(|registry| {
command::register(registry, world);
Expand Down
1 change: 1 addition & 0 deletions events/tag/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod level;
pub mod regeneration;
pub mod spawn;
pub mod stats;
pub mod vanish;
87 changes: 87 additions & 0 deletions events/tag/src/module/vanish.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use flecs_ecs::{core::World, prelude::*};
use hyperion::{
net::{Compose, ConnectionId},
simulation::{Uuid, metadata::entity::EntityFlags},
};
use valence_protocol::packets::play::{self, player_list_s2c::PlayerListActions};
use valence_server::GameMode;

#[derive(Component)]
pub struct VanishModule;

#[derive(Default, Component, Debug)]
pub struct Vanished(pub bool);

impl Vanished {
#[must_use]
pub const fn new(is_vanished: bool) -> Self {
Self(is_vanished)
}

#[must_use]
pub const fn is_vanished(&self) -> bool {
self.0
}
}

impl Module for VanishModule {
fn module(world: &World) {
world.component::<Vanished>();

system!(
"vanish_sync",
world,
&Compose($),
&ConnectionId,
&Vanished,
&Uuid,
)
.multi_threaded()
.kind::<flecs::pipeline::PreStore>()
.each_iter(move |it, row, (compose, _connection_id, vanished, uuid)| {
let entity = it.entity(row);
let system = it.system();
let world = it.world();

if vanished.is_vanished() {
// Remove from player list and make them invisible
let remove_packet = play::PlayerListS2c {
actions: PlayerListActions::new()
.with_update_listed(true)
.with_update_game_mode(true),
entries: vec![play::player_list_s2c::PlayerListEntry {
player_uuid: uuid.0,
listed: false,
game_mode: GameMode::Survival,
..Default::default()
}]
.into(),
};
compose.broadcast(&remove_packet, system).send().unwrap();

// Set entity flags to make them invisible
let flags = EntityFlags::INVISIBLE;
entity.entity_view(world).set(flags);
} else {
// Add back to player list and make them visible
let add_packet = play::PlayerListS2c {
actions: PlayerListActions::new()
.with_update_listed(true)
.with_update_game_mode(true),
entries: vec![play::player_list_s2c::PlayerListEntry {
player_uuid: uuid.0,
listed: true,
game_mode: GameMode::Survival,
..Default::default()
}]
.into(),
};
compose.broadcast(&add_packet, system).send().unwrap();

// Clear invisible flag
let flags = EntityFlags::default();
entity.entity_view(world).set(flags);
}
});
}
}

0 comments on commit 37ad0fd

Please sign in to comment.