pumpkinplus/modules/mechanics/server/
tablist.rs1use crate::config::ConfigManager;
21use crate::mechanics::mechanic::Mechanic;
22use pumpkin_plugin_api::events::{
23 EventData, EventHandler, EventPriority, PlayerJoinEvent, PlayerLeaveEvent,
24};
25use pumpkin_plugin_api::player::Player;
26use pumpkin_plugin_api::text::TextComponent;
27use pumpkin_plugin_api::{Context, Server};
28use serde::{Deserialize, Serialize};
29
30#[derive(Default)]
32pub struct Tablist;
33
34impl Mechanic for Tablist {
35 fn enabled(&self) -> bool {
36 ConfigManager::get()
37 .map(|cm| cm.get_config::<TablistConfig>().enabled)
38 .unwrap_or(true)
39 }
40
41 fn events(&self, context: &Context) {
42 context
43 .register_event_handler::<PlayerJoinEvent, _>(Tablist, EventPriority::Normal, true)
44 .expect("failed to register tablist event handler");
45 context
46 .register_event_handler::<PlayerLeaveEvent, _>(Tablist, EventPriority::Normal, true)
47 .expect("failed to register tablist leave event handler");
48 }
49}
50
51impl Tablist {
52 fn replace_placeholders(text: &str, server: &Server, player: &Player) -> String {
55 let player_name = player.get_display_name().get_text();
56 let online = server.get_player_count();
57 let tps = server.get_tps();
58 let mspt = server.get_mspt();
59
60 text.replace("{player}", &player_name)
61 .replace("{online}", &online.to_string())
62 .replace("{tps}", &format!("{:.1}", tps))
63 .replace("{mspt}", &format!("{:.1}", mspt))
64 }
65
66 fn update_tablist_for_player(config: &TablistConfig, server: &Server, player: &Player) {
69 let header = Self::replace_placeholders(&config.header, server, player);
70 let footer = Self::replace_placeholders(&config.footer, server, player);
71 player
72 .set_tab_list_header_footer(TextComponent::text(&header), TextComponent::text(&footer));
73 }
74
75 fn update_tablist_for_all_players(server: &Server) {
77 let config: TablistConfig = ConfigManager::get()
78 .map(|cm| cm.get_config())
79 .unwrap_or_default();
80
81 if !config.enabled {
82 return;
83 }
84
85 for player in server.get_all_players() {
86 Self::update_tablist_for_player(&config, server, &player);
87 }
88 }
89}
90
91impl EventHandler<PlayerJoinEvent> for Tablist {
92 fn handle(
93 &self,
94 server: Server,
95 event: EventData<PlayerJoinEvent>,
96 ) -> EventData<PlayerJoinEvent> {
97 let config: TablistConfig = ConfigManager::get()
98 .map(|cm| cm.get_config())
99 .unwrap_or_default();
100
101 if !self.enabled() {
102 return event;
103 }
104
105 Self::update_tablist_for_player(&config, &server, &event.player);
106
107 for player in server.get_all_players() {
108 if player.get_display_name().get_text() != event.player.get_display_name().get_text() {
109 Self::update_tablist_for_player(&config, &server, &player);
110 }
111 }
112
113 event
114 }
115}
116
117impl EventHandler<PlayerLeaveEvent> for Tablist {
118 fn handle(
119 &self,
120 server: Server,
121 event: EventData<PlayerLeaveEvent>,
122 ) -> EventData<PlayerLeaveEvent> {
123 if !self.enabled() {
124 return event;
125 }
126
127 Self::update_tablist_for_all_players(&server);
128
129 event
130 }
131}
132
133#[derive(Debug, Default, Clone, Serialize, Deserialize)]
135pub struct TablistConfig {
136 pub enabled: bool,
138 pub header: String,
140 pub footer: String,
142}