Skip to content

Commit

Permalink
so much optimization i can't take it anymore
Browse files Browse the repository at this point in the history
  • Loading branch information
dankmeme01 committed Nov 24, 2023
1 parent 4d4bda0 commit e27fe28
Show file tree
Hide file tree
Showing 13 changed files with 313 additions and 140 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This repository contains the complete rewrite of Globed, for Geometry Dash 2.2 a

* Real-time multiplayer
* Voice chat and text messages with full encryption and zero logging
* blazing fast server written in pure Rust 🚀 (feauring only **one** unsafe block)
* blazing fast server written in pure Rust 🚀 (feauring only **two** unsafe blocks so far)

## Installation

Expand Down
1 change: 1 addition & 0 deletions server/central/src/web/routes/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ pub async fn challenge_start(context: &mut Context<ServerState>) -> roa::Result
Ok(())
}

// rollercoaster of a function i'd say
#[allow(clippy::too_many_lines)]
pub async fn challenge_finish(context: &mut Context<ServerState>) -> roa::Result {
check_user_agent!(context, _ua);
Expand Down
10 changes: 5 additions & 5 deletions server/game/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ edition = "2021"
[dependencies]
globed-shared = { path = "../shared" }

alloca = "0.4.0"
anyhow = "1.0.75"
array-init = "2.1.0"
bytebuffer = "2.2.0"
colored = "2.0.4"
crypto_box = { version = "0.9.1", features = ["std", "chacha20"] }
lazy_static = "1.4.0"
log = { version = "0.4.20" }
num_enum = "0.7.1"
parking_lot = "0.12.1"
reqwest = "0.11.22"
rustc-hash = "1.1.0"
serde = { version = "1.0.192", features = ["serde_derive"] }
serde_json = "1.0.108"
time = { version = "0.3.30", features = ["formatting"] }
tokio = { version = "1.34.0", features = ["full"] }
parking_lot = "0.12.1"
array-init = "2.1.0"
num_enum = "0.7.1"
alloca = "0.4.0"
lazy_static = "1.4.0"
54 changes: 36 additions & 18 deletions server/game/src/bytebufferext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ pub trait Decodable {
Self: Sized;
}

// For dynamically sized types, this must be the maximum permitted size in the encoded form.
// If encode() tries to write more bytes than this value, FastByteBuffer will panic.
pub trait EncodableWithKnownSize: Encodable {
const ENCODED_SIZE: usize;
}

pub const MAX_ENCODED_STRING_SIZE: usize = 512 + size_of_types!(u32); // 512 chars

macro_rules! encode_impl {
($packet_type:ty, $buf:ident, $self:ident, $encode:expr) => {
impl crate::bytebufferext::Encodable for $packet_type {
($typ:ty, $buf:ident, $self:ident, $encode:expr) => {
impl crate::bytebufferext::Encodable for $typ {
fn encode(&$self, $buf: &mut bytebuffer::ByteBuffer) {
$encode
}
Expand All @@ -31,8 +39,8 @@ macro_rules! encode_impl {
}

macro_rules! decode_impl {
($packet_type:ty, $buf:ident, $decode:expr) => {
impl crate::bytebufferext::Decodable for $packet_type {
($typ:ty, $buf:ident, $decode:expr) => {
impl crate::bytebufferext::Decodable for $typ {
fn decode($buf: &mut bytebuffer::ByteBuffer) -> anyhow::Result<Self> {
$decode
}
Expand All @@ -45,49 +53,59 @@ macro_rules! decode_impl {
}

macro_rules! encode_unimpl {
($packet_type:ty) => {
impl crate::bytebufferext::Encodable for $packet_type {
($typ:ty) => {
impl crate::bytebufferext::Encodable for $typ {
fn encode(&self, _: &mut bytebuffer::ByteBuffer) {
panic!(
"Tried to call {}::encode when Encodable was not implemented for this type",
stringify!($packet_type)
stringify!($typ)
);
}

fn encode_fast(&self, _: &mut crate::bytebufferext::FastByteBuffer) {
panic!(
"Tried to call {}::encode_fast when Encodable was not implemented for this type",
stringify!($packet_type)
stringify!($typ)
);
}
}
};
}

macro_rules! decode_unimpl {
($packet_type:ty) => {
impl crate::bytebufferext::Decodable for $packet_type {
($typ:ty) => {
impl crate::bytebufferext::Decodable for $typ {
fn decode(_: &mut bytebuffer::ByteBuffer) -> anyhow::Result<Self> {
Err(anyhow::anyhow!(
"decoding unimplemented for {}",
stringify!($packet_type)
))
Err(anyhow::anyhow!("decoding unimplemented for {}", stringify!($typ)))
}

fn decode_from_reader(_: &mut bytebuffer::ByteReader) -> anyhow::Result<Self> {
Err(anyhow::anyhow!(
"decoding unimplemented for {}",
stringify!($packet_type)
))
Err(anyhow::anyhow!("decoding unimplemented for {}", stringify!($typ)))
}
}
};
}

macro_rules! size_calc_impl {
($typ:ty, $calc:expr) => {
impl crate::bytebufferext::EncodableWithKnownSize for $typ {
const ENCODED_SIZE: usize = $calc;
}
};
}

macro_rules! size_of_types {
($($t:ty),+ $(,)?) => {{
0 $(+ std::mem::size_of::<$t>())*
}};
}

pub(crate) use decode_impl;
pub(crate) use decode_unimpl;
pub(crate) use encode_impl;
pub(crate) use encode_unimpl;
pub(crate) use size_calc_impl;
pub(crate) use size_of_types;

/* ByteBuffer extensions */
pub trait ByteBufferExt {
Expand Down
7 changes: 6 additions & 1 deletion server/game/src/data/packets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ macro_rules! packet {
}
}

impl crate::data::packets::PacketWithId for $packet_type {
impl crate::data::packets::PacketMetadata for $packet_type {
const PACKET_ID: crate::data::packets::PacketId = $packet_id;
const ENCRYPTED: bool = $encrypted;
}
};
($packet_type:ident, $packet_id:expr, $encrypted:expr, { $($field:ident: $field_type:ty),* $(,)? }) => {
Expand All @@ -49,6 +50,7 @@ macro_rules! packet {
impl crate::data::packets::PacketMetadata for $packet_type {
const PACKET_ID: crate::data::packets::PacketId = $packet_id;
const ENCRYPTED: bool = $encrypted;
const NAME: &'static str = stringify!($packet_type);
}
};
}
Expand All @@ -60,6 +62,8 @@ macro_rules! empty_server_packet {
encode_impl!($packet_type, _buf, self, {});

decode_unimpl!($packet_type);

size_calc_impl!($packet_type, 0);
};
}

Expand All @@ -86,6 +90,7 @@ pub trait Packet: Encodable + Decodable + Send + Sync + PacketMetadata {
pub trait PacketMetadata {
const PACKET_ID: PacketId;
const ENCRYPTED: bool;
const NAME: &'static str;
}

pub const PACKET_HEADER_LEN: usize = std::mem::size_of::<PacketId>() + std::mem::size_of::<bool>();
14 changes: 13 additions & 1 deletion server/game/src/data/packets/server/connection.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
bytebufferext::{decode_unimpl, encode_impl, ByteBufferExtWrite},
bytebufferext::*,
data::{
packets::{empty_server_packet, packet},
types::CryptoPublicKey,
Expand All @@ -20,6 +20,8 @@ encode_impl!(PingResponsePacket, buf, self, {

decode_unimpl!(PingResponsePacket);

size_calc_impl!(PingResponsePacket, size_of_types!(u32, u32));

/* CryptoHandshakeResponsePacket - 20001 */

packet!(CryptoHandshakeResponsePacket, 20001, false, {
Expand All @@ -32,6 +34,8 @@ encode_impl!(CryptoHandshakeResponsePacket, buf, self, {

decode_unimpl!(CryptoHandshakeResponsePacket);

size_calc_impl!(CryptoHandshakeResponsePacket, CryptoPublicKey::ENCODED_SIZE);

/* KeepaliveResponsePacket - 20002 */

packet!(KeepaliveResponsePacket, 20002, false, {
Expand All @@ -44,6 +48,8 @@ encode_impl!(KeepaliveResponsePacket, buf, self, {

decode_unimpl!(KeepaliveResponsePacket);

size_calc_impl!(KeepaliveResponsePacket, size_of_types!(u32));

/* ServerDisconnectPacket - 20003 */

packet!(ServerDisconnectPacket, 20003, false, {
Expand All @@ -56,6 +62,8 @@ encode_impl!(ServerDisconnectPacket, buf, self, {

decode_unimpl!(ServerDisconnectPacket);

size_calc_impl!(ServerDisconnectPacket, MAX_ENCODED_STRING_SIZE);

/* LoggedInPacket - 20004 */

empty_server_packet!(LoggedInPacket, 20004);
Expand All @@ -72,6 +80,8 @@ encode_impl!(LoginFailedPacket, buf, self, {

decode_unimpl!(LoginFailedPacket);

size_calc_impl!(LoginFailedPacket, MAX_ENCODED_STRING_SIZE);

/* ServerNoticePacket - 20006 */
// used to communicate a simple message to the user

Expand All @@ -84,3 +94,5 @@ encode_impl!(ServerNoticePacket, buf, self, {
});

decode_unimpl!(ServerNoticePacket);

size_calc_impl!(ServerNoticePacket, MAX_ENCODED_STRING_SIZE);
2 changes: 2 additions & 0 deletions server/game/src/data/types/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ decode_impl!(CryptoPublicKey, buf, {
pubkey: PublicKey::from_bytes(key),
})
});

size_calc_impl!(CryptoPublicKey, KEY_SIZE);
14 changes: 3 additions & 11 deletions server/game/src/data/types/gd.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use globed_shared::SpecialUser;

use crate::bytebufferext::{decode_impl, decode_unimpl, encode_impl, ByteBufferExtWrite};
use crate::bytebufferext::*;

use super::Color3B;

Expand Down Expand Up @@ -148,11 +148,7 @@ encode_impl!(PlayerData, _buf, self, {});

decode_impl!(PlayerData, _buf, Ok(Self {}));

impl PlayerData {
const fn encoded_size() -> usize {
0
}
}
size_calc_impl!(PlayerData, 0);

/* AssociatedPlayerData */

Expand All @@ -167,8 +163,4 @@ encode_impl!(AssociatedPlayerData, buf, self, {
buf.write_value(&self.data);
});

impl AssociatedPlayerData {
pub const fn encoded_size() -> usize {
std::mem::size_of::<i32>() + PlayerData::encoded_size()
}
}
size_calc_impl!(AssociatedPlayerData, size_of_types!(i32) + PlayerData::ENCODED_SIZE);
15 changes: 15 additions & 0 deletions server/game/src/managers/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,26 @@ impl PlayerManager {
self.levels.get(&level_id)
}

pub fn get_player_count_on_level(&self, level_id: i32) -> Option<usize> {
self.levels.get(&level_id).map(FxHashSet::len)
}

pub fn get_players_on_level(&self, level_id: i32) -> Option<Vec<&AssociatedPlayerData>> {
let ids = self.levels.get(&level_id)?;
Some(ids.iter().filter_map(|&key| self.players.get(&key)).collect())
}

pub fn for_each_player_on_level<F, A>(&self, level_id: i32, f: F, additional: &mut A)
where
F: Fn(&AssociatedPlayerData, &mut A),
{
if let Some(ids) = self.levels.get(&level_id) {
ids.iter().filter_map(|&key| self.players.get(&key)).for_each(|data| {
f(data, additional);
});
}
}

pub fn add_to_level(&mut self, level_id: i32, account_id: i32) {
let players = self.levels.entry(level_id).or_default();
players.insert(account_id);
Expand Down
10 changes: 6 additions & 4 deletions server/game/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ impl GameServer {
});
}

// we preallocate a buffer to avoid zeroing out MAX_PACKET_SIZE bytes on each packet
let mut buf = [0u8; MAX_PACKET_SIZE];

loop {
match self.recv_and_handle().await {
match self.recv_and_handle(&mut buf).await {
Ok(()) => {}
Err(err) => {
warn!("Failed to handle a packet: {err}");
Expand Down Expand Up @@ -145,9 +148,8 @@ impl GameServer {

/* private handling stuff */

async fn recv_and_handle(&'static self) -> anyhow::Result<()> {
let mut buf = [0u8; MAX_PACKET_SIZE];
let (len, peer) = self.socket.recv_from(&mut buf).await?;
async fn recv_and_handle(&'static self, buf: &mut [u8]) -> anyhow::Result<()> {
let (len, peer) = self.socket.recv_from(buf).await?;

let peer = match peer {
SocketAddr::V6(_) => return Err(anyhow!("rejecting request from ipv6 host")),
Expand Down
Loading

0 comments on commit e27fe28

Please sign in to comment.