mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-20 14:47:45 +00:00
Multiple fixes attempting to fix packet errors
It doesn't unfortunately, there's still a bunch of errors when decoding packets. These are all decent fixes though.
This commit is contained in:
parent
b01ec22950
commit
eae962cc85
10 changed files with 106 additions and 47 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
use kawari::RECEIVE_BUFFER_SIZE;
|
||||||
use kawari::common::GameData;
|
use kawari::common::GameData;
|
||||||
use kawari::common::custom_ipc::CustomIpcData;
|
use kawari::common::custom_ipc::CustomIpcData;
|
||||||
use kawari::common::custom_ipc::CustomIpcSegment;
|
use kawari::common::custom_ipc::CustomIpcSegment;
|
||||||
|
@ -45,7 +46,7 @@ async fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut buf = [0; 2056];
|
let mut buf = vec![0; RECEIVE_BUFFER_SIZE];
|
||||||
loop {
|
loop {
|
||||||
let n = connection
|
let n = connection
|
||||||
.socket
|
.socket
|
||||||
|
@ -54,8 +55,6 @@ async fn main() {
|
||||||
.expect("Failed to read data!");
|
.expect("Failed to read data!");
|
||||||
|
|
||||||
if n != 0 {
|
if n != 0 {
|
||||||
tracing::info!("read {} bytes", n);
|
|
||||||
|
|
||||||
let (segments, _) = connection.parse_packet(&buf[..n]).await;
|
let (segments, _) = connection.parse_packet(&buf[..n]).await;
|
||||||
for segment in &segments {
|
for segment in &segments {
|
||||||
match &segment.segment_type {
|
match &segment.segment_type {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use kawari::RECEIVE_BUFFER_SIZE;
|
||||||
use kawari::common::custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType};
|
use kawari::common::custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType};
|
||||||
use kawari::common::{GameData, ObjectId, timestamp_secs};
|
use kawari::common::{GameData, ObjectId, timestamp_secs};
|
||||||
use kawari::common::{Position, determine_initial_starting_zone};
|
use kawari::common::{Position, determine_initial_starting_zone};
|
||||||
|
@ -28,6 +29,7 @@ use kawari::world::{
|
||||||
SocialList,
|
SocialList,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use mlua::{Function, Lua};
|
use mlua::{Function, Lua};
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
use tokio::join;
|
use tokio::join;
|
||||||
|
@ -162,18 +164,17 @@ pub fn spawn_client(info: ZoneConnection) {
|
||||||
id: *id,
|
id: *id,
|
||||||
ip: *ip,
|
ip: *ip,
|
||||||
channel: send,
|
channel: send,
|
||||||
kill,
|
//kill,
|
||||||
};
|
};
|
||||||
let _ = my_send.send(handle);
|
let _ = my_send.send(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_client(my_handle: oneshot::Receiver<ClientHandle>, mut data: ClientData) {
|
async fn start_client(my_handle: oneshot::Receiver<ClientHandle>, data: ClientData) {
|
||||||
// Recieve client information from global
|
// Recieve client information from global
|
||||||
let my_handle = match my_handle.await {
|
let my_handle = match my_handle.await {
|
||||||
Ok(my_handle) => my_handle,
|
Ok(my_handle) => my_handle,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
data.handle.send(ToServer::NewClient(my_handle)).await;
|
|
||||||
|
|
||||||
let connection = data.connection;
|
let connection = data.connection;
|
||||||
let recv = data.recv;
|
let recv = data.recv;
|
||||||
|
@ -182,7 +183,7 @@ async fn start_client(my_handle: oneshot::Receiver<ClientHandle>, mut data: Clie
|
||||||
let (internal_send, internal_recv) = unbounded_channel();
|
let (internal_send, internal_recv) = unbounded_channel();
|
||||||
|
|
||||||
join! {
|
join! {
|
||||||
client_loop(connection, internal_recv),
|
client_loop(connection, internal_recv, my_handle),
|
||||||
client_server_loop(recv, internal_send)
|
client_server_loop(recv, internal_send)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -202,6 +203,7 @@ async fn client_server_loop(
|
||||||
async fn client_loop(
|
async fn client_loop(
|
||||||
mut connection: ZoneConnection,
|
mut connection: ZoneConnection,
|
||||||
mut internal_recv: UnboundedReceiver<FromServer>,
|
mut internal_recv: UnboundedReceiver<FromServer>,
|
||||||
|
client_handle: ClientHandle,
|
||||||
) {
|
) {
|
||||||
let database = connection.database.clone();
|
let database = connection.database.clone();
|
||||||
let game_data = connection.gamedata.clone();
|
let game_data = connection.gamedata.clone();
|
||||||
|
@ -213,9 +215,10 @@ async fn client_loop(
|
||||||
|
|
||||||
let mut lua_player = LuaPlayer::default();
|
let mut lua_player = LuaPlayer::default();
|
||||||
|
|
||||||
let mut buf = [0; 4096];
|
let mut buf = vec![0; RECEIVE_BUFFER_SIZE];
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
biased; // client data should always be prioritized
|
||||||
Ok(n) = connection.socket.read(&mut buf) => {
|
Ok(n) = connection.socket.read(&mut buf) => {
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
let (segments, connection_type) = connection.parse_packet(&buf[..n]).await;
|
let (segments, connection_type) = connection.parse_packet(&buf[..n]).await;
|
||||||
|
@ -225,11 +228,21 @@ async fn client_loop(
|
||||||
// for some reason they send a string representation
|
// for some reason they send a string representation
|
||||||
let actor_id = actor_id.parse::<u32>().unwrap();
|
let actor_id = actor_id.parse::<u32>().unwrap();
|
||||||
|
|
||||||
// collect actor data
|
// initialize player data if it doesn't exist'
|
||||||
|
if connection.player_data.actor_id == 0 {
|
||||||
connection.player_data = database.find_player_data(actor_id);
|
connection.player_data = database.find_player_data(actor_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect actor data
|
||||||
connection.initialize(&connection_type, actor_id).await;
|
connection.initialize(&connection_type, actor_id).await;
|
||||||
|
|
||||||
|
if connection_type == ConnectionType::Zone {
|
||||||
exit_position = Some(connection.player_data.position);
|
exit_position = Some(connection.player_data.position);
|
||||||
exit_rotation = Some(connection.player_data.rotation);
|
exit_rotation = Some(connection.player_data.rotation);
|
||||||
|
|
||||||
|
// tell the server we exist, now that we confirmed we are a legitimate connection
|
||||||
|
connection.handle.send(ToServer::NewClient(client_handle.clone())).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SegmentType::Ipc { data } => {
|
SegmentType::Ipc { data } => {
|
||||||
match &data.data {
|
match &data.data {
|
||||||
|
@ -1040,14 +1053,17 @@ async fn client_loop(
|
||||||
lua_player.status_effects = connection.status_effects.clone();
|
lua_player.status_effects = connection.status_effects.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg = internal_recv.recv() => match msg {
|
/*msg = internal_recv.recv() => match msg {
|
||||||
Some(msg) => match msg {
|
Some(msg) => match msg {
|
||||||
FromServer::Message(msg)=>connection.send_message(&msg).await,
|
FromServer::Message(msg)=>connection.send_message(&msg).await,
|
||||||
FromServer::ActorSpawn(actor) => connection.spawn_actor(actor).await,
|
FromServer::ActorSpawn(actor) => {
|
||||||
|
tracing::info!("connection {:?} is recieving an actorspawn!", connection.id);
|
||||||
|
connection.spawn_actor(actor).await
|
||||||
|
},
|
||||||
FromServer::ActorMove(actor_id, position) => connection.set_actor_position(actor_id, position).await,
|
FromServer::ActorMove(actor_id, position) => connection.set_actor_position(actor_id, position).await,
|
||||||
},
|
},
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ impl ReadWriteIpcSegment for CustomIpcSegment {
|
||||||
CustomIpcType::CheckNameIsAvailable => CHAR_NAME_MAX_LENGTH as u32,
|
CustomIpcType::CheckNameIsAvailable => CHAR_NAME_MAX_LENGTH as u32,
|
||||||
CustomIpcType::NameIsAvailableResponse => 1,
|
CustomIpcType::NameIsAvailableResponse => 1,
|
||||||
CustomIpcType::RequestCharacterList => 4,
|
CustomIpcType::RequestCharacterList => 4,
|
||||||
CustomIpcType::RequestCharacterListRepsonse => 1184 * 8,
|
CustomIpcType::RequestCharacterListRepsonse => 1 + (1184 * 8),
|
||||||
CustomIpcType::DeleteCharacter => 4,
|
CustomIpcType::DeleteCharacter => 4,
|
||||||
CustomIpcType::CharacterDeleted => 1,
|
CustomIpcType::CharacterDeleted => 1,
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,7 @@ pub enum CustomIpcData {
|
||||||
#[bw(calc = characters.len() as u8)]
|
#[bw(calc = characters.len() as u8)]
|
||||||
num_characters: u8,
|
num_characters: u8,
|
||||||
#[br(count = num_characters)]
|
#[br(count = num_characters)]
|
||||||
|
#[brw(pad_size_to = 1184 * 8)]
|
||||||
characters: Vec<CharacterDetails>, // TODO: maybe chunk this into 4 parts ala the lobby server?
|
characters: Vec<CharacterDetails>, // TODO: maybe chunk this into 4 parts ala the lobby server?
|
||||||
},
|
},
|
||||||
#[br(pre_assert(*magic == CustomIpcType::DeleteCharacter))]
|
#[br(pre_assert(*magic == CustomIpcType::DeleteCharacter))]
|
||||||
|
|
|
@ -7,6 +7,12 @@ pub struct GameData {
|
||||||
pub game_data: physis::gamedata::GameData,
|
pub game_data: physis::gamedata::GameData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for GameData {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GameData {
|
impl GameData {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let config = get_config();
|
let config = get_config();
|
||||||
|
|
|
@ -82,7 +82,7 @@ pub(crate) fn read_packed_float(packed: u16) -> f32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_packed_float(float: f32) -> u16 {
|
pub(crate) fn write_packed_float(float: f32) -> u16 {
|
||||||
(((float + 1000.0) * 100.0) * 0.32767501) as u16
|
(((float + 1000.0) * 100.0) * 0.327_675) as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_packed_position(packed: [u16; 3]) -> Position {
|
pub(crate) fn read_packed_position(packed: [u16; 3]) -> Position {
|
||||||
|
|
|
@ -40,6 +40,8 @@ pub mod opcodes;
|
||||||
/// Used in the encryption key.
|
/// Used in the encryption key.
|
||||||
const GAME_VERSION: u16 = 7000;
|
const GAME_VERSION: u16 = 7000;
|
||||||
|
|
||||||
|
pub const RECEIVE_BUFFER_SIZE: usize = 32000;
|
||||||
|
|
||||||
/// Supported boot version.
|
/// Supported boot version.
|
||||||
pub const SUPPORTED_BOOT_VERSION: Version = Version("2025.01.10.0000.0001");
|
pub const SUPPORTED_BOOT_VERSION: Version = Version("2025.01.10.0000.0001");
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::cmp::min;
|
||||||
use tokio::{io::AsyncReadExt, net::TcpStream};
|
use tokio::{io::AsyncReadExt, net::TcpStream};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
RECEIVE_BUFFER_SIZE,
|
||||||
blowfish::Blowfish,
|
blowfish::Blowfish,
|
||||||
common::{
|
common::{
|
||||||
custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType},
|
custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType},
|
||||||
|
@ -589,11 +590,9 @@ pub async fn send_custom_world_packet(segment: CustomIpcSegment) -> Option<Custo
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
let mut buf = [0; 10024]; // TODO: this large buffer is just working around these packets not being compressed, but they really should be!
|
let mut buf = vec![0; RECEIVE_BUFFER_SIZE];
|
||||||
let n = stream.read(&mut buf).await.expect("Failed to read data!");
|
let n = stream.read(&mut buf).await.expect("Failed to read data!");
|
||||||
if n != 0 {
|
if n != 0 {
|
||||||
println!("Got {n} bytes of response!");
|
|
||||||
|
|
||||||
let (segments, _) = parse_packet::<CustomIpcSegment>(&buf[..n], &mut packet_state).await;
|
let (segments, _) = parse_packet::<CustomIpcSegment>(&buf[..n], &mut packet_state).await;
|
||||||
|
|
||||||
return match &segments[0].segment_type {
|
return match &segments[0].segment_type {
|
||||||
|
|
15
src/oodle.rs
15
src/oodle.rs
|
@ -105,6 +105,7 @@ pub struct OodleNetwork {
|
||||||
|
|
||||||
const HT_BITS: i32 = 0x11;
|
const HT_BITS: i32 = 0x11;
|
||||||
const WINDOW_SIZE: usize = 0x100000;
|
const WINDOW_SIZE: usize = 0x100000;
|
||||||
|
const OODLENETWORK1_DECOMP_BUF_OVERREAD_LEN: usize = 5;
|
||||||
|
|
||||||
impl OodleNetwork {
|
impl OodleNetwork {
|
||||||
pub fn new() -> OodleNetwork {
|
pub fn new() -> OodleNetwork {
|
||||||
|
@ -137,13 +138,19 @@ impl OodleNetwork {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(&mut self, mut input: Vec<u8>, decompressed_size: u32) -> Vec<u8> {
|
pub fn decode(&mut self, input: Vec<u8>, decompressed_size: u32) -> Vec<u8> {
|
||||||
|
let mut padded_buffer = input.clone();
|
||||||
|
padded_buffer.resize(
|
||||||
|
padded_buffer.len() + OODLENETWORK1_DECOMP_BUF_OVERREAD_LEN,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut out_buf: Vec<u8> = vec![0u8; decompressed_size.try_into().unwrap()];
|
let mut out_buf: Vec<u8> = vec![0u8; decompressed_size.try_into().unwrap()];
|
||||||
let success = OodleNetwork1TCP_Decode(
|
let success = OodleNetwork1TCP_Decode(
|
||||||
self.state.as_mut_ptr() as *mut c_void,
|
self.state.as_mut_ptr() as *mut c_void,
|
||||||
self.shared.as_mut_ptr() as *mut c_void,
|
self.shared.as_mut_ptr() as *const c_void,
|
||||||
input.as_mut_ptr() as *const c_void,
|
padded_buffer.as_mut_ptr() as *const c_void,
|
||||||
input.len().try_into().unwrap(),
|
input.len().try_into().unwrap(),
|
||||||
out_buf.as_mut_ptr() as *mut c_void,
|
out_buf.as_mut_ptr() as *mut c_void,
|
||||||
out_buf.len().try_into().unwrap(),
|
out_buf.len().try_into().unwrap(),
|
||||||
|
@ -162,7 +169,7 @@ impl OodleNetwork {
|
||||||
let mut out_buf: Vec<u8> = vec![0u8; input.len()];
|
let mut out_buf: Vec<u8> = vec![0u8; input.len()];
|
||||||
let len = OodleNetwork1TCP_Encode(
|
let len = OodleNetwork1TCP_Encode(
|
||||||
self.state.as_mut_ptr() as *mut c_void,
|
self.state.as_mut_ptr() as *mut c_void,
|
||||||
self.shared.as_mut_ptr() as *mut c_void,
|
self.shared.as_mut_ptr() as *const c_void,
|
||||||
input.as_mut_ptr() as *const c_void,
|
input.as_mut_ptr() as *const c_void,
|
||||||
input.len().try_into().unwrap(),
|
input.len().try_into().unwrap(),
|
||||||
out_buf.as_mut_ptr() as *mut c_void,
|
out_buf.as_mut_ptr() as *mut c_void,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use tokio::{net::TcpStream, sync::mpsc::Sender, task::JoinHandle};
|
use tokio::{net::TcpStream, sync::mpsc::Sender};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{GameData, ObjectId, Position, timestamp_secs},
|
common::{GameData, ObjectId, Position, timestamp_secs},
|
||||||
|
@ -61,12 +61,13 @@ pub enum FromServer {
|
||||||
ActorMove(u32, Position),
|
ActorMove(u32, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ClientHandle {
|
pub struct ClientHandle {
|
||||||
pub id: ClientId,
|
pub id: ClientId,
|
||||||
pub ip: SocketAddr,
|
pub ip: SocketAddr,
|
||||||
pub channel: Sender<FromServer>,
|
pub channel: Sender<FromServer>,
|
||||||
pub kill: JoinHandle<()>,
|
// TODO: restore, i guess
|
||||||
|
//pub kill: JoinHandle<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientHandle {
|
impl ClientHandle {
|
||||||
|
@ -161,6 +162,17 @@ impl ZoneConnection {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_chat_segment(&mut self, segment: PacketSegment<ServerZoneIpcSegment>) {
|
||||||
|
send_packet(
|
||||||
|
&mut self.socket,
|
||||||
|
&mut self.state,
|
||||||
|
ConnectionType::Chat,
|
||||||
|
CompressionType::Oodle,
|
||||||
|
&[segment],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn initialize(&mut self, connection_type: &ConnectionType, actor_id: u32) {
|
pub async fn initialize(&mut self, connection_type: &ConnectionType, actor_id: u32) {
|
||||||
// some still hardcoded values
|
// some still hardcoded values
|
||||||
self.player_data.classjob_id = 1;
|
self.player_data.classjob_id = 1;
|
||||||
|
@ -170,6 +182,10 @@ impl ZoneConnection {
|
||||||
self.player_data.curr_mp = 10000;
|
self.player_data.curr_mp = 10000;
|
||||||
self.player_data.max_mp = 10000;
|
self.player_data.max_mp = 10000;
|
||||||
|
|
||||||
|
match connection_type {
|
||||||
|
ConnectionType::Zone => {
|
||||||
|
tracing::info!("Client {actor_id} is initializing zone session...");
|
||||||
|
|
||||||
// We have send THEM a keep alive
|
// We have send THEM a keep alive
|
||||||
{
|
{
|
||||||
self.send_segment(PacketSegment {
|
self.send_segment(PacketSegment {
|
||||||
|
@ -183,10 +199,6 @@ impl ZoneConnection {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
match connection_type {
|
|
||||||
ConnectionType::Zone => {
|
|
||||||
tracing::info!("Client {actor_id} is initializing zone session...");
|
|
||||||
|
|
||||||
self.send_segment(PacketSegment {
|
self.send_segment(PacketSegment {
|
||||||
source_actor: 0,
|
source_actor: 0,
|
||||||
target_actor: 0,
|
target_actor: 0,
|
||||||
|
@ -200,8 +212,21 @@ impl ZoneConnection {
|
||||||
ConnectionType::Chat => {
|
ConnectionType::Chat => {
|
||||||
tracing::info!("Client {actor_id} is initializing chat session...");
|
tracing::info!("Client {actor_id} is initializing chat session...");
|
||||||
|
|
||||||
|
// We have send THEM a keep alive
|
||||||
{
|
{
|
||||||
self.send_segment(PacketSegment {
|
self.send_chat_segment(PacketSegment {
|
||||||
|
source_actor: 0,
|
||||||
|
target_actor: 0,
|
||||||
|
segment_type: SegmentType::KeepAlive {
|
||||||
|
id: 0xE0037603u32,
|
||||||
|
timestamp: timestamp_secs(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
self.send_chat_segment(PacketSegment {
|
||||||
source_actor: 0,
|
source_actor: 0,
|
||||||
target_actor: 0,
|
target_actor: 0,
|
||||||
segment_type: SegmentType::ZoneInitialize {
|
segment_type: SegmentType::ZoneInitialize {
|
||||||
|
@ -212,6 +237,9 @@ impl ZoneConnection {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we need the actor id at this point!
|
||||||
|
assert!(self.player_data.actor_id != 0);
|
||||||
|
|
||||||
{
|
{
|
||||||
let ipc = ServerZoneIpcSegment {
|
let ipc = ServerZoneIpcSegment {
|
||||||
op_code: ServerZoneIpcType::InitializeChat,
|
op_code: ServerZoneIpcType::InitializeChat,
|
||||||
|
@ -220,7 +248,7 @@ impl ZoneConnection {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.send_segment(PacketSegment {
|
self.send_chat_segment(PacketSegment {
|
||||||
source_actor: self.player_data.actor_id,
|
source_actor: self.player_data.actor_id,
|
||||||
target_actor: self.player_data.actor_id,
|
target_actor: self.player_data.actor_id,
|
||||||
segment_type: SegmentType::Ipc { data: ipc },
|
segment_type: SegmentType::Ipc { data: ipc },
|
||||||
|
@ -276,6 +304,9 @@ impl ZoneConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn spawn_actor(&mut self, actor: Actor) {
|
pub async fn spawn_actor(&mut self, actor: Actor) {
|
||||||
|
// There is no reason for us to spawn our own player again. It's probably a bug!'
|
||||||
|
assert!(actor.id.0 != self.player_data.actor_id);
|
||||||
|
|
||||||
let ipc = ServerZoneIpcSegment {
|
let ipc = ServerZoneIpcSegment {
|
||||||
unk1: 20,
|
unk1: 20,
|
||||||
unk2: 0,
|
unk2: 0,
|
||||||
|
@ -351,7 +382,7 @@ impl ZoneConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
// link shell information
|
// link shell information
|
||||||
{
|
/*{
|
||||||
let ipc = ServerZoneIpcSegment {
|
let ipc = ServerZoneIpcSegment {
|
||||||
op_code: ServerZoneIpcType::LinkShellInformation,
|
op_code: ServerZoneIpcType::LinkShellInformation,
|
||||||
timestamp: timestamp_secs(),
|
timestamp: timestamp_secs(),
|
||||||
|
@ -365,7 +396,7 @@ impl ZoneConnection {
|
||||||
segment_type: SegmentType::Ipc { data: ipc },
|
segment_type: SegmentType::Ipc { data: ipc },
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// TODO: send unk16?
|
// TODO: send unk16?
|
||||||
|
|
||||||
|
@ -573,7 +604,7 @@ impl ZoneConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn actor_control_self(&mut self, actor_control: ActorControlSelf) {
|
pub async fn actor_control_self(&mut self, actor_control: ActorControlSelf) {
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use physis::{
|
use physis::{
|
||||||
common::{Language, Platform},
|
common::Language,
|
||||||
gamedata::GameData,
|
gamedata::GameData,
|
||||||
layer::{
|
layer::{
|
||||||
ExitRangeInstanceObject, InstanceObject, LayerEntryData, LayerGroup, PopRangeInstanceObject,
|
ExitRangeInstanceObject, InstanceObject, LayerEntryData, LayerGroup, PopRangeInstanceObject,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::config::get_config;
|
|
||||||
|
|
||||||
/// Represents a loaded zone
|
/// Represents a loaded zone
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Zone {
|
pub struct Zone {
|
||||||
|
|
Loading…
Add table
Reference in a new issue