Skip to content

Commit 8dab473

Browse files
committed
mutable status stuff
1 parent 04af60b commit 8dab473

File tree

9 files changed

+101
-51
lines changed

9 files changed

+101
-51
lines changed

server/src/network/client.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ use crate::network::protocol::login::serverbound::LoginStart;
1010
use crate::network::protocol::play::serverbound::Play;
1111
use crate::network::protocol::status::clientbound::{StatusPong, StatusResponse};
1212
use crate::network::protocol::status::serverbound::StatusPing;
13+
use crate::network::status::StatusBytes;
1314
use crate::player::player::{ClientId, GameProfile};
1415
use crate::GameProfileProperty;
1516
use anyhow::bail;
1617
use bytes::{Buf, Bytes, BytesMut};
1718
use fstr::FString;
1819
use std::collections::HashMap;
19-
use std::sync::Arc;
2020
use tokio::io::{AsyncReadExt, AsyncWriteExt};
2121
use tokio::net::TcpStream;
2222
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
@@ -40,8 +40,7 @@ pub async fn handle_client(
4040
mut rx: UnboundedReceiver<ClientHandlerMessage>,
4141
main_tx: UnboundedSender<MainThreadMessage>,
4242
network_tx: UnboundedSender<NetworkThreadMessage>,
43-
// probably needs to be made mutable?, so it can update the player count, etc
44-
status: Arc<String>
43+
status: StatusBytes
4544
) {
4645
let mut client = Client {
4746
id: client_id,
@@ -62,7 +61,7 @@ pub async fn handle_client(
6261
&mut client,
6362
&tx,
6463
&main_tx,
65-
status.as_ref()
64+
&status
6665
).await {
6766
eprintln!("client {client_id:?} errored: {err}");
6867
break;
@@ -89,7 +88,9 @@ pub async fn handle_client(
8988
}
9089
}
9190

92-
let _ = network_tx.send(NetworkThreadMessage::ConnectionClosed { client_id });
91+
if client.connection_state == ConnectionState::Play {
92+
let _ = network_tx.send(NetworkThreadMessage::ConnectionClosed { client_id });
93+
}
9394
println!("handle client for {client_id:?} closed.");
9495
}
9596

@@ -98,7 +99,7 @@ async fn read_packets(
9899
client: &mut Client,
99100
client_tx: &UnboundedSender<ClientHandlerMessage>,
100101
main_tx: &UnboundedSender<MainThreadMessage>,
101-
status: &String
102+
status: &StatusBytes
102103
) -> anyhow::Result<()> {
103104
while let Some(mut buffer) = try_read_packet_slice(buffer) {
104105
match client.connection_state {
@@ -158,14 +159,14 @@ fn handle_handshake(buffer: &mut impl Buf, client: &mut Client) -> anyhow::Resul
158159
fn handle_status(
159160
buffer: &mut impl Buf,
160161
client_tx: &UnboundedSender<ClientHandlerMessage>,
161-
status: &String
162+
status: &StatusBytes
162163
) -> anyhow::Result<()> {
163164
let packet_id = *VarInt::read(buffer)?;
164165
let mut packet_buffer = PacketBuffer::new();
165166
match packet_id {
166167
0x00 => {
167168
packet_buffer.write_packet(&StatusResponse {
168-
status,
169+
status: status.get_str(),
169170
});
170171
}
171172
0x01 => {
@@ -215,6 +216,8 @@ fn handle_login(
215216
),
216217
};
217218

219+
client.connection_state = ConnectionState::Play;
220+
218221
packet_buffer.write_packet(&LoginSuccess {
219222
uuid: uuid.hyphenated().to_string(),
220223
name: game_profile.username.clone(),
@@ -225,7 +228,6 @@ fn handle_login(
225228
client_id: client.id,
226229
profile: game_profile,
227230
})?;
228-
client.connection_state = ConnectionState::Play;
229231
}
230232
_ => bail!("Unknown packet id during login")
231233
}

server/src/network/internal_packets.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
use crate::network::protocol::play::serverbound::Play;
2+
use crate::network::status::StatusUpdate;
23
use crate::player::player::{ClientId, GameProfile};
34
use bytes::Bytes;
45

56
pub enum NetworkThreadMessage {
7+
UpdateStatus {
8+
update: StatusUpdate
9+
},
10+
611
SendPackets {
712
client_id: ClientId,
813
buffer: Bytes,

server/src/network/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ pub mod network;
44
pub mod connection_state;
55
pub mod internal_packets;
66
pub mod protocol;
7-
pub mod binary;
7+
pub mod binary;
8+
pub mod status;

server/src/network/network.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::network::client::handle_client;
2+
use crate::network::status::Status;
23
use core::panic;
34
use std::collections::HashMap;
45
use std::sync::Arc;
@@ -15,7 +16,7 @@ type ClientMap = HashMap<ClientId, UnboundedSender<ClientHandlerMessage>>;
1516

1617
pub fn start_network(
1718
ip: &'static str,
18-
status: Arc<String> // should probably be mutable
19+
status: Status,
1920
) -> (Sender<NetworkThreadMessage>, Receiver<MainThreadMessage>) {
2021
let (network_tx, network_rx) = unbounded_channel::<NetworkThreadMessage>();
2122
let (main_tx, main_rx) = unbounded_channel::<MainThreadMessage>();
@@ -25,7 +26,7 @@ pub fn start_network(
2526

2627
async fn run_network_thread(
2728
ip: &'static str,
28-
status: Arc<String>,
29+
mut status: Status,
2930
mut network_rx: Receiver<NetworkThreadMessage>,
3031
network_tx: Sender<NetworkThreadMessage>,
3132
main_tx: Sender<MainThreadMessage>,
@@ -57,7 +58,7 @@ async fn run_network_thread(
5758
client_rx,
5859
main_tx.clone(),
5960
network_tx.clone(),
60-
status.clone()
61+
status.get()
6162
));
6263
}
6364

@@ -66,6 +67,7 @@ async fn run_network_thread(
6667
// we can just discard main thread -> network thread messages with a disconnected client_id
6768
// as the main thread either already has or will be be informed shortly of this issue
6869
match msg {
70+
NetworkThreadMessage::UpdateStatus { update } => status.set(update),
6971
NetworkThreadMessage::SendPackets { client_id, buffer } => {
7072
if let Some(client_tx) = clients.get(&client_id) {
7173
if let Err(e) = client_tx.send(ClientHandlerMessage::Send(buffer)) {
@@ -84,9 +86,7 @@ async fn run_network_thread(
8486
}
8587
}
8688

87-
NetworkThreadMessage::ConnectionClosed { client_id } => {
88-
disconnect_client(client_id, &main_tx, &mut clients)
89-
}
89+
NetworkThreadMessage::ConnectionClosed { client_id } => disconnect_client(client_id, &main_tx, &mut clients),
9090
}
9191
}
9292
}

server/src/network/status.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use bytes::Bytes;
2+
use crate::types::chat_component::ChatComponent;
3+
4+
#[derive(Debug, Clone)]
5+
pub struct StatusBytes(Bytes);
6+
impl StatusBytes {
7+
#[inline(always)]
8+
pub fn get_str(&self) -> &str {
9+
// SAFETY: These should always be constructed from a String.
10+
unsafe { str::from_utf8_unchecked(&self.0) }
11+
}
12+
}
13+
14+
pub struct Status {
15+
players: u32,
16+
max_players: u32,
17+
18+
info: ChatComponent,
19+
icon: &'static str,
20+
21+
cached: Option<StatusBytes>,
22+
}
23+
24+
impl Status {
25+
pub fn new(players: u32, max_players: u32, info: ChatComponent, icon: &'static str) -> Self {
26+
Self { players, max_players, info, icon, cached: None, }
27+
}
28+
29+
pub fn set(&mut self, update: StatusUpdate) {
30+
match update {
31+
StatusUpdate::Players(count) => self.players = count,
32+
StatusUpdate::MaxPlayers(count) => self.max_players = count,
33+
StatusUpdate::Info(component) => self.info = component,
34+
StatusUpdate::Icon(icon_data) => self.icon = icon_data,
35+
}
36+
self.cached = None;
37+
}
38+
39+
pub fn get(&mut self) -> StatusBytes {
40+
self.cached.get_or_insert_with(|| {
41+
StatusBytes(Bytes::from(format!(r#"{{
42+
"version": {{
43+
"name": "1.8.9",
44+
"protocol": 47
45+
}},
46+
"players": {{
47+
"max": {},
48+
"online": {}
49+
}},
50+
"description": {},
51+
"favicon": "data:image/png;base64,{}"
52+
}}"#, self.max_players, self.players, self.info.serialize(), self.icon)))
53+
}).clone()
54+
}
55+
}
56+
57+
pub enum StatusUpdate {
58+
Players(u32),
59+
MaxPlayers(u32),
60+
Info(ChatComponent),
61+
Icon(&'static str),
62+
}

server/src/world/chunk/chunk.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::collections::HashSet;
88

99
pub struct ChunkSection {
1010
solid_block_amount: u16,
11-
data: [u16; 4096],
11+
data: Box<[u16; 4096]>,
1212
}
1313
pub struct Chunk {
1414
pub chunk_sections: [Option<ChunkSection>; 16],
@@ -52,7 +52,7 @@ impl Chunk {
5252
if self.chunk_sections[section_index].is_none() {
5353
self.chunk_sections[section_index] = Some(ChunkSection {
5454
solid_block_amount: 0,
55-
data: [0; 4096],
55+
data: Box::new([0; 4096]),
5656
})
5757
}
5858
if let Some(section) = &mut self.chunk_sections[section_index] {
@@ -92,7 +92,7 @@ impl Chunk {
9292
if section.solid_block_amount == 0 {
9393
continue
9494
}
95-
for block in section.data {
95+
for block in section.data.iter() {
9696
data[offset] = (block & 0xFF) as u8;
9797
data[offset + 1] = ((block >> 8) & 0xFF) as u8;
9898
offset += 2;

src/assets/assets.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub struct Assets {
1515
pub dungeon_seeds: Vec<&'static str>,
1616
pub door_data: HashMap<DoorType, Vec<Vec<Blocks>>>,
1717
pub room_data: DeterministicHashMap<usize, RoomData>,
18-
pub icon_data: String,
18+
pub icon_data: &'static str,
1919
}
2020

2121
impl Assets {

src/assets/load_asset.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,10 @@ impl LoadAsset for DungeonStorageAssets {
107107

108108
impl LoadAsset for FaviconAssets {
109109
const SUBPATH: &'static str = "favicon.png";
110-
type Output = String;
110+
type Output = &'static str;
111111

112112
async fn load_asset(path: &Path) -> anyhow::Result<Self::Output> {
113113
let bytes = fs::read(path.join(Self::SUBPATH)).await?;
114-
Ok(general_purpose::STANDARD.encode(&bytes))
114+
Ok(Box::leak(general_purpose::STANDARD.encode(&bytes).into_boxed_str()))
115115
}
116116
}

src/main.rs

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ use server::entity::entity_metadata::{EntityMetadata, EntityVariant};
1010
use server::inventory::menu::OpenContainer;
1111
use server::network::internal_packets::NetworkThreadMessage;
1212
use server::network::network::start_network;
13+
use server::network::status::Status;
14+
use server::types::chat_component::{ChatComponent, MCColors};
1315
use server::utils::seeded_rng::{seeded_rng, SeededRng};
1416
use server::world::world::World;
15-
use std::sync::Arc;
1617
use std::time::Duration;
1718
use tokio::sync::mpsc::error::TryRecvError;
1819
use tokio::sync::mpsc::UnboundedSender as Sender;
@@ -80,34 +81,13 @@ async fn main() -> anyhow::Result<()> {
8081
// ^^^ for rooms/doors this is really pointless, because there is no reason to customize them, especially once finalised
8182
// I can understand it for favicon tho
8283

83-
let (tx, mut rx) = start_network("127.0.0.1:4972", Arc::new(
84-
r#"{
85-
"version": {
86-
"name": "1.8.9",
87-
"protocol": 47
88-
},
89-
"players": {
90-
"max": 1,
91-
"online": 0
92-
},
93-
"description": {
94-
"text": "RustClear",
95-
"color": "gold",
96-
"extra": [
97-
{
98-
"text": " version ",
99-
"color": "gray"
100-
},
101-
{
102-
"text": "{version}",
103-
"color": "green"
104-
}
105-
]
106-
},
107-
"favicon": "data:image/png;base64,<data>"
108-
}"#.into()
109-
));
110-
84+
let text = ChatComponent::new("RustClear").color(MCColors::Gold)
85+
.append(ChatComponent::new(" version ").color(MCColors::Gray))
86+
.append(ChatComponent::new(env!("CARGO_PKG_VERSION")).color(MCColors::Green));
87+
88+
let status = Status::new(1, 0, text, get_assets().icon_data);
89+
let (tx, mut rx) = start_network("127.0.0.1:4972", status);
90+
11191
let mut tick_interval = tokio::time::interval(Duration::from_millis(50));
11292
let mut world = initialize_world(tx)?;
11393
spawn_mort(&mut world);

0 commit comments

Comments
 (0)