Skip to content

Commit 37ad0fd

Browse files
feat: vanish 💨 (#670)
added `/vanish` command for admins. --------- Co-authored-by: Andrew Gazelka <andrew.gazelka@gmail.com>
1 parent e272fa0 commit 37ad0fd

File tree

10 files changed

+164
-29
lines changed

10 files changed

+164
-29
lines changed

‎Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎crates/hyperion/src/egress/player_join/mod.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -258,17 +258,6 @@ pub fn player_join_world(
258258

259259
metadata.encode(*flags);
260260

261-
if let Some(view) = metadata.get_and_clear() {
262-
let pkt = play::EntityTrackerUpdateS2c {
263-
entity_id: VarInt(query_entity.minecraft_id()),
264-
tracked_values: RawBytes(&view),
265-
};
266-
267-
bundle
268-
.add_packet(&pkt)
269-
.context("failed to send player spawn packet")?;
270-
}
271-
272261
Ok(())
273262
};
274263

‎crates/hyperion/src/egress/sync_entity_state.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@ use glam::Vec3;
66
use hyperion_inventory::PlayerInventory;
77
use hyperion_utils::EntityExt;
88
use tracing::error;
9-
use valence_protocol::{RawBytes, VarInt, packets::play};
9+
use valence_protocol::{
10+
RawBytes, VarInt,
11+
packets::play::{self},
12+
};
1013

1114
use crate::{
1215
Prev,
1316
net::{Compose, ConnectionId},
14-
simulation::{Position, Velocity, Xp, animation::ActiveAnimation, metadata::MetadataChanges},
17+
simulation::{
18+
Position, Velocity, Xp,
19+
animation::ActiveAnimation,
20+
metadata::{MetadataChanges, get_and_clear_metadata},
21+
},
1522
};
1623

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

118-
let metadata = metadata_changes.get_and_clear();
125+
let metadata = get_and_clear_metadata(metadata_changes);
119126

120127
if let Some(view) = metadata {
121128
let pkt = play::EntityTrackerUpdateS2c {

‎crates/hyperion/src/simulation/metadata/mod.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -233,16 +233,6 @@ impl MetadataChanges {
233233
let r#type = metadata.to_type();
234234
r#type.encode(&mut self.0).unwrap();
235235
}
236-
237-
pub fn get_and_clear(&mut self) -> Option<MetadataView<'_>> {
238-
if self.is_empty() {
239-
return None;
240-
}
241-
// denote end of metadata
242-
self.0.push(0xff);
243-
244-
Some(MetadataView(self))
245-
}
246236
}
247237

248238
#[derive(Debug)]
@@ -261,3 +251,14 @@ impl Drop for MetadataView<'_> {
261251
self.0.0.clear();
262252
}
263253
}
254+
255+
/// This is only meant to be called from egress systems
256+
pub(crate) fn get_and_clear_metadata(metadata: &mut MetadataChanges) -> Option<MetadataView<'_>> {
257+
if metadata.is_empty() {
258+
return None;
259+
}
260+
// denote end of metadata
261+
metadata.0.push(0xff);
262+
263+
Some(MetadataView(metadata))
264+
}

‎events/tag/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ tracing = { workspace = true }
2525
tracing-subscriber = { workspace = true }
2626
tracing-tracy = { workspace = true }
2727
uuid = { version = "1.11.0", features = ["v4"] }
28-
28+
valence_protocol = { workspace = true }
29+
valence_server = { workspace = true }
2930

3031
[dev-dependencies]
3132
tracing = {workspace = true, features = ["release_max_level_info"]}

‎events/tag/src/command.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use hyperion_clap::{MinecraftCommand, hyperion_command::CommandRegistry};
44
use crate::command::{
55
bow::BowCommand, class::ClassCommand, fly::FlyCommand, gui::GuiCommand,
66
raycast::RaycastCommand, replace::ReplaceCommand, shoot::ShootCommand, spawn::SpawnCommand,
7-
speed::SpeedCommand, xp::XpCommand,
7+
speed::SpeedCommand, vanish::VanishCommand, xp::XpCommand,
88
};
99

1010
mod bow;
@@ -16,17 +16,19 @@ mod replace;
1616
mod shoot;
1717
mod spawn;
1818
mod speed;
19+
mod vanish;
1920
mod xp;
2021

2122
pub fn register(registry: &mut CommandRegistry, world: &World) {
2223
BowCommand::register(registry, world);
2324
ClassCommand::register(registry, world);
2425
FlyCommand::register(registry, world);
26+
GuiCommand::register(registry, world);
2527
RaycastCommand::register(registry, world);
2628
ReplaceCommand::register(registry, world);
2729
ShootCommand::register(registry, world);
30+
SpawnCommand::register(registry, world);
2831
SpeedCommand::register(registry, world);
32+
VanishCommand::register(registry, world);
2933
XpCommand::register(registry, world);
30-
SpawnCommand::register(registry, world);
31-
GuiCommand::register(registry, world);
3234
}

‎events/tag/src/command/vanish.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use clap::Parser;
2+
use flecs_ecs::{
3+
core::{Entity, EntityView, EntityViewGet, WorldProvider},
4+
prelude::*,
5+
};
6+
use hyperion::net::{Compose, ConnectionId};
7+
use hyperion_clap::{CommandPermission, MinecraftCommand};
8+
9+
use crate::module::vanish::Vanished;
10+
11+
#[derive(Parser, CommandPermission, Debug)]
12+
#[command(name = "vanish")]
13+
#[command_permission(group = "Admin")]
14+
pub struct VanishCommand;
15+
16+
impl MinecraftCommand for VanishCommand {
17+
fn execute(self, system: EntityView<'_>, caller: Entity) {
18+
let world = system.world();
19+
20+
world.get::<&Compose>(|compose| {
21+
caller.entity_view(world).get::<(
22+
Option<&Vanished>,
23+
&ConnectionId,
24+
&hyperion::simulation::Name,
25+
)>(|(vanished, stream, name)| {
26+
let is_vanished = vanished.is_some_and(Vanished::is_vanished);
27+
let caller = caller.entity_view(world);
28+
if is_vanished {
29+
caller.set(Vanished::new(false));
30+
let packet = hyperion::net::agnostic::chat(format!(
31+
"§7[Admin] §f{name} §7is now visible",
32+
));
33+
compose.unicast(&packet, *stream, system).unwrap();
34+
} else {
35+
caller.set(Vanished::new(true));
36+
let packet = hyperion::net::agnostic::chat(format!(
37+
"§7[Admin] §f{name} §7is now vanished",
38+
));
39+
compose.unicast(&packet, *stream, system).unwrap();
40+
}
41+
});
42+
});
43+
}
44+
}

‎events/tag/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use hyperion::{
1212
simulation::{Player, blocks::Blocks},
1313
};
1414
use hyperion_clap::hyperion_command::CommandRegistry;
15-
use module::block::BlockModule;
15+
use module::{block::BlockModule, vanish::VanishModule};
1616

1717
mod module;
1818

@@ -97,6 +97,7 @@ impl Module for TagModule {
9797
world.import::<hyperion_utils::HyperionUtilsModule>();
9898
world.import::<hyperion_clap::ClapCommandModule>();
9999
world.import::<SkinModule>();
100+
world.import::<VanishModule>();
100101

101102
world.get::<&mut CommandRegistry>(|registry| {
102103
command::register(registry, world);

‎events/tag/src/module.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pub mod level;
66
pub mod regeneration;
77
pub mod spawn;
88
pub mod stats;
9+
pub mod vanish;

‎events/tag/src/module/vanish.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use flecs_ecs::{core::World, prelude::*};
2+
use hyperion::{
3+
net::{Compose, ConnectionId},
4+
simulation::{Uuid, metadata::entity::EntityFlags},
5+
};
6+
use valence_protocol::packets::play::{self, player_list_s2c::PlayerListActions};
7+
use valence_server::GameMode;
8+
9+
#[derive(Component)]
10+
pub struct VanishModule;
11+
12+
#[derive(Default, Component, Debug)]
13+
pub struct Vanished(pub bool);
14+
15+
impl Vanished {
16+
#[must_use]
17+
pub const fn new(is_vanished: bool) -> Self {
18+
Self(is_vanished)
19+
}
20+
21+
#[must_use]
22+
pub const fn is_vanished(&self) -> bool {
23+
self.0
24+
}
25+
}
26+
27+
impl Module for VanishModule {
28+
fn module(world: &World) {
29+
world.component::<Vanished>();
30+
31+
system!(
32+
"vanish_sync",
33+
world,
34+
&Compose($),
35+
&ConnectionId,
36+
&Vanished,
37+
&Uuid,
38+
)
39+
.multi_threaded()
40+
.kind::<flecs::pipeline::PreStore>()
41+
.each_iter(move |it, row, (compose, _connection_id, vanished, uuid)| {
42+
let entity = it.entity(row);
43+
let system = it.system();
44+
let world = it.world();
45+
46+
if vanished.is_vanished() {
47+
// Remove from player list and make them invisible
48+
let remove_packet = play::PlayerListS2c {
49+
actions: PlayerListActions::new()
50+
.with_update_listed(true)
51+
.with_update_game_mode(true),
52+
entries: vec![play::player_list_s2c::PlayerListEntry {
53+
player_uuid: uuid.0,
54+
listed: false,
55+
game_mode: GameMode::Survival,
56+
..Default::default()
57+
}]
58+
.into(),
59+
};
60+
compose.broadcast(&remove_packet, system).send().unwrap();
61+
62+
// Set entity flags to make them invisible
63+
let flags = EntityFlags::INVISIBLE;
64+
entity.entity_view(world).set(flags);
65+
} else {
66+
// Add back to player list and make them visible
67+
let add_packet = play::PlayerListS2c {
68+
actions: PlayerListActions::new()
69+
.with_update_listed(true)
70+
.with_update_game_mode(true),
71+
entries: vec![play::player_list_s2c::PlayerListEntry {
72+
player_uuid: uuid.0,
73+
listed: true,
74+
game_mode: GameMode::Survival,
75+
..Default::default()
76+
}]
77+
.into(),
78+
};
79+
compose.broadcast(&add_packet, system).send().unwrap();
80+
81+
// Clear invisible flag
82+
let flags = EntityFlags::default();
83+
entity.entity_view(world).set(flags);
84+
}
85+
});
86+
}
87+
}

0 commit comments

Comments
 (0)