1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-23 15:47:45 +00:00
kawari/src/world/connection.rs
Joshua Goins 0900d0b94e Implement basic character persistence, World <-> Lobby server communication
This is unfortunately lumped into one big commit, and is very hacky and WIP but
does indeed work! Since the Lobby and World server are two separate servers, it
uses it's own custom IPC packets (reusing the same packet structures as regular
game ones.)

The characters you create in the Lobby server are now saved in the World server,
but this is not yet reflected in the Lobby screen.
2025-03-21 19:56:16 -04:00

170 lines
5 KiB
Rust

use tokio::net::TcpStream;
use crate::{
common::timestamp_secs,
packet::{
CompressionType, ConnectionType, PacketSegment, PacketState, SegmentType, parse_packet,
send_packet,
},
};
use super::{
Zone,
ipc::{
ActorSetPos, ClientZoneIpcSegment, InitZone, Position, ServerZoneIpcData,
ServerZoneIpcSegment, ServerZoneIpcType, UpdateClassInfo, WeatherChange,
},
};
#[derive(Debug, Default)]
pub struct PlayerData {
pub actor_id: u32,
pub content_id: u64,
pub account_id: u32,
}
/// Represents a single connection between an instance of the client and the world server
pub struct ZoneConnection {
pub socket: TcpStream,
pub state: PacketState,
pub player_data: PlayerData,
pub zone: Zone,
pub spawn_index: u8,
}
impl ZoneConnection {
pub async fn parse_packet(
&mut self,
data: &[u8],
) -> (Vec<PacketSegment<ClientZoneIpcSegment>>, ConnectionType) {
parse_packet(data, &mut self.state).await
}
pub async fn send_segment(&mut self, segment: PacketSegment<ServerZoneIpcSegment>) {
send_packet(
&mut self.socket,
&mut self.state,
ConnectionType::Zone,
CompressionType::Oodle,
&[segment],
)
.await;
}
pub async fn set_player_position(&mut self, position: Position) {
// set pos
{
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::ActorSetPos,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::ActorSetPos(ActorSetPos {
unk: 0x020fa3b8,
position,
..Default::default()
}),
..Default::default()
};
self.send_segment(PacketSegment {
source_actor: self.player_data.actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
}
pub async fn change_zone(&mut self, new_zone_id: u16) {
self.zone = Zone::load(new_zone_id);
// Player Class Info
{
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::UpdateClassInfo,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::UpdateClassInfo(UpdateClassInfo {
class_id: 35,
unknown: 1,
synced_level: 90,
class_level: 90,
..Default::default()
}),
..Default::default()
};
self.send_segment(PacketSegment {
source_actor: self.player_data.actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
// link shell information
{
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::LinkShellInformation,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::LinkShellInformation { unk: [0; 456] },
..Default::default()
};
self.send_segment(PacketSegment {
source_actor: self.player_data.actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
// TODO: send unk16?
// Init Zone
{
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::InitZone,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::InitZone(InitZone {
server_id: 0,
zone_id: self.zone.id,
weather_id: 1,
..Default::default()
}),
..Default::default()
};
self.send_segment(PacketSegment {
source_actor: self.player_data.actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
}
pub async fn change_weather(&mut self, new_weather_id: u16) {
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::WeatherChange,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::WeatherChange(WeatherChange {
weather_id: new_weather_id,
transistion_time: 1.0,
}),
..Default::default()
};
self.send_segment(PacketSegment {
source_actor: self.player_data.actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
pub fn get_free_spawn_index(&mut self) -> u8 {
self.spawn_index += 1;
self.spawn_index
}
}