mirror of
https://github.com/redstrate/Kawari.git
synced 2025-06-30 11:47:45 +00:00
Allow building for WebAssembly
This really only allows you to access the packet parsing bits, starting the servers isn't possible for a variety of reasons.
This commit is contained in:
parent
05f909497c
commit
7b8177b27b
5 changed files with 100 additions and 78 deletions
45
Cargo.toml
45
Cargo.toml
|
@ -51,27 +51,13 @@ serde = { version = "1.0", features = ["derive"], default-features = false }
|
||||||
serde_json = { version = "1.0", features = ["std"], default-features = false }
|
serde_json = { version = "1.0", features = ["std"], default-features = false }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Used for the web servers
|
|
||||||
axum = { version = "0.8", features = ["json", "tokio", "http1", "form", "query", "multipart"], default-features = false }
|
|
||||||
axum-extra = { version = "0.10", features = ["cookie"], default-features = false }
|
|
||||||
|
|
||||||
# Serialization used in almost every server
|
# Serialization used in almost every server
|
||||||
serde = { version = "1.0", features = ["derive"], default-features = false }
|
serde = { version = "1.0", features = ["derive"], default-features = false }
|
||||||
serde_json = { version = "1.0", default-features = false }
|
serde_json = { version = "1.0", features = ["std"], default-features = false }
|
||||||
serde_yaml_ng = { version = "0.10", default-features = false }
|
serde_yaml_ng = { version = "0.10", default-features = false }
|
||||||
|
|
||||||
# Async runtime
|
|
||||||
tokio = { version = "1.45", features = ["macros", "rt", "rt-multi-thread", "io-util"], default-features = false }
|
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
tracing = { version = "0.1", default-features = false }
|
tracing = { version = "0.1", default-features = false }
|
||||||
tracing-subscriber = { version = "0.3", features = ["fmt"], default-features = false }
|
|
||||||
|
|
||||||
# Used currently for SID generation
|
|
||||||
fastrand = { version = "2.3", features = ["std"], default-features = false }
|
|
||||||
|
|
||||||
# HTML templates used in the web servers
|
|
||||||
minijinja = { version = "2.10", features = ["serde", "loader", "multi_template"], default-features = false }
|
|
||||||
|
|
||||||
# Serialization of packets
|
# Serialization of packets
|
||||||
binrw = { version = "0.15", features = ["std"], default-features = false }
|
binrw = { version = "0.15", features = ["std"], default-features = false }
|
||||||
|
@ -82,12 +68,32 @@ md5 = { version = "0.7", default-features = false }
|
||||||
# Used to access game data
|
# Used to access game data
|
||||||
physis = { git = "https://github.com/redstrate/physis", default-features = false }
|
physis = { git = "https://github.com/redstrate/physis", default-features = false }
|
||||||
|
|
||||||
# Used for data persistence
|
|
||||||
rusqlite = { version = "0.36", features = ["bundled"], default-features = false }
|
|
||||||
|
|
||||||
# needed for c-style bitflags
|
# needed for c-style bitflags
|
||||||
bitflags = { version = "2.9", default-features = false }
|
bitflags = { version = "2.9", default-features = false }
|
||||||
|
|
||||||
|
# excel sheet data
|
||||||
|
icarus = { git = "https://github.com/redstrate/Icarus", branch = "ver/2025.04.16.0000.0000", features = ["Warp", "Tribe", "ClassJob", "World", "TerritoryType", "Race", "Aetheryte", "EquipSlotCategory", "Action", "WeatherRate", "PlaceName"], default-features = false }
|
||||||
|
|
||||||
|
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||||
|
# Used for the web servers
|
||||||
|
axum = { version = "0.8", features = ["json", "tokio", "http1", "form", "query", "multipart"], default-features = false }
|
||||||
|
axum-extra = { version = "0.10", features = ["cookie"], default-features = false }
|
||||||
|
|
||||||
|
# Async runtime
|
||||||
|
tokio = { version = "1.45", features = ["macros", "rt", "rt-multi-thread", "io-util"], default-features = false }
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["fmt"], default-features = false }
|
||||||
|
|
||||||
|
# Used currently for SID generation
|
||||||
|
fastrand = { version = "2.3", features = ["std"], default-features = false }
|
||||||
|
|
||||||
|
# HTML templates used in the web servers
|
||||||
|
minijinja = { version = "2.10", features = ["serde", "loader", "multi_template"], default-features = false }
|
||||||
|
|
||||||
|
# Used for data persistence
|
||||||
|
rusqlite = { version = "0.36", features = ["bundled"], default-features = false }
|
||||||
|
|
||||||
# For server-side scripting
|
# For server-side scripting
|
||||||
mlua = { version = "0.10", features = ["lua54", "vendored", "send", "async", "serialize"], default-features = false }
|
mlua = { version = "0.10", features = ["lua54", "vendored", "send", "async", "serialize"], default-features = false }
|
||||||
|
|
||||||
|
@ -102,6 +108,3 @@ rkon = { version = "0.1" }
|
||||||
|
|
||||||
# For serving static files on the website
|
# For serving static files on the website
|
||||||
tower-http = { version = "0.6", features = ["fs", "cors"] }
|
tower-http = { version = "0.6", features = ["fs", "cors"] }
|
||||||
|
|
||||||
# excel sheet data
|
|
||||||
icarus = { git = "https://github.com/redstrate/Icarus", branch = "ver/2025.04.16.0000.0000", features = ["Warp", "Tribe", "ClassJob", "World", "TerritoryType", "Race", "Aetheryte", "EquipSlotCategory", "Action", "WeatherRate", "PlaceName"], default-features = false }
|
|
||||||
|
|
|
@ -16,15 +16,18 @@ pub mod common;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|
||||||
/// Lobby server-specific code.
|
/// Lobby server-specific code.
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
pub mod lobby;
|
pub mod lobby;
|
||||||
|
|
||||||
/// World server-specific code.
|
/// World server-specific code.
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
|
||||||
/// Everything packet parsing related.
|
/// Everything packet parsing related.
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
|
|
||||||
/// Logic server-specific code.
|
/// Logic server-specific code.
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
pub mod login;
|
pub mod login;
|
||||||
|
|
||||||
/// Patch server-specific code.
|
/// Patch server-specific code.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod parsing;
|
mod parsing;
|
||||||
pub use parsing::{
|
pub use parsing::{
|
||||||
ConnectionType, PacketHeader, PacketSegment, PacketState, SegmentData, SegmentType,
|
ConnectionType, PacketHeader, PacketSegment, PacketState, SegmentData, SegmentType,
|
||||||
parse_packet, send_keep_alive, send_packet,
|
parse_packet,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod compression;
|
mod compression;
|
||||||
|
@ -15,3 +15,9 @@ pub use ipc::{IpcSegment, ReadWriteIpcSegment};
|
||||||
|
|
||||||
/// Bindings for Oodle network compression.
|
/// Bindings for Oodle network compression.
|
||||||
pub mod oodle;
|
pub mod oodle;
|
||||||
|
|
||||||
|
/// Send packet helpers.
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
mod send_helpers;
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub use send_helpers::{send_keep_alive, send_packet};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::{fs::write, io::Cursor};
|
use std::{fs::write, io::Cursor};
|
||||||
|
|
||||||
use binrw::{BinRead, BinWrite, binrw};
|
use binrw::{BinRead, BinWrite, binrw};
|
||||||
use tokio::{io::AsyncWriteExt, net::TcpStream};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{read_string, timestamp_msecs, write_string},
|
common::{read_string, timestamp_msecs, write_string},
|
||||||
|
@ -181,39 +180,6 @@ fn dump(msg: &str, data: &[u8]) {
|
||||||
tracing::warn!("{msg} Dumped to packet.bin.");
|
tracing::warn!("{msg} Dumped to packet.bin.");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_packet<T: ReadWriteIpcSegment>(
|
|
||||||
socket: &mut TcpStream,
|
|
||||||
state: &mut PacketState,
|
|
||||||
connection_type: ConnectionType,
|
|
||||||
compression_type: CompressionType,
|
|
||||||
segments: &[PacketSegment<T>],
|
|
||||||
) {
|
|
||||||
let (data, uncompressed_size) = compress(state, &compression_type, segments);
|
|
||||||
let size = std::mem::size_of::<PacketHeader>() + data.len();
|
|
||||||
|
|
||||||
let header = PacketHeader {
|
|
||||||
prefix: [0; 16],
|
|
||||||
timestamp: timestamp_msecs(),
|
|
||||||
size: size as u32,
|
|
||||||
connection_type,
|
|
||||||
segment_count: segments.len() as u16,
|
|
||||||
version: 0,
|
|
||||||
compression_type,
|
|
||||||
unk4: 0,
|
|
||||||
uncompressed_size: uncompressed_size as u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut cursor = Cursor::new(Vec::new());
|
|
||||||
header.write_le(&mut cursor).unwrap();
|
|
||||||
std::io::Write::write_all(&mut cursor, &data).unwrap();
|
|
||||||
|
|
||||||
let buffer = cursor.into_inner();
|
|
||||||
|
|
||||||
if let Err(e) = socket.write_all(&buffer).await {
|
|
||||||
tracing::warn!("Failed to send packet: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// temporary
|
// temporary
|
||||||
/// State needed for each connection between the client & server, containing various things like the compressor and encryption keys.
|
/// State needed for each connection between the client & server, containing various things like the compressor and encryption keys.
|
||||||
pub struct PacketState {
|
pub struct PacketState {
|
||||||
|
@ -249,28 +215,6 @@ pub fn parse_packet<T: ReadWriteIpcSegment>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_keep_alive<T: ReadWriteIpcSegment>(
|
|
||||||
socket: &mut TcpStream,
|
|
||||||
state: &mut PacketState,
|
|
||||||
connection_type: ConnectionType,
|
|
||||||
id: u32,
|
|
||||||
timestamp: u32,
|
|
||||||
) {
|
|
||||||
let response_packet: PacketSegment<T> = PacketSegment {
|
|
||||||
segment_type: SegmentType::KeepAliveResponse,
|
|
||||||
data: SegmentData::KeepAliveResponse { id, timestamp },
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
send_packet(
|
|
||||||
socket,
|
|
||||||
state,
|
|
||||||
connection_type,
|
|
||||||
CompressionType::Uncompressed,
|
|
||||||
&[response_packet],
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::packet::IpcSegment;
|
use crate::packet::IpcSegment;
|
||||||
|
|
66
src/packet/send_helpers.rs
Normal file
66
src/packet/send_helpers.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use binrw::BinWrite;
|
||||||
|
use tokio::{io::AsyncWriteExt, net::TcpStream};
|
||||||
|
|
||||||
|
use crate::common::timestamp_msecs;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
CompressionType, ConnectionType, PacketHeader, PacketSegment, PacketState, ReadWriteIpcSegment,
|
||||||
|
SegmentData, SegmentType, compression::compress,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn send_packet<T: ReadWriteIpcSegment>(
|
||||||
|
socket: &mut TcpStream,
|
||||||
|
state: &mut PacketState,
|
||||||
|
connection_type: ConnectionType,
|
||||||
|
compression_type: CompressionType,
|
||||||
|
segments: &[PacketSegment<T>],
|
||||||
|
) {
|
||||||
|
let (data, uncompressed_size) = compress(state, &compression_type, segments);
|
||||||
|
let size = std::mem::size_of::<PacketHeader>() + data.len();
|
||||||
|
|
||||||
|
let header = PacketHeader {
|
||||||
|
prefix: [0; 16],
|
||||||
|
timestamp: timestamp_msecs(),
|
||||||
|
size: size as u32,
|
||||||
|
connection_type,
|
||||||
|
segment_count: segments.len() as u16,
|
||||||
|
version: 0,
|
||||||
|
compression_type,
|
||||||
|
unk4: 0,
|
||||||
|
uncompressed_size: uncompressed_size as u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cursor = Cursor::new(Vec::new());
|
||||||
|
header.write_le(&mut cursor).unwrap();
|
||||||
|
std::io::Write::write_all(&mut cursor, &data).unwrap();
|
||||||
|
|
||||||
|
let buffer = cursor.into_inner();
|
||||||
|
|
||||||
|
if let Err(e) = socket.write_all(&buffer).await {
|
||||||
|
tracing::warn!("Failed to send packet: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_keep_alive<T: ReadWriteIpcSegment>(
|
||||||
|
socket: &mut TcpStream,
|
||||||
|
state: &mut PacketState,
|
||||||
|
connection_type: ConnectionType,
|
||||||
|
id: u32,
|
||||||
|
timestamp: u32,
|
||||||
|
) {
|
||||||
|
let response_packet: PacketSegment<T> = PacketSegment {
|
||||||
|
segment_type: SegmentType::KeepAliveResponse,
|
||||||
|
data: SegmentData::KeepAliveResponse { id, timestamp },
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
send_packet(
|
||||||
|
socket,
|
||||||
|
state,
|
||||||
|
connection_type,
|
||||||
|
CompressionType::Uncompressed,
|
||||||
|
&[response_packet],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue