|
@ -1,4 +1,6 @@ |
|
|
use std::net;
|
|
|
use std::net;
|
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
use std::io::Read;
|
|
|
|
|
|
|
|
|
use rand::{Rng, RngCore};
|
|
|
use rand::{Rng, RngCore};
|
|
|
use bcrypt::{DEFAULT_COST, hash, verify};
|
|
|
use bcrypt::{DEFAULT_COST, hash, verify};
|
|
@ -16,6 +18,7 @@ use elseware::common::network::{PacketNetworkError}; |
|
|
use elseware::common::client::Client;
|
|
|
use elseware::common::client::Client;
|
|
|
use elseware::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
|
|
|
use elseware::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
|
|
|
use elseware::common::util::array_to_utf8;
|
|
|
use elseware::common::util::array_to_utf8;
|
|
|
|
|
|
use elseware::utf8_to_array;
|
|
|
|
|
|
|
|
|
use crate::dataaccess::DataAccess;
|
|
|
use crate::dataaccess::DataAccess;
|
|
|
use crate::login::{SharedLoginState, get_login_status};
|
|
|
use crate::login::{SharedLoginState, get_login_status};
|
|
@ -36,6 +39,8 @@ pub enum RecvCharacterPacket { |
|
|
Checksum(Checksum),
|
|
|
Checksum(Checksum),
|
|
|
GuildcardDataRequest(GuildcardDataRequest),
|
|
|
GuildcardDataRequest(GuildcardDataRequest),
|
|
|
GuildcardDataChunkRequest(GuildcardDataChunkRequest),
|
|
|
GuildcardDataChunkRequest(GuildcardDataChunkRequest),
|
|
|
|
|
|
ParamDataRequest(ParamDataRequest),
|
|
|
|
|
|
ParamDataChunkRequest(ParamDataChunkRequest),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
impl RecvServerPacket for RecvCharacterPacket {
|
|
|
impl RecvServerPacket for RecvCharacterPacket {
|
|
@ -47,6 +52,8 @@ impl RecvServerPacket for RecvCharacterPacket { |
|
|
0x1E8 => Ok(RecvCharacterPacket::Checksum(Checksum::from_bytes(data)?)),
|
|
|
0x1E8 => Ok(RecvCharacterPacket::Checksum(Checksum::from_bytes(data)?)),
|
|
|
0x3E8 => Ok(RecvCharacterPacket::GuildcardDataRequest(GuildcardDataRequest::from_bytes(data)?)),
|
|
|
0x3E8 => Ok(RecvCharacterPacket::GuildcardDataRequest(GuildcardDataRequest::from_bytes(data)?)),
|
|
|
0x3DC => Ok(RecvCharacterPacket::GuildcardDataChunkRequest(GuildcardDataChunkRequest::from_bytes(data)?)),
|
|
|
0x3DC => Ok(RecvCharacterPacket::GuildcardDataChunkRequest(GuildcardDataChunkRequest::from_bytes(data)?)),
|
|
|
|
|
|
0x4EB => Ok(RecvCharacterPacket::ParamDataRequest(ParamDataRequest::from_bytes(data)?)),
|
|
|
|
|
|
0x3EB => Ok(RecvCharacterPacket::ParamDataChunkRequest(ParamDataChunkRequest::from_bytes(data)?)),
|
|
|
_ => Err(PacketParseError::WrongPacketForServerType)
|
|
|
_ => Err(PacketParseError::WrongPacketForServerType)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@ -62,7 +69,9 @@ pub enum SendCharacterPacket { |
|
|
ChecksumAck(ChecksumAck),
|
|
|
ChecksumAck(ChecksumAck),
|
|
|
CharacterPreview(CharacterPreview),
|
|
|
CharacterPreview(CharacterPreview),
|
|
|
GuildcardDataHeader(GuildcardDataHeader),
|
|
|
GuildcardDataHeader(GuildcardDataHeader),
|
|
|
GuildcardDataChunk(GuildcardDataChunk)
|
|
|
|
|
|
|
|
|
GuildcardDataChunk(GuildcardDataChunk),
|
|
|
|
|
|
ParamDataHeader(ParamDataHeader),
|
|
|
|
|
|
ParamDataChunk(ParamDataChunk),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
impl SendServerPacket for SendCharacterPacket {
|
|
|
impl SendServerPacket for SendCharacterPacket {
|
|
@ -76,14 +85,52 @@ impl SendServerPacket for SendCharacterPacket { |
|
|
SendCharacterPacket::CharacterPreview(pkt) => pkt.as_bytes(),
|
|
|
SendCharacterPacket::CharacterPreview(pkt) => pkt.as_bytes(),
|
|
|
SendCharacterPacket::GuildcardDataHeader(pkt) => pkt.as_bytes(),
|
|
|
SendCharacterPacket::GuildcardDataHeader(pkt) => pkt.as_bytes(),
|
|
|
SendCharacterPacket::GuildcardDataChunk(pkt) => pkt.as_bytes(),
|
|
|
SendCharacterPacket::GuildcardDataChunk(pkt) => pkt.as_bytes(),
|
|
|
|
|
|
SendCharacterPacket::ParamDataHeader(pkt) => pkt.as_bytes(),
|
|
|
|
|
|
SendCharacterPacket::ParamDataChunk(pkt) => pkt.as_bytes(),
|
|
|
//SendLoginPacket::RedirectClient(pkt) => pkt.as_bytes(),
|
|
|
//SendLoginPacket::RedirectClient(pkt) => pkt.as_bytes(),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn generate_param_data(path: &str) -> (ParamDataHeader, Vec<u8>) {
|
|
|
|
|
|
let paths = std::fs::read_dir(path).expect("could not find param/ directory");
|
|
|
|
|
|
|
|
|
|
|
|
let mut files = Vec::new();
|
|
|
|
|
|
let mut buffer = Vec::new();
|
|
|
|
|
|
for p in paths {
|
|
|
|
|
|
let param = p.unwrap().path();
|
|
|
|
|
|
let mut file = std::fs::File::open(¶m).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
let mut filebuf = Vec::new();
|
|
|
|
|
|
let len = file.read_to_end(&mut filebuf).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
let mut crc = crc32::Digest::new(crc32::IEEE);
|
|
|
|
|
|
crc.write(&filebuf[..]);
|
|
|
|
|
|
|
|
|
|
|
|
files.push(ParamFile {
|
|
|
|
|
|
size: len as u32,
|
|
|
|
|
|
checksum: crc.sum32(),
|
|
|
|
|
|
offset: buffer.len() as u32,
|
|
|
|
|
|
filename: utf8_to_array!(param.file_name().unwrap().to_str().unwrap(), 0x40),
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
buffer.append(&mut filebuf);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
(ParamDataHeader {
|
|
|
|
|
|
files: files
|
|
|
|
|
|
}, buffer)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: rip these client-specific vars into a HashMap<ClientId, ClientState>
|
|
|
pub struct CharacterServerState<DA: DataAccess> {
|
|
|
pub struct CharacterServerState<DA: DataAccess> {
|
|
|
//shared_state: SharedLoginState<DA>,
|
|
|
//shared_state: SharedLoginState<DA>,
|
|
|
data_access: DA,
|
|
|
data_access: DA,
|
|
|
|
|
|
param_header: ParamDataHeader,
|
|
|
|
|
|
|
|
|
|
|
|
param_index: usize,
|
|
|
|
|
|
param_data: Arc<Vec<u8>>,
|
|
|
user: Option<UserAccount>,
|
|
|
user: Option<UserAccount>,
|
|
|
characters: Option<[Option<Character>; 4]>,
|
|
|
characters: Option<[Option<Character>; 4]>,
|
|
|
guildcard_data_buffer: Option<Vec<u8>>,
|
|
|
guildcard_data_buffer: Option<Vec<u8>>,
|
|
@ -92,9 +139,15 @@ pub struct CharacterServerState<DA: DataAccess> { |
|
|
|
|
|
|
|
|
impl<DA: DataAccess> CharacterServerState<DA> {
|
|
|
impl<DA: DataAccess> CharacterServerState<DA> {
|
|
|
pub fn new(data_access: DA) -> CharacterServerState<DA> {
|
|
|
pub fn new(data_access: DA) -> CharacterServerState<DA> {
|
|
|
|
|
|
let (param_header, param_data) = generate_param_data("param/");
|
|
|
|
|
|
|
|
|
CharacterServerState {
|
|
|
CharacterServerState {
|
|
|
//shared_state: shared_state,
|
|
|
//shared_state: shared_state,
|
|
|
data_access: data_access,
|
|
|
data_access: data_access,
|
|
|
|
|
|
param_header: param_header,
|
|
|
|
|
|
|
|
|
|
|
|
param_index: 0,
|
|
|
|
|
|
param_data: Arc::new(param_data),
|
|
|
user: None,
|
|
|
user: None,
|
|
|
characters: None,
|
|
|
characters: None,
|
|
|
guildcard_data_buffer: None,
|
|
|
guildcard_data_buffer: None,
|
|
@ -226,6 +279,27 @@ impl<DA: DataAccess> ServerState for CharacterServerState<DA> { |
|
|
},
|
|
|
},
|
|
|
RecvCharacterPacket::GuildcardDataChunkRequest(request) => {
|
|
|
RecvCharacterPacket::GuildcardDataChunkRequest(request) => {
|
|
|
Box::new(self.guildcard_data_chunk(request.chunk, request.again).into_iter().map(move |pkt| (id, pkt)))
|
|
|
Box::new(self.guildcard_data_chunk(request.chunk, request.again).into_iter().map(move |pkt| (id, pkt)))
|
|
|
|
|
|
},
|
|
|
|
|
|
RecvCharacterPacket::ParamDataRequest(_request) => {
|
|
|
|
|
|
Box::new(vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt)))
|
|
|
|
|
|
},
|
|
|
|
|
|
RecvCharacterPacket::ParamDataChunkRequest(_request) => {
|
|
|
|
|
|
let chunk = self.param_index;
|
|
|
|
|
|
self.param_index += 1;
|
|
|
|
|
|
|
|
|
|
|
|
let start = chunk * 0x6800;
|
|
|
|
|
|
let end = std::cmp::min((chunk+1)*0x6800, self.param_data.len());
|
|
|
|
|
|
|
|
|
|
|
|
let mut data = [0u8; 0x6800];
|
|
|
|
|
|
data[..end-start].copy_from_slice(&self.param_data[start..end]);
|
|
|
|
|
|
|
|
|
|
|
|
Box::new(vec![SendCharacterPacket::ParamDataChunk(
|
|
|
|
|
|
ParamDataChunk {
|
|
|
|
|
|
flag: 0,
|
|
|
|
|
|
chunk: chunk as u32,
|
|
|
|
|
|
data: data,
|
|
|
|
|
|
}
|
|
|
|
|
|
)].into_iter().map(move |pkt| (id, pkt)))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|