Merge pull request 'the clip has spoken' (#42) from clippylint into master
All checks were successful
continuous-integration/drone/push Build is passing

Reviewed-on: #42
This commit is contained in:
jake 2021-06-19 02:48:24 -04:00
commit 4c7fa97c5b
72 changed files with 903 additions and 939 deletions

View File

@ -7,7 +7,7 @@ concurrency:
limit: 1 limit: 1
steps: steps:
- name: cargo build - name: build
image: rustlang/rust:nightly image: rustlang/rust:nightly
volumes: volumes:
- name: cache - name: cache
@ -16,7 +16,16 @@ steps:
path: /drone/src/target path: /drone/src/target
commands: commands:
- cargo build - cargo build
- name: cargo test - name: clippy!
image: rustlang/rust:nightly
volumes:
- name: cache
path: /usr/local/cargo
- name: target-cache
path: /drone/src/target
commands:
- cargo clippy -- --deny warnings
- name: test
image: rustlang/rust:nightly image: rustlang/rust:nightly
volumes: volumes:
- name: cache - name: cache

View File

@ -41,7 +41,7 @@ fn main() {
let login_state = LoginServerState::new(thread_entity_gateway, charserv_ip); let login_state = LoginServerState::new(thread_entity_gateway, charserv_ip);
let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT); let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT);
let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token.into())); let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token));
let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT, elseware::login::login::COMMUNICATION_PORT); let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT, elseware::login::login::COMMUNICATION_PORT);
info!("[auth/character] starting server"); info!("[auth/character] starting server");

View File

@ -6,6 +6,7 @@ use elseware::login::login::LoginServerState;
use elseware::login::character::CharacterServerState; use elseware::login::character::CharacterServerState;
use elseware::ship::ship::ShipServerStateBuilder; use elseware::ship::ship::ShipServerStateBuilder;
use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity};
#[allow(unused_imports)]
use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway};
use elseware::entity::character::NewCharacterEntity; use elseware::entity::character::NewCharacterEntity;
use elseware::entity::item::{NewItemEntity, ItemDetail, ItemLocation}; use elseware::entity::item::{NewItemEntity, ItemDetail, ItemLocation};
@ -48,7 +49,7 @@ fn main() {
setup_logger(); setup_logger();
async_std::task::block_on(async move { async_std::task::block_on(async move {
//let mut entity_gateway = PostgresGateway::new("localhost", "elsewhere", "elsewhere", ""); //let mut entity_gateway = PostgresGateway::new("localhost", "elsewhere", "elsewhere", "");
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
for i in 0..5 { for i in 0..5 {
let fake_user = NewUserAccountEntity { let fake_user = NewUserAccountEntity {
@ -383,7 +384,7 @@ fn main() {
let thread_entity_gateway = entity_gateway.clone(); let thread_entity_gateway = entity_gateway.clone();
info!("[ship] starting server"); info!("[ship] starting server");
let ship_state = Box::new(ShipServerStateBuilder::new() let ship_state = Box::new(ShipServerStateBuilder::default()
.name("US/Sona-Nyl".into()) .name("US/Sona-Nyl".into())
.ip(Ipv4Addr::new(127,0,0,1)) .ip(Ipv4Addr::new(127,0,0,1))
.port(elseware::ship::ship::SHIP_PORT) .port(elseware::ship::ship::SHIP_PORT)
@ -392,7 +393,7 @@ fn main() {
let ship_loop = ship_mainloop(*ship_state, elseware::ship::ship::SHIP_PORT, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT); let ship_loop = ship_mainloop(*ship_state, elseware::ship::ship::SHIP_PORT, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT);
let thread_entity_gateway = entity_gateway.clone(); let thread_entity_gateway = entity_gateway.clone();
let ship_state = Box::new(ShipServerStateBuilder::new() let ship_state = Box::new(ShipServerStateBuilder::default()
.name("EU/Dylath-Leen".into()) .name("EU/Dylath-Leen".into())
.ip(Ipv4Addr::new(127,0,0,1)) .ip(Ipv4Addr::new(127,0,0,1))
.port(elseware::ship::ship::SHIP_PORT+2000) .port(elseware::ship::ship::SHIP_PORT+2000)
@ -401,7 +402,7 @@ fn main() {
let ship_loop2 = ship_mainloop(*ship_state, elseware::ship::ship::SHIP_PORT+2000, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT); let ship_loop2 = ship_mainloop(*ship_state, elseware::ship::ship::SHIP_PORT+2000, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT);
let thread_entity_gateway = entity_gateway.clone(); let thread_entity_gateway = entity_gateway.clone();
let ship_state = Box::new(ShipServerStateBuilder::new() let ship_state = Box::new(ShipServerStateBuilder::default()
.name("JP/Thalarion".into()) .name("JP/Thalarion".into())
.ip(Ipv4Addr::new(127,0,0,1)) .ip(Ipv4Addr::new(127,0,0,1))
.port(elseware::ship::ship::SHIP_PORT+3000) .port(elseware::ship::ship::SHIP_PORT+3000)

View File

@ -37,12 +37,12 @@ fn main() {
let shipgate_token = std::env::var("SHIPGATE_TOKEN").unwrap(); let shipgate_token = std::env::var("SHIPGATE_TOKEN").unwrap();
let ship_name = std::env::var("SHIP_NAME").unwrap().parse().unwrap(); let ship_name = std::env::var("SHIP_NAME").unwrap().parse().unwrap();
let ip = std::env::var("SELF_IP").unwrap().parse().unwrap(); let ip = std::env::var("SELF_IP").unwrap().parse().unwrap();
let ship_state = ShipServerStateBuilder::new() let ship_state = ShipServerStateBuilder::default()
.name(ship_name) .name(ship_name)
.ip(ip) .ip(ip)
.port(elseware::ship::ship::SHIP_PORT) .port(elseware::ship::ship::SHIP_PORT)
.gateway(entity_gateway) .gateway(entity_gateway)
.auth_token(AuthToken(shipgate_token.into())) .auth_token(AuthToken(shipgate_token))
.build(); .build();
let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap(); let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap();

View File

@ -30,9 +30,8 @@ pub struct CharacterLevelTable {
table: HashMap<CharacterClass, [CharacterLevelEntry; 200]>, table: HashMap<CharacterClass, [CharacterLevelEntry; 200]>,
} }
impl Default for CharacterLevelTable {
impl CharacterLevelTable { fn default() -> CharacterLevelTable {
pub fn new() -> CharacterLevelTable {
let file = File::open("data/char_stats.json").unwrap(); let file = File::open("data/char_stats.json").unwrap();
let json: Value = serde_json::from_reader(file).unwrap(); let json: Value = serde_json::from_reader(file).unwrap();
let mut table = HashMap::new(); let mut table = HashMap::new();
@ -55,7 +54,7 @@ impl CharacterLevelTable {
}; };
let mut statlist = [CharacterLevelEntry::default(); 200]; let mut statlist = [CharacterLevelEntry::default(); 200];
for (i, stat) in it.1.as_array().unwrap().into_iter().enumerate() { for (i, stat) in it.1.as_array().unwrap().iter().enumerate() {
statlist[i] = CharacterLevelEntry { statlist[i] = CharacterLevelEntry {
hp: stat["hp"].as_i64().unwrap() as u32, hp: stat["hp"].as_i64().unwrap() as u32,
atp: stat["atp"].as_i64().unwrap() as u32, atp: stat["atp"].as_i64().unwrap() as u32,
@ -72,10 +71,12 @@ impl CharacterLevelTable {
} }
CharacterLevelTable { CharacterLevelTable {
table: table, table,
}
} }
} }
impl CharacterLevelTable {
pub fn get_level_from_exp(&self, ch_class: CharacterClass, exp: u32) -> u32 { pub fn get_level_from_exp(&self, ch_class: CharacterClass, exp: u32) -> u32 {
if let Some(statlist) = self.table.get(&ch_class) { if let Some(statlist) = self.table.get(&ch_class) {
statlist statlist
@ -120,14 +121,14 @@ mod test {
use super::*; use super::*;
#[test] #[test]
fn test_stat_levels() { fn test_stat_levels() {
let table = CharacterLevelTable::new(); let table = CharacterLevelTable::default();
assert!(table.get_stats_from_exp(CharacterClass::FOmarl, 0) == (1, CharacterStats { hp: 20, atp: 13, mst: 53, evp: 35, dfp: 10, ata: 15, lck: 10 })); assert!(table.get_stats_from_exp(CharacterClass::FOmarl, 0) == (1, CharacterStats { hp: 20, atp: 13, mst: 53, evp: 35, dfp: 10, ata: 15, lck: 10 }));
assert!(table.get_stats_from_exp(CharacterClass::FOmarl, 1 << 17) == (36, CharacterStats { hp: 125, atp: 114, mst: 219, evp: 182, dfp: 42, ata: 213, lck: 10 })); assert!(table.get_stats_from_exp(CharacterClass::FOmarl, 1 << 17) == (36, CharacterStats { hp: 125, atp: 114, mst: 219, evp: 182, dfp: 42, ata: 213, lck: 10 }));
} }
#[test] #[test]
fn test_levels() { fn test_levels() {
let table = CharacterLevelTable::new(); let table = CharacterLevelTable::default();
assert!(table.get_level_from_exp(CharacterClass::FOmarl, 0) == 1); assert!(table.get_level_from_exp(CharacterClass::FOmarl, 0) == 1);
assert!(table.get_level_from_exp(CharacterClass::FOmarl, 3000) == 8); assert!(table.get_level_from_exp(CharacterClass::FOmarl, 3000) == 8);
assert!(table.get_level_from_exp(CharacterClass::FOmarl, 3200) == 9); assert!(table.get_level_from_exp(CharacterClass::FOmarl, 3200) == 9);

View File

@ -49,8 +49,8 @@ struct PacketReceiver {
impl PacketReceiver { impl PacketReceiver {
fn new(socket: Arc<async_std::net::TcpStream>, cipher: Arc<Mutex<Box<dyn PSOCipher + Send>>>) -> PacketReceiver { fn new(socket: Arc<async_std::net::TcpStream>, cipher: Arc<Mutex<Box<dyn PSOCipher + Send>>>) -> PacketReceiver {
PacketReceiver { PacketReceiver {
socket: socket, socket,
cipher: cipher, cipher,
recv_buffer: Vec::new(), recv_buffer: Vec::new(),
incoming_data: Vec::new(), incoming_data: Vec::new(),
} }
@ -65,7 +65,7 @@ impl PacketReceiver {
return Err(NetworkError::ClientDisconnected); return Err(NetworkError::ClientDisconnected);
} }
self.recv_buffer.extend_from_slice(&mut data[..len]); self.recv_buffer.extend_from_slice(&data[..len]);
let mut dec_buf = { let mut dec_buf = {
let mut cipher = self.cipher.lock().await; let mut cipher = self.cipher.lock().await;
@ -149,7 +149,7 @@ where
R: RecvServerPacket + std::fmt::Debug + Send + 'static, R: RecvServerPacket + std::fmt::Debug + Send + 'static,
{ {
async_std::task::spawn(async move { async_std::task::spawn(async move {
server_sender.send(ClientAction::NewClient(client_id, client_sender)).await; server_sender.send(ClientAction::NewClient(client_id, client_sender)).await.unwrap();
let mut pkt_receiver = PacketReceiver::new(socket, cipher); let mut pkt_receiver = PacketReceiver::new(socket, cipher);
loop { loop {
@ -157,14 +157,14 @@ where
Ok(pkts) => { Ok(pkts) => {
for pkt in pkts { for pkt in pkts {
trace!("[recv from {:?}] {:?}", client_id, pkt); trace!("[recv from {:?}] {:?}", client_id, pkt);
server_sender.send(ClientAction::Packet(client_id, pkt)).await; server_sender.send(ClientAction::Packet(client_id, pkt)).await.unwrap();
} }
}, },
Err(err) => { Err(err) => {
match err { match err {
NetworkError::ClientDisconnected => { NetworkError::ClientDisconnected => {
trace!("[client disconnected] {:?}", client_id); trace!("[client disconnected] {:?}", client_id);
server_sender.send(ClientAction::Disconnect(client_id)).await; server_sender.send(ClientAction::Disconnect(client_id)).await.unwrap();
break; break;
} }
_ => { _ => {
@ -229,10 +229,10 @@ fn state_client_loop<STATE, S, R, E>(state: Arc<Mutex<STATE>>,
for action in actions { for action in actions {
match action { match action {
OnConnect::Cipher((inc, outc)) => { OnConnect::Cipher((inc, outc)) => {
sender.send(ServerStateAction::Cipher(inc, outc)).await; sender.send(ServerStateAction::Cipher(inc, outc)).await.unwrap();
}, },
OnConnect::Packet(pkt) => { OnConnect::Packet(pkt) => {
sender.send(ServerStateAction::Packet(pkt)).await; sender.send(ServerStateAction::Packet(pkt)).await.unwrap();
} }
} }
} }
@ -249,7 +249,7 @@ fn state_client_loop<STATE, S, R, E>(state: Arc<Mutex<STATE>>,
Ok(pkts) => { Ok(pkts) => {
for (client_id, pkt) in pkts { for (client_id, pkt) in pkts {
if let Some(client) = clients.get_mut(&client_id) { if let Some(client) = clients.get_mut(&client_id) {
client.send(ServerStateAction::Packet(pkt)).await; client.send(ServerStateAction::Packet(pkt)).await.unwrap();
} }
} }
}, },
@ -264,12 +264,12 @@ fn state_client_loop<STATE, S, R, E>(state: Arc<Mutex<STATE>>,
Ok(pkts) => { Ok(pkts) => {
for (client_id, pkt) in pkts { for (client_id, pkt) in pkts {
if let Some(client) = clients.get_mut(&client_id) { if let Some(client) = clients.get_mut(&client_id) {
client.send(ServerStateAction::Packet(pkt)).await; client.send(ServerStateAction::Packet(pkt)).await.unwrap();
} }
} }
if let Some(client) = clients.get_mut(&client_id) { if let Some(client) = clients.get_mut(&client_id) {
client.send(ServerStateAction::Disconnect).await; client.send(ServerStateAction::Disconnect).await.unwrap();
} }
} }
Err(err) => { Err(err) => {

View File

@ -29,7 +29,7 @@ struct MessageReceiver {
impl MessageReceiver { impl MessageReceiver {
fn new(socket: async_std::net::TcpStream) -> MessageReceiver { fn new(socket: async_std::net::TcpStream) -> MessageReceiver {
MessageReceiver { MessageReceiver {
socket: socket, socket,
} }
} }
@ -79,7 +79,7 @@ where
ships.insert(server_id, ship_action_sender); ships.insert(server_id, ship_action_sender);
for (server, action) in state.on_connect(server_id).await { for (server, action) in state.on_connect(server_id).await {
if let Some(sender) = ships.get_mut(&server) { if let Some(sender) = ships.get_mut(&server) {
sender.send(action).await; sender.send(action).await.unwrap();
} }
} }
}, },
@ -89,7 +89,7 @@ where
Ok(actions) => { Ok(actions) => {
for (server, action) in actions{ for (server, action) in actions{
if let Some(sender) = ships.get_mut(&server) { if let Some(sender) = ships.get_mut(&server) {
sender.send(action).await; sender.send(action).await.unwrap();
} }
} }
}, },
@ -103,7 +103,7 @@ where
ships.remove(&server_id); ships.remove(&server_id);
for (server, action) in actions { for (server, action) in actions {
if let Some(sender) = ships.get_mut(&server) { if let Some(sender) = ships.get_mut(&server) {
sender.send(action).await; sender.send(action).await.unwrap();
} }
} }
} }
@ -121,7 +121,7 @@ where
R: DeserializeOwned + std::fmt::Debug + Send + 'static, R: DeserializeOwned + std::fmt::Debug + Send + 'static,
{ {
async_std::task::spawn(async move { async_std::task::spawn(async move {
state_loop_sender.send(InterserverInputAction::NewConnection(server_id, output_loop_sender)).await; state_loop_sender.send(InterserverInputAction::NewConnection(server_id, output_loop_sender)).await.unwrap();
let mut msg_receiver = MessageReceiver::new(socket); let mut msg_receiver = MessageReceiver::new(socket);
loop { loop {
@ -129,12 +129,12 @@ where
match msg_receiver.recv().await { match msg_receiver.recv().await {
Ok(msg) => { Ok(msg) => {
info!("[login recv loop msg] {:?}", msg); info!("[login recv loop msg] {:?}", msg);
state_loop_sender.send(InterserverInputAction::Message(server_id, msg)).await; state_loop_sender.send(InterserverInputAction::Message(server_id, msg)).await.unwrap();
}, },
Err(err) => { Err(err) => {
if let MessageReceiverError::Disconnected = err { if let MessageReceiverError::Disconnected = err {
info!("[login recv loop disconnect] {:?}", server_id); info!("[login recv loop disconnect] {:?}", server_id);
state_loop_sender.send(InterserverInputAction::Disconnect(server_id)).await; state_loop_sender.send(InterserverInputAction::Disconnect(server_id)).await.unwrap();
break; break;
} }
info!("[login recv loop err] {:?}", err); info!("[login recv loop err] {:?}", err);
@ -163,7 +163,7 @@ where
warn!("interserver send failed: {:?}", err); warn!("interserver send failed: {:?}", err);
break; break;
} }
if let Err(err) = socket.write_all(&payload.as_bytes()).await { if let Err(err) = socket.write_all(payload.as_bytes()).await {
warn!("intserserver send failed: {:?}", err); warn!("intserserver send failed: {:?}", err);
break; break;
} }
@ -200,7 +200,7 @@ pub fn login_listen_mainloop<EG: EntityGateway + 'static>(state: Arc<Mutex<Chara
let mut state = state.lock().await; let mut state = state.lock().await;
let local_sender = client_sender.clone(); let local_sender = client_sender.clone();
state.set_sender(server_id, Box::new(move |message| { state.set_sender(server_id, Box::new(move |message| {
async_std::task::block_on(local_sender.send(message)); async_std::task::block_on(local_sender.send(message)).unwrap();
})) }))
} }
@ -236,7 +236,7 @@ pub fn ship_connect_mainloop<EG: EntityGateway + 'static>(state: Arc<Mutex<ShipS
let mut state = state.lock().await; let mut state = state.lock().await;
let local_sender = client_sender.clone(); let local_sender = client_sender.clone();
state.set_sender(Box::new(move |message| { state.set_sender(Box::new(move |message| {
async_std::task::block_on(local_sender.send(message)); async_std::task::block_on(local_sender.send(message)).unwrap();
})) }))
} }

View File

@ -25,7 +25,7 @@ pub fn patch_mainloop(patch_state: PatchServerState, patch_port: u16) -> Pin<Box
pub fn login_mainloop<EG: EntityGateway + 'static>(login_state: LoginServerState<EG>, login_port: u16) -> Pin<Box<dyn Future<Output = ()>>> { pub fn login_mainloop<EG: EntityGateway + 'static>(login_state: LoginServerState<EG>, login_port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
let login_state = Arc::new(Mutex::new(login_state)); let login_state = Arc::new(Mutex::new(login_state));
let client_mainloop = client_accept_mainloop(login_state.clone(), login_port); let client_mainloop = client_accept_mainloop(login_state, login_port);
Box::pin(client_mainloop) Box::pin(client_mainloop)
} }

View File

@ -75,7 +75,7 @@ pub struct NewUserSettingsEntity {
impl NewUserSettingsEntity { impl NewUserSettingsEntity {
pub fn new(user_id: UserAccountId) -> NewUserSettingsEntity { pub fn new(user_id: UserAccountId) -> NewUserSettingsEntity {
NewUserSettingsEntity { NewUserSettingsEntity {
user_id: user_id, user_id,
settings: settings::UserSettings::default(), settings: settings::UserSettings::default(),
} }
} }
@ -98,7 +98,7 @@ pub struct NewGuildCardDataEntity {
impl NewGuildCardDataEntity { impl NewGuildCardDataEntity {
pub fn new(user_id: UserAccountId) -> NewGuildCardDataEntity { pub fn new(user_id: UserAccountId) -> NewGuildCardDataEntity {
NewGuildCardDataEntity { NewGuildCardDataEntity {
user_id: user_id, user_id,
guildcard: guildcard::GuildCardData::default(), guildcard: guildcard::GuildCardData::default(),
} }
} }
@ -116,7 +116,7 @@ impl GuildCardDataEntity {
pub fn new(user_id: UserAccountId) -> GuildCardDataEntity { pub fn new(user_id: UserAccountId) -> GuildCardDataEntity {
GuildCardDataEntity { GuildCardDataEntity {
id: GuildCardDataId(0), id: GuildCardDataId(0),
user_id: user_id, user_id,
guildcard: guildcard::GuildCardData::default(), guildcard: guildcard::GuildCardData::default(),
} }
} }

View File

@ -44,9 +44,9 @@ impl From<u8> for CharacterClass {
} }
} }
impl Into<u8> for CharacterClass { impl From<CharacterClass> for u8 {
fn into(self) -> u8 { fn from(other: CharacterClass) -> u8 {
match self { match other {
CharacterClass::HUmar => 0, CharacterClass::HUmar => 0,
CharacterClass::HUnewearl => 1, CharacterClass::HUnewearl => 1,
CharacterClass::HUcast => 2, CharacterClass::HUcast => 2,
@ -65,29 +65,27 @@ impl Into<u8> for CharacterClass {
impl CharacterClass { impl CharacterClass {
pub fn is_human(&self) -> bool { pub fn is_human(&self) -> bool {
match self { matches!(self,
CharacterClass::HUmar | CharacterClass::HUmar |
CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::RAmar |
CharacterClass::FOmar | CharacterClass::FOmarl => true, CharacterClass::RAmarl |
CharacterClass::FOmar |
_ => false, CharacterClass::FOmarl)
}
} }
pub fn is_newman(&self) -> bool { pub fn is_newman(&self) -> bool {
match self { matches!(self,
CharacterClass::HUnewearl | CharacterClass::HUnewearl |
CharacterClass::FOnewm | CharacterClass::FOnewearl => true, CharacterClass::FOnewm |
_ => false, CharacterClass::FOnewearl)
}
} }
pub fn is_android(&self) -> bool { pub fn is_android(&self) -> bool {
match self { matches!(self,
CharacterClass::HUcast | CharacterClass::HUcaseal | CharacterClass::HUcast |
CharacterClass::RAcast | CharacterClass::RAcaseal => true, CharacterClass::HUcaseal |
_ => false, CharacterClass::RAcast |
} CharacterClass::RAcaseal)
} }
} }
@ -124,9 +122,9 @@ impl From<u8> for SectionID {
} }
} }
impl Into<u8> for SectionID { impl From<SectionID> for u8 {
fn into(self) -> u8 { fn from(other: SectionID) -> u8 {
match self { match other {
SectionID::Viridia => 0, SectionID::Viridia => 0,
SectionID::Greenill => 1, SectionID::Greenill => 1,
SectionID::Skyly => 2, SectionID::Skyly => 2,

View File

@ -21,8 +21,8 @@ pub struct InMemoryGateway {
weapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<weapon::WeaponModifier>>>>, weapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<weapon::WeaponModifier>>>>,
} }
impl InMemoryGateway { impl Default for InMemoryGateway {
pub fn new() -> InMemoryGateway { fn default() -> InMemoryGateway {
InMemoryGateway { InMemoryGateway {
users: Arc::new(Mutex::new(BTreeMap::new())), users: Arc::new(Mutex::new(BTreeMap::new())),
user_settings: Arc::new(Mutex::new(BTreeMap::new())), user_settings: Arc::new(Mutex::new(BTreeMap::new())),
@ -47,7 +47,7 @@ impl InMemoryGateway {
ItemDetail::Weapon(mut weapon) => { ItemDetail::Weapon(mut weapon) => {
if let Some(weapon_modifiers) = self.weapon_modifiers.lock().unwrap().get(&item.id) { if let Some(weapon_modifiers) = self.weapon_modifiers.lock().unwrap().get(&item.id) {
for weapon_modifier in weapon_modifiers.iter() { for weapon_modifier in weapon_modifiers.iter() {
weapon.apply_modifier(&weapon_modifier); weapon.apply_modifier(weapon_modifier);
} }
} }
ItemDetail::Weapon(weapon) ItemDetail::Weapon(weapon)
@ -58,23 +58,21 @@ impl InMemoryGateway {
for mag_modifier in mag_modifiers.iter() { for mag_modifier in mag_modifiers.iter() {
match mag_modifier { match mag_modifier {
mag::MagModifier::FeedMag {food} => { mag::MagModifier::FeedMag {food} => {
items.get(&food).map(|mag_feed| { if let Some(mag_feed) = items.get(food) {
match mag_feed.item { if let ItemDetail::Tool(mag_feed) = mag_feed.item {
ItemDetail::Tool(mag_feed) => mag.feed(mag_feed.tool), mag.feed(mag_feed.tool)
_ => {} }
} }
});
}, },
mag::MagModifier::OwnerChange(class, section_id) => { mag::MagModifier::OwnerChange(class, section_id) => {
mag.change_owner(*class, *section_id) mag.change_owner(*class, *section_id)
}, },
mag::MagModifier::MagCell(mag_cell_id) => { mag::MagModifier::MagCell(mag_cell_id) => {
items.get(&mag_cell_id).map(|mag_cell| { if let Some(mag_cell) = items.get(mag_cell_id) {
match mag_cell.item { if let ItemDetail::Tool(mag_cell) = mag_cell.item {
ItemDetail::Tool(mag_cell) => mag.apply_mag_cell(mag_cell.tool.try_into().unwrap()), mag.apply_mag_cell(mag_cell.tool.try_into().unwrap())
_ => {} }
} }
});
}, },
_ => {} _ => {}
} }
@ -124,7 +122,7 @@ impl EntityGateway for InMemoryGateway {
async fn get_user_by_id(&self, id: UserAccountId) -> Result<UserAccountEntity, GatewayError> { async fn get_user_by_id(&self, id: UserAccountId) -> Result<UserAccountEntity, GatewayError> {
let users = self.users.lock().unwrap(); let users = self.users.lock().unwrap();
users.get(&id).map(|k| k.clone()).ok_or(GatewayError::Error) users.get(&id).cloned().ok_or(GatewayError::Error)
} }
async fn get_user_by_name(&self, username: String) -> Result<UserAccountEntity, GatewayError> { async fn get_user_by_name(&self, username: String) -> Result<UserAccountEntity, GatewayError> {
@ -233,17 +231,16 @@ impl EntityGateway for InMemoryGateway {
} }
async fn change_item_location(&mut self, item_id: &ItemEntityId, item_location: ItemLocation) -> Result<(), GatewayError> { async fn change_item_location(&mut self, item_id: &ItemEntityId, item_location: ItemLocation) -> Result<(), GatewayError> {
self.items.lock().unwrap().get_mut(&item_id) if let Some(item_entity) = self.items.lock().unwrap().get_mut(item_id) {
.map(|item_entity| {
item_entity.location = item_location item_entity.location = item_location
}); }
Ok(()) Ok(())
} }
async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> { async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> {
self.mag_modifiers.lock().unwrap() self.mag_modifiers.lock().unwrap()
.entry(*mag_item_id) .entry(*mag_item_id)
.or_insert(Vec::new()) .or_insert_with(Vec::new)
.push(mag::MagModifier::FeedMag { .push(mag::MagModifier::FeedMag {
food: *tool_item_id food: *tool_item_id
}); });
@ -253,7 +250,7 @@ impl EntityGateway for InMemoryGateway {
async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> { async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> {
self.mag_modifiers.lock().unwrap() self.mag_modifiers.lock().unwrap()
.entry(*mag_item_id) .entry(*mag_item_id)
.or_insert(Vec::new()) .or_insert_with(Vec::new)
.push(mag::MagModifier::OwnerChange(character.char_class, character.section_id)); .push(mag::MagModifier::OwnerChange(character.char_class, character.section_id));
Ok(()) Ok(())
} }
@ -261,15 +258,15 @@ impl EntityGateway for InMemoryGateway {
async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> { async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> {
self.mag_modifiers.lock().unwrap() self.mag_modifiers.lock().unwrap()
.entry(*mag_item_id) .entry(*mag_item_id)
.or_insert(Vec::new()) .or_insert_with(Vec::new)
.push(mag::MagModifier::MagCell(mag_cell_id.clone())); .push(mag::MagModifier::MagCell(*mag_cell_id));
Ok(()) Ok(())
} }
async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> { async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> {
self.weapon_modifiers.lock().unwrap() self.weapon_modifiers.lock().unwrap()
.entry(*item_id) .entry(*item_id)
.or_insert(Vec::new()) .or_insert_with(Vec::new)
.push(modifier); .push(modifier);
Ok(()) Ok(())
} }
@ -282,7 +279,7 @@ impl EntityGateway for InMemoryGateway {
.find(|(id, _)| **id == *char_id) .find(|(id, _)| **id == *char_id)
.map(|(_, inv)| inv.clone()) .map(|(_, inv)| inv.clone())
.map(|inv| self.apply_modifiers(inv)) .map(|inv| self.apply_modifiers(inv))
.unwrap_or(InventoryEntity::default())) .unwrap_or_default())
} }
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, _bank_name: BankName) -> Result<BankEntity, GatewayError> { async fn get_character_bank(&mut self, char_id: &CharacterEntityId, _bank_name: BankName) -> Result<BankEntity, GatewayError> {
@ -291,7 +288,7 @@ impl EntityGateway for InMemoryGateway {
.iter() .iter()
.find(|(id, _)| **id == *char_id) .find(|(id, _)| **id == *char_id)
.map(|(_, b)| b.clone()) .map(|(_, b)| b.clone())
.unwrap_or(BankEntity::default())) .unwrap_or_default())
} }
async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> { async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> {
@ -313,7 +310,7 @@ impl EntityGateway for InMemoryGateway {
.iter() .iter()
.find(|(id, _)| **id == *char_id) .find(|(id, _)| **id == *char_id)
.map(|(_, inv)| inv.clone()) .map(|(_, inv)| inv.clone())
.unwrap_or(EquippedEntity::default())) .unwrap_or_default())
} }
async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equipped: &EquippedEntity) -> Result<(), GatewayError> { async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equipped: &EquippedEntity) -> Result<(), GatewayError> {

View File

@ -1,3 +1,4 @@
#[allow(clippy::module_inception)]
pub mod postgres; pub mod postgres;
pub mod migrations; pub mod migrations;
pub mod models; pub mod models;

View File

@ -23,22 +23,22 @@ pub struct PgUserAccount {
at_ship: bool, at_ship: bool,
} }
impl Into<UserAccountEntity> for PgUserAccount { impl From<PgUserAccount> for UserAccountEntity {
fn into(self) -> UserAccountEntity { fn from(other: PgUserAccount) -> UserAccountEntity {
UserAccountEntity { UserAccountEntity {
id: UserAccountId(self.id as u32), id: UserAccountId(other.id as u32),
username: self.username, username: other.username,
password: self.password, password: other.password,
banned_until: self.banned, banned_until: other.banned,
muted_until: self.muted, muted_until: other.muted,
created_at: self.created_at, created_at: other.created_at,
flags: self.flags as u32, flags: other.flags as u32,
guildcard: self.id as u32 + 1, guildcard: other.id as u32 + 1,
team_id: None, team_id: None,
activated: self.activated, activated: other.activated,
at_login: self.at_login, at_login: other.at_login,
at_character: self.at_character, at_character: other.at_character,
at_ship: self.at_ship, at_ship: other.at_ship,
} }
} }
} }
@ -56,19 +56,19 @@ pub struct PgUserSettings {
team_name: Vec<u8>, //[u16; 0x10], team_name: Vec<u8>, //[u16; 0x10],
} }
impl Into<UserSettingsEntity> for PgUserSettings { impl From<PgUserSettings> for UserSettingsEntity {
fn into(self) -> UserSettingsEntity { fn from(other: PgUserSettings) -> UserSettingsEntity {
UserSettingsEntity { UserSettingsEntity {
id: UserSettingsId(self.id as u32), id: UserSettingsId(other.id as u32),
user_id: UserAccountId(self.user_account as u32), user_id: UserAccountId(other.user_account as u32),
settings: settings::UserSettings { settings: settings::UserSettings {
blocked_users: vec_to_array(self.blocked_users.chunks(4).map(|b| u32::from_le_bytes([b[0], b[1], b[2], b[3]])).collect()), blocked_users: vec_to_array(other.blocked_users.chunks(4).map(|b| u32::from_le_bytes([b[0], b[1], b[2], b[3]])).collect()),
key_config: vec_to_array(self.key_config), key_config: vec_to_array(other.key_config),
joystick_config: vec_to_array(self.joystick_config), joystick_config: vec_to_array(other.joystick_config),
option_flags: self.option_flags as u32, option_flags: other.option_flags as u32,
shortcuts: vec_to_array(self.shortcuts), shortcuts: vec_to_array(other.shortcuts),
symbol_chats: vec_to_array(self.symbol_chats), symbol_chats: vec_to_array(other.symbol_chats),
team_name: vec_to_array(self.team_name.chunks(2).map(|b| u16::from_le_bytes([b[0], b[1]])).collect()), team_name: vec_to_array(other.team_name.chunks(2).map(|b| u16::from_le_bytes([b[0], b[1]])).collect()),
} }
} }
} }
@ -91,9 +91,9 @@ pub enum PgCharacterClass {
FOnewearl, FOnewearl,
} }
impl Into<CharacterClass> for PgCharacterClass { impl From<PgCharacterClass> for CharacterClass {
fn into(self) -> CharacterClass { fn from(other: PgCharacterClass) -> CharacterClass {
match self { match other{
PgCharacterClass::HUmar => CharacterClass::HUmar, PgCharacterClass::HUmar => CharacterClass::HUmar,
PgCharacterClass::HUnewearl => CharacterClass::HUnewearl, PgCharacterClass::HUnewearl => CharacterClass::HUnewearl,
PgCharacterClass::HUcast => CharacterClass::HUcast, PgCharacterClass::HUcast => CharacterClass::HUcast,
@ -144,9 +144,9 @@ pub enum PgSectionId {
Whitill, Whitill,
} }
impl Into<SectionID> for PgSectionId { impl From<PgSectionId> for SectionID {
fn into(self) -> SectionID { fn from(other: PgSectionId) -> SectionID {
match self { match other {
PgSectionId::Viridia => SectionID::Viridia, PgSectionId::Viridia => SectionID::Viridia,
PgSectionId::Greenill => SectionID::Greenill, PgSectionId::Greenill => SectionID::Greenill,
PgSectionId::Skyly => SectionID::Skyly, PgSectionId::Skyly => SectionID::Skyly,
@ -220,55 +220,55 @@ pub struct PgCharacter {
bank_meseta: i32, bank_meseta: i32,
} }
impl Into<CharacterEntity> for PgCharacter { impl From<PgCharacter> for CharacterEntity {
fn into(self) -> CharacterEntity { fn from(other: PgCharacter) -> CharacterEntity {
CharacterEntity { CharacterEntity {
id: CharacterEntityId(self.id as u32), id: CharacterEntityId(other.id as u32),
user_id: UserAccountId(self.user_account as u32), user_id: UserAccountId(other.user_account as u32),
slot: self.slot as u32, slot: other.slot as u32,
name: self.name, name: other.name,
exp: self.exp as u32, exp: other.exp as u32,
char_class: self.class.parse().unwrap(), char_class: other.class.parse().unwrap(),
section_id: self.section_id.parse().unwrap(), section_id: other.section_id.parse().unwrap(),
appearance: CharacterAppearance { appearance: CharacterAppearance {
costume: self.costume as u16, costume: other.costume as u16,
skin: self.skin as u16, skin: other.skin as u16,
face: self.face as u16, face: other.face as u16,
head: self.head as u16, head: other.head as u16,
hair: self.hair as u16, hair: other.hair as u16,
hair_r: self.hair_r as u16, hair_r: other.hair_r as u16,
hair_g: self.hair_g as u16, hair_g: other.hair_g as u16,
hair_b: self.hair_b as u16, hair_b: other.hair_b as u16,
prop_x: self.prop_x, prop_x: other.prop_x,
prop_y: self.prop_y, prop_y: other.prop_y,
}, },
techs: CharacterTechniques { techs: CharacterTechniques {
techs: self.techs.iter().enumerate().take(19).filter(|(_, t)| **t != 0xFF).map(|(i, t)| (tech::Technique::from_value(i as u8), TechLevel(*t)) ).collect() techs: other.techs.iter().enumerate().take(19).filter(|(_, t)| **t != 0xFF).map(|(i, t)| (tech::Technique::from_value(i as u8), TechLevel(*t)) ).collect()
}, },
config: CharacterConfig { config: CharacterConfig {
raw_data: vec_to_array(self.config) raw_data: vec_to_array(other.config)
}, },
info_board: CharacterInfoboard { info_board: CharacterInfoboard {
board: libpso::utf8_to_utf16_array!(self.infoboard, 172), board: libpso::utf8_to_utf16_array!(other.infoboard, 172),
}, },
guildcard: CharacterGuildCard { guildcard: CharacterGuildCard {
description: self.guildcard, description: other.guildcard,
}, },
option_flags: self.option_flags as u32, option_flags: other.option_flags as u32,
materials: CharacterMaterials { materials: CharacterMaterials {
power: self.power as u32, power: other.power as u32,
mind: self.mind as u32, mind: other.mind as u32,
def: self.def as u32, def: other.def as u32,
evade: self.evade as u32, evade: other.evade as u32,
luck: self.luck as u32, luck: other.luck as u32,
hp: self.hp as u32, hp: other.hp as u32,
tp: self.tp as u32, tp: other.tp as u32,
}, },
tech_menu: CharacterTechMenu { tech_menu: CharacterTechMenu {
tech_menu: vec_to_array(self.tech_menu) tech_menu: vec_to_array(other.tech_menu)
}, },
meseta: self.meseta as u32, meseta: other.meseta as u32,
bank_meseta: self.bank_meseta as u32, bank_meseta: other.bank_meseta as u32,
} }
} }
} }
@ -300,10 +300,10 @@ impl From<weapon::Weapon> for PgWeapon {
} }
} }
impl Into<weapon::Weapon> for PgWeapon { impl From<PgWeapon> for weapon::Weapon {
fn into(self) -> weapon::Weapon { fn from(other: PgWeapon) -> weapon::Weapon {
let mut attrs: [Option<weapon::WeaponAttribute>; 3] = [None; 3]; let mut attrs: [Option<weapon::WeaponAttribute>; 3] = [None; 3];
for (attr, (atype, value)) in attrs.iter_mut().zip(self.attrs.iter()) { for (attr, (atype, value)) in attrs.iter_mut().zip(other.attrs.iter()) {
*attr = Some(weapon::WeaponAttribute { *attr = Some(weapon::WeaponAttribute {
attr: *atype, attr: *atype,
value: *value value: *value
@ -311,11 +311,11 @@ impl Into<weapon::Weapon> for PgWeapon {
} }
weapon::Weapon { weapon::Weapon {
weapon: self.weapon, weapon: other.weapon,
special: self.special, special: other.special,
grind: self.grind, grind: other.grind,
attrs: attrs, attrs,
tekked: self.tekked, tekked: other.tekked,
} }
} }
} }
@ -345,13 +345,13 @@ impl From<armor::Armor> for PgArmor {
} }
} }
impl Into<armor::Armor> for PgArmor { impl From<PgArmor> for armor::Armor {
fn into(self) -> armor::Armor { fn from(other: PgArmor) -> armor::Armor {
armor::Armor { armor::Armor {
armor: self.armor, armor: other.armor,
dfp: self.dfp, dfp: other.dfp,
evp: self.evp, evp: other.evp,
slots: self.slots, slots: other.slots,
} }
} }
} }
@ -373,12 +373,12 @@ impl From<shield::Shield> for PgShield {
} }
} }
impl Into<shield::Shield> for PgShield { impl From<PgShield> for shield::Shield {
fn into(self) -> shield::Shield { fn from(other: PgShield) -> shield::Shield {
shield::Shield { shield::Shield {
shield: self.shield, shield: other.shield,
dfp: self.dfp, dfp: other.dfp,
evp: self.evp, evp: other.evp,
} }
} }
} }
@ -398,11 +398,11 @@ impl From<unit::Unit> for PgUnit {
} }
} }
impl Into<unit::Unit> for PgUnit { impl From<PgUnit> for unit::Unit {
fn into(self) -> unit::Unit { fn from(other: PgUnit) -> unit::Unit {
unit::Unit { unit::Unit {
unit: self.unit, unit: other.unit,
modifier: self.modifier, modifier: other.modifier,
} }
} }
} }
@ -420,10 +420,10 @@ impl From<tool::Tool> for PgTool {
} }
} }
impl Into<tool::Tool> for PgTool { impl From<PgTool> for tool::Tool {
fn into(self) -> tool::Tool { fn from(other: PgTool) -> tool::Tool {
tool::Tool { tool::Tool {
tool: self.tool, tool: other.tool,
} }
} }
} }
@ -443,11 +443,11 @@ impl From<tech::TechniqueDisk> for PgTechDisk {
} }
} }
impl Into<tech::TechniqueDisk> for PgTechDisk { impl From<PgTechDisk> for tech::TechniqueDisk {
fn into(self) -> tech::TechniqueDisk { fn from(other: PgTechDisk) -> tech::TechniqueDisk {
tech::TechniqueDisk { tech::TechniqueDisk {
tech: self.tech, tech: other.tech,
level: self.level level: other.level
} }
} }
} }
@ -469,8 +469,8 @@ impl From<mag::Mag> for PgMag {
} }
} }
impl Into<mag::Mag> for PgMag { impl From<PgMag> for mag::Mag {
fn into(self) -> mag::Mag { fn from(other: PgMag) -> mag::Mag {
/*mag::Mag { /*mag::Mag {
mag: self.mag, mag: self.mag,
synchro: self.synchro, synchro: self.synchro,
@ -484,9 +484,9 @@ impl Into<mag::Mag> for PgMag {
class: CharacterClass::HUmar, class: CharacterClass::HUmar,
id: SectionID::Viridia, id: SectionID::Viridia,
}*/ }*/
let mut mag = mag::Mag::baby_mag(self.color as u16); let mut mag = mag::Mag::baby_mag(other.color as u16);
mag.mag = self.mag; mag.mag = other.mag;
mag.synchro = self.synchro; mag.synchro = other.synchro;
mag mag
} }
} }
@ -510,13 +510,13 @@ impl From<esweapon::ESWeapon> for PgESWeapon {
} }
} }
impl Into<esweapon::ESWeapon> for PgESWeapon { impl From<PgESWeapon> for esweapon::ESWeapon {
fn into(self) -> esweapon::ESWeapon { fn from(other: PgESWeapon) -> esweapon::ESWeapon {
esweapon::ESWeapon { esweapon::ESWeapon {
esweapon: self.esweapon, esweapon: other.esweapon,
special: self.special, special: other.special,
name: self.name, name: other.name,
grind: self.grind, grind: other.grind,
} }
} }
} }
@ -548,9 +548,9 @@ impl From<ItemDetail> for PgItemDetail {
} }
} }
impl Into<ItemDetail> for PgItemDetail { impl From<PgItemDetail> for ItemDetail {
fn into(self) -> ItemDetail { fn from(other: PgItemDetail) -> ItemDetail {
match self { match other {
PgItemDetail::Weapon(weapon) => ItemDetail::Weapon(weapon.into()), PgItemDetail::Weapon(weapon) => ItemDetail::Weapon(weapon.into()),
PgItemDetail::Armor(armor) => ItemDetail::Armor(armor.into()), PgItemDetail::Armor(armor) => ItemDetail::Armor(armor.into()),
PgItemDetail::Shield(shield) => ItemDetail::Shield(shield.into()), PgItemDetail::Shield(shield) => ItemDetail::Shield(shield.into()),
@ -613,9 +613,9 @@ impl From<ItemLocation> for PgItemLocationDetail {
} }
} }
impl Into<ItemLocation> for PgItemLocationDetail { impl From<PgItemLocationDetail> for ItemLocation {
fn into(self) -> ItemLocation { fn from(other: PgItemLocationDetail) -> ItemLocation {
match self { match other{
PgItemLocationDetail::Inventory{character_id} => ItemLocation::Inventory{character_id: CharacterEntityId(character_id)}, PgItemLocationDetail::Inventory{character_id} => ItemLocation::Inventory{character_id: CharacterEntityId(character_id)},
PgItemLocationDetail::Bank{character_id, name} => ItemLocation::Bank{character_id: CharacterEntityId(character_id), name: BankName(name)}, PgItemLocationDetail::Bank{character_id, name} => ItemLocation::Bank{character_id: CharacterEntityId(character_id), name: BankName(name)},
PgItemLocationDetail::LocalFloor{character_id, map_area, x,y,z} => ItemLocation::LocalFloor{character_id: CharacterEntityId(character_id), map_area, x,y,z}, PgItemLocationDetail::LocalFloor{character_id, map_area, x,y,z} => ItemLocation::LocalFloor{character_id: CharacterEntityId(character_id), map_area, x,y,z},
@ -655,9 +655,9 @@ impl From<mag::MagModifier> for PgMagModifierDetail {
} }
} }
impl Into<mag::MagModifier> for PgMagModifierDetail { impl From<PgMagModifierDetail> for mag::MagModifier {
fn into(self) -> mag::MagModifier { fn from(other: PgMagModifierDetail) -> mag::MagModifier {
match self { match other {
PgMagModifierDetail::FeedMag(food) => mag::MagModifier::FeedMag{food: ItemEntityId(food as u32)}, PgMagModifierDetail::FeedMag(food) => mag::MagModifier::FeedMag{food: ItemEntityId(food as u32)},
PgMagModifierDetail::BankMag => mag::MagModifier::BankMag, PgMagModifierDetail::BankMag => mag::MagModifier::BankMag,
PgMagModifierDetail::MagCell(cell) => mag::MagModifier::MagCell(ItemEntityId(cell as u32)), PgMagModifierDetail::MagCell(cell) => mag::MagModifier::MagCell(ItemEntityId(cell as u32)),
@ -687,12 +687,12 @@ pub struct PgItemWithLocation {
pub location: sqlx::types::Json<PgItemLocationDetail>, pub location: sqlx::types::Json<PgItemLocationDetail>,
} }
impl Into<ItemEntity> for PgItemWithLocation { impl From<PgItemWithLocation> for ItemEntity {
fn into(self) -> ItemEntity { fn from(other: PgItemWithLocation) -> ItemEntity {
ItemEntity { ItemEntity {
id: ItemEntityId(self.id as u32), id: ItemEntityId(other.id as u32),
item: self.item.0.into(), item: other.item.0.into(),
location: self.location.0.into(), location: other.location.0.into(),
} }
} }
} }
@ -740,18 +740,18 @@ pub struct PgEquipped {
mag: Option<i32>, mag: Option<i32>,
} }
impl Into<EquippedEntity> for PgEquipped { impl From<PgEquipped> for EquippedEntity{
fn into(self) -> EquippedEntity { fn from(other: PgEquipped) -> EquippedEntity {
EquippedEntity { EquippedEntity {
weapon: self.weapon.map(|i| ItemEntityId(i as u32)), weapon: other.weapon.map(|i| ItemEntityId(i as u32)),
armor: self.armor.map(|i| ItemEntityId(i as u32)), armor: other.armor.map(|i| ItemEntityId(i as u32)),
shield: self.shield.map(|i| ItemEntityId(i as u32)), shield: other.shield.map(|i| ItemEntityId(i as u32)),
unit: [self.unit0.map(|i| ItemEntityId(i as u32)), unit: [other.unit0.map(|i| ItemEntityId(i as u32)),
self.unit1.map(|i| ItemEntityId(i as u32)), other.unit1.map(|i| ItemEntityId(i as u32)),
self.unit2.map(|i| ItemEntityId(i as u32)), other.unit2.map(|i| ItemEntityId(i as u32)),
self.unit3.map(|i| ItemEntityId(i as u32)), other.unit3.map(|i| ItemEntityId(i as u32)),
], ],
mag: self.mag.map(|i| ItemEntityId(i as u32)), mag: other.mag.map(|i| ItemEntityId(i as u32)),
} }
} }
} }

View File

@ -1,5 +1,4 @@
use std::convert::{From, TryFrom, Into}; use std::convert::{From, TryFrom, Into};
use futures::future::join_all;
use futures::TryStreamExt; use futures::TryStreamExt;
use async_std::stream::StreamExt; use async_std::stream::StreamExt;
use libpso::character::guildcard; use libpso::character::guildcard;
@ -25,10 +24,10 @@ pub struct PostgresGateway {
impl PostgresGateway { impl PostgresGateway {
pub fn new(host: &str, dbname: &str, username: &str, password: &str) -> PostgresGateway { pub fn new(host: &str, dbname: &str, username: &str, password: &str) -> PostgresGateway {
let mut conn = refinery::config::Config::new(refinery::config::ConfigDbType::Postgres) let mut conn = refinery::config::Config::new(refinery::config::ConfigDbType::Postgres)
.set_db_host(&host) .set_db_host(host)
.set_db_user(&username) .set_db_user(username)
.set_db_pass(&password) .set_db_pass(password)
.set_db_name(&dbname); .set_db_name(dbname);
embedded::migrations::runner().run(&mut conn).unwrap(); embedded::migrations::runner().run(&mut conn).unwrap();
let pool = async_std::task::block_on(async move { let pool = async_std::task::block_on(async move {
@ -40,7 +39,7 @@ impl PostgresGateway {
}); });
PostgresGateway { PostgresGateway {
pool: pool, pool,
} }
} }
@ -96,13 +95,13 @@ impl PostgresGateway {
ItemDetail::Mag(mag) ItemDetail::Mag(mag)
}, },
item @ _ => item item => item
}; };
ItemEntity { ItemEntity {
id: id, id,
item: item, item,
location: location location
} }
} }
} }

View File

@ -317,9 +317,9 @@ impl Armor {
pub fn from_bytes(data: [u8; 16]) -> Result<Armor, ItemParseError> { pub fn from_bytes(data: [u8; 16]) -> Result<Armor, ItemParseError> {
let a = ArmorType::parse_type([data[0], data[1], data[2]]); let a = ArmorType::parse_type([data[0], data[1], data[2]]);
if a.is_ok() { if let Ok(a) = a {
Ok(Armor { Ok(Armor {
armor: a.unwrap(), armor: a,
dfp: data[6], dfp: data[6],
evp: data[8], evp: data[8],
slots: data[5], slots: data[5],

View File

@ -190,10 +190,10 @@ impl ESWeapon {
pub fn bytes_from_name(&self) -> [u8; 6] { pub fn bytes_from_name(&self) -> [u8; 6] {
let mut result = [0u16; 3]; let mut result = [0u16; 3];
let mut letters = [0u8; 8]; let mut letters = [0u8; 8];
letters[0..self.name.len()].clone_from_slice(&self.name.to_uppercase().clone().into_bytes()); letters[0..self.name.len()].clone_from_slice(&self.name.to_uppercase().into_bytes());
for letter in letters.iter_mut() { for letter in letters.iter_mut() {
*letter = *letter & 0x3F; *letter &= 0x3F;
} }
result[0] = 0x8000 + (0x20 * letters[0] as u16) + (letters[1] as u16); result[0] = 0x8000 + (0x20 * letters[0] as u16) + (letters[1] as u16);
@ -207,29 +207,22 @@ impl ESWeapon {
// TODO: error handling, ensure name is never more than 8 // TODO: error handling, ensure name is never more than 8
pub fn name_from_bytes(namebytes: &[u8]) -> String { pub fn name_from_bytes(namebytes: &[u8]) -> String {
let mut name: Vec<u8> = Vec::with_capacity(8);
name.extend_from_slice(namebytes);
for _ in name.len()..name.capacity() {
name.push(0);
}
let buf: [u16; 3] = [ let buf: [u16; 3] = [
u16::from_be_bytes([namebytes[0], namebytes[1]]), u16::from_be_bytes([namebytes[0], namebytes[1]]),
u16::from_be_bytes([namebytes[2], namebytes[3]]), u16::from_be_bytes([namebytes[2], namebytes[3]]),
u16::from_be_bytes([namebytes[4], namebytes[5]]), u16::from_be_bytes([namebytes[4], namebytes[5]]),
]; ];
name[0] = ((buf[0] - 0x8000) / 0x20 + 0x40) as u8; let mut name: Vec<u8> = vec![
name[1] = ((buf[0] - 0x8000) % 0x20 + 0x40) as u8; ((buf[0] - 0x8000) / 0x20 + 0x40) as u8,
((buf[0] - 0x8000) % 0x20 + 0x40) as u8,
name[2] = ((buf[1] - 0x8000) / 0x400 + 0x40) as u8; ((buf[1] - 0x8000) / 0x400 + 0x40) as u8,
name[3] = (((buf[1] - 0x8000) % 0x400) / 0x20 + 0x40) as u8; (((buf[1] - 0x8000) % 0x400) / 0x20 + 0x40) as u8,
name[4] = (((buf[1] - 0x8000) % 0x400) % 0x20 + 0x40) as u8; (((buf[1] - 0x8000) % 0x400) % 0x20 + 0x40) as u8,
((buf[2] - 0x8000) / 0x400 + 0x40) as u8,
name[5] = ((buf[2] - 0x8000) / 0x400 + 0x40) as u8; (((buf[2] - 0x8000) % 0x400) / 0x20 + 0x40) as u8,
name[6] = (((buf[2] - 0x8000) % 0x400) / 0x20 + 0x40) as u8; (((buf[2] - 0x8000) % 0x400) % 0x20 + 0x40) as u8,
name[7] = (((buf[2] - 0x8000) % 0x400) % 0x20 + 0x40) as u8; ];
name.retain(|&x| x > 0x40 && x < 0x5B); name.retain(|&x| x > 0x40 && x < 0x5B);
@ -254,10 +247,10 @@ impl ESWeapon {
let name = ESWeapon::name_from_bytes(&bytes[6..12]); let name = ESWeapon::name_from_bytes(&bytes[6..12]);
ESWeapon { ESWeapon {
esweapon: esweapon, esweapon,
special: special.ok(), special: special.ok(),
grind: grind, grind,
name: name, name,
} }
} }
} }

View File

@ -43,7 +43,7 @@ lazy_static::lazy_static! {
f.read_to_string(&mut s).unwrap(); f.read_to_string(&mut s).unwrap();
let mut feed: HashMap<String, Vec<HashMap<String, MagFeedTable>>> = toml::from_str(&s).unwrap(); let mut feed: HashMap<String, Vec<HashMap<String, MagFeedTable>>> = toml::from_str(&s).unwrap();
let feed = feed.remove("feedtable".into()).unwrap(); let feed = feed.remove("feedtable").unwrap();
feed.into_iter() feed.into_iter()
.map(|table| { .map(|table| {
table.into_iter() table.into_iter()
@ -624,7 +624,7 @@ impl Mag {
fn photon_blast_count(&self) -> u8 { fn photon_blast_count(&self) -> u8 {
let mut count = 0; let mut count = 0;
for i in 0..3 { for i in 0..3 {
if let Some(_) = self.photon_blast[i] { if self.photon_blast[i].is_some() {
count |= 1 << i count |= 1 << i
}; };
} }
@ -633,7 +633,7 @@ impl Mag {
pub fn from_bytes(data: [u8; 16]) -> Result<Mag, ItemParseError> { pub fn from_bytes(data: [u8; 16]) -> Result<Mag, ItemParseError> {
let m = MagType::parse_type([data[0], data[1], data[2]]); let m = MagType::parse_type([data[0], data[1], data[2]]);
if m.is_ok() { if let Ok(m) = m {
let mut def = u16::from_le_bytes([data[4], data[5]]); let mut def = u16::from_le_bytes([data[4], data[5]]);
let mut pow = u16::from_le_bytes([data[6], data[7]]); let mut pow = u16::from_le_bytes([data[6], data[7]]);
let mut dex = u16::from_le_bytes([data[8], data[9]]); let mut dex = u16::from_le_bytes([data[8], data[9]]);
@ -650,13 +650,13 @@ impl Mag {
let iq = data[13] % 201; // TODO: handle invalid values. let iq = data[13] % 201; // TODO: handle invalid values.
Ok(Mag{ Ok(Mag{
mag: m.unwrap(), mag: m,
def: def, def,
pow: pow, pow,
dex: dex, dex,
mnd: mind, mnd: mind,
synchro: sync, synchro: sync,
iq: iq, iq,
photon_blast: [None, None, None], // TODO: actually get PBs from bytes photon_blast: [None, None, None], // TODO: actually get PBs from bytes
color: data[15] % 18, color: data[15] % 18,
//modifiers: Vec::new(), //modifiers: Vec::new(),
@ -739,6 +739,7 @@ impl Mag {
} }
}, },
MagType::Vritra => { MagType::Vritra => {
#[allow(clippy::if_same_then_else)]
if self.pow > self.dex && self.pow > self.mnd { if self.pow > self.dex && self.pow > self.mnd {
self.mag = MagType::Sumba self.mag = MagType::Sumba
} }
@ -1004,9 +1005,9 @@ impl Mag {
MAG_STATS.get(&self.mag).map(|stats| { MAG_STATS.get(&self.mag).map(|stats| {
stats.photon_blast.map(|photon_blast| { stats.photon_blast.map(|photon_blast| {
if !self.photon_blast.contains(&Some(photon_blast)) { if !self.photon_blast.contains(&Some(photon_blast)) {
self.photon_blast.iter_mut().find(|k| k.is_none()).map(|pb_slot| { if let Some(pb_slot) = self.photon_blast.iter_mut().find(|k| k.is_none()) {
*pb_slot = Some(photon_blast) *pb_slot = Some(photon_blast)
}); }
} }
}) })
}); });
@ -1038,10 +1039,10 @@ impl Mag {
} }
pub fn bank(&mut self) { pub fn bank(&mut self) {
self.def = self.def & 0xFFFE; self.def &= 0xFFFE;
self.pow = self.pow & 0xFFFE; self.pow &= 0xFFFE;
self.dex = self.dex & 0xFFFE; self.dex &= 0xFFFE;
self.mnd = self.mnd & 0xFFFE; self.mnd &= 0xFFFE;
} }
// TODO: this needs more checks on validity // TODO: this needs more checks on validity

View File

@ -121,13 +121,13 @@ impl ItemDetail {
} }
pub fn parse_item_from_bytes(data: [u8; 16]) -> Option<ItemDropType> { pub fn parse_item_from_bytes(data: [u8; 16]) -> Option<ItemDropType> {
let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(|w| ItemType::Weapon(w)) let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon)
.or(armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(|a| ItemType::Armor(a))) .or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor))
.or(shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(|s| ItemType::Shield(s))) .or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield))
.or(unit::UnitType::parse_type([data[0],data[1],data[2]]).map(|u| ItemType::Unit(u))) .or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit))
.or(mag::MagType::parse_type([data[0],data[1],data[2]]).map(|m| ItemType::Mag(m))) .or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag))
.or(tool::ToolType::parse_type([data[0],data[1],data[2]]).map(|t| ItemType::Tool(t))) .or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool))
.or(esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(|e| ItemType::ESWeapon(e))).ok()?; .or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?;
match item_type { match item_type {
ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)), ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)),

View File

@ -537,9 +537,9 @@ impl Shield {
pub fn from_bytes(data: [u8; 16]) -> Result<Shield, ItemParseError> { pub fn from_bytes(data: [u8; 16]) -> Result<Shield, ItemParseError> {
let s = ShieldType::parse_type([data[0], data[1], data[2]]); let s = ShieldType::parse_type([data[0], data[1], data[2]]);
if s.is_ok() { if let Ok(s) = s {
Ok(Shield{ Ok(Shield{
shield: s.unwrap(), shield: s,
dfp: data[6], dfp: data[6],
evp: data[8], evp: data[8],
}) })

View File

@ -186,36 +186,33 @@ pub enum ToolType {
impl ToolType { impl ToolType {
pub fn is_stackable(&self) -> bool { pub fn is_stackable(&self) -> bool {
match self { matches!(self, ToolType::Monomate |
ToolType::Monomate => true, ToolType::Dimate |
ToolType::Dimate => true, ToolType::Trimate |
ToolType::Trimate => true, ToolType::Monofluid |
ToolType::Monofluid => true, ToolType::Difluid |
ToolType::Difluid => true, ToolType::Trifluid |
ToolType::Trifluid => true, ToolType::SolAtomizer |
ToolType::SolAtomizer => true, ToolType::MoonAtomizer |
ToolType::MoonAtomizer => true, ToolType::StarAtomizer |
ToolType::StarAtomizer => true, ToolType::Antidote |
ToolType::Antidote => true, ToolType::Antiparalysis |
ToolType::Antiparalysis => true, ToolType::Telepipe |
ToolType::Telepipe => true, ToolType::TrapVision |
ToolType::TrapVision => true, ToolType::Monogrinder |
ToolType::Monogrinder => true, ToolType::Digrinder |
ToolType::Digrinder => true, ToolType::Trigrinder |
ToolType::Trigrinder => true, ToolType::PowerMaterial |
ToolType::PowerMaterial => true, ToolType::MindMaterial |
ToolType::MindMaterial => true, ToolType::EvadeMaterial |
ToolType::EvadeMaterial => true, ToolType::HpMaterial |
ToolType::HpMaterial => true, ToolType::TpMaterial |
ToolType::TpMaterial => true, ToolType::DefMaterial |
ToolType::DefMaterial => true, ToolType::LuckMaterial |
ToolType::LuckMaterial => true, ToolType::Addslot |
ToolType::Addslot => true, ToolType::PhotonDrop |
ToolType::PhotonDrop => true, ToolType::PhotonSphere |
ToolType::PhotonSphere => true, ToolType::PhotonCrystal)
ToolType::PhotonCrystal => true,
_ => false,
}
} }
pub fn max_stack(&self) -> usize { pub fn max_stack(&self) -> usize {
@ -252,39 +249,36 @@ impl ToolType {
} }
pub fn is_mag_cell(&self) -> bool { pub fn is_mag_cell(&self) -> bool {
match self { matches!(self, ToolType::CellOfMag502 |
ToolType::CellOfMag502 => true, ToolType::CellOfMag213 |
ToolType::CellOfMag213 => true, ToolType::PartsOfRobochao |
ToolType::PartsOfRobochao => true, ToolType::HeartOfOpaOpa |
ToolType::HeartOfOpaOpa => true, ToolType::HeartOfPian |
ToolType::HeartOfPian => true, ToolType::HeartOfChao |
ToolType::HeartOfChao => true, ToolType::HeartOfAngel |
ToolType::HeartOfAngel => true, ToolType::HeartOfDevil |
ToolType::HeartOfDevil => true, ToolType::KitOfHamburger |
ToolType::KitOfHamburger => true, ToolType::PanthersSpirit |
ToolType::PanthersSpirit => true, ToolType::KitOfMark3 |
ToolType::KitOfMark3 => true, ToolType::KitOfMasterSystem |
ToolType::KitOfMasterSystem => true, ToolType::KitOfGenesis |
ToolType::KitOfGenesis => true, ToolType::KitOfSegaSaturn |
ToolType::KitOfSegaSaturn => true, ToolType::KitOfDreamcast |
ToolType::KitOfDreamcast => true, ToolType::Tablet |
ToolType::Tablet => true, ToolType::DragonScale |
ToolType::DragonScale => true, ToolType::HeavenStrikerCoat |
ToolType::HeavenStrikerCoat => true, ToolType::PioneerParts |
ToolType::PioneerParts => true, ToolType::AmitiesMemo |
ToolType::AmitiesMemo => true, ToolType::HeartOfMorolian |
ToolType::HeartOfMorolian => true, ToolType::RappysBeak |
ToolType::RappysBeak => true, ToolType::YahoosEngine |
ToolType::YahoosEngine => true, ToolType::DPhotonCore |
ToolType::DPhotonCore => true, ToolType::LibertaKit |
ToolType::LibertaKit => true, ToolType::CellOfMag0503 |
ToolType::CellOfMag0503 => true, ToolType::CellOfMag0504 |
ToolType::CellOfMag0504 => true, ToolType::CellOfMag0505 |
ToolType::CellOfMag0505 => true, ToolType::CellOfMag0506 |
ToolType::CellOfMag0506 => true, ToolType::CellOfMag0507)
ToolType::CellOfMag0507 => true,
_ => false,
}
} }
pub fn value(&self) -> [u8; 3] { pub fn value(&self) -> [u8; 3] {
@ -669,9 +663,9 @@ impl Tool {
pub fn from_bytes(data: [u8; 16]) -> Result<Tool, ItemParseError> { pub fn from_bytes(data: [u8; 16]) -> Result<Tool, ItemParseError> {
let t = ToolType::parse_type([data[0], data[1], data[2]]); let t = ToolType::parse_type([data[0], data[1], data[2]]);
if t.is_ok() { if let Ok(t) = t {
Ok(Tool { Ok(Tool {
tool: t.unwrap(), tool: t,
}) })
} }
else { else {

View File

@ -366,7 +366,7 @@ impl Unit {
pub fn from_bytes(data: [u8; 16]) -> Result<Unit, ItemParseError> { pub fn from_bytes(data: [u8; 16]) -> Result<Unit, ItemParseError> {
let u = UnitType::parse_type([data[0], data[1], data[2]]); let u = UnitType::parse_type([data[0], data[1], data[2]]);
if u.is_ok() { if let Ok(u) = u {
let m = match u16::from_le_bytes([data[6], data[7]]) { let m = match u16::from_le_bytes([data[6], data[7]]) {
0x02 => Some(UnitModifier::PlusPlus), 0x02 => Some(UnitModifier::PlusPlus),
0x01 => Some(UnitModifier::Plus), 0x01 => Some(UnitModifier::Plus),
@ -376,7 +376,7 @@ impl Unit {
}; };
Ok(Unit{ Ok(Unit{
unit: u.unwrap(), unit: u,
modifier: m, modifier: m,
}) })
} }

View File

@ -1476,8 +1476,7 @@ impl Weapon {
} }
pub fn apply_modifier(&mut self, modifier: &WeaponModifier) { pub fn apply_modifier(&mut self, modifier: &WeaponModifier) {
match modifier { if let WeaponModifier::Tekked{special, percent, grind} = modifier {
WeaponModifier::Tekked{special, percent, grind} => {
match special { match special {
TekSpecialModifier::Plus => { TekSpecialModifier::Plus => {
self.special = self.special.map(|special| { self.special = self.special.map(|special| {
@ -1515,8 +1514,6 @@ impl Weapon {
} }
self.grind = std::cmp::max(self.grind as i32 + grind, 0) as u8; self.grind = std::cmp::max(self.grind as i32 + grind, 0) as u8;
self.tekked = true; self.tekked = true;
},
_ => {}
} }
} }
@ -1526,7 +1523,7 @@ impl Weapon {
result[3] = self.grind; result[3] = self.grind;
result[4] = self.special.map(|s| s.value()).unwrap_or(0); result[4] = self.special.map(|s| s.value()).unwrap_or(0);
if self.tekked == false { if !self.tekked {
result[4] += 0x80 result[4] += 0x80
}; };
@ -1539,25 +1536,25 @@ impl Weapon {
// TODO: error handling // TODO: error handling
pub fn from_bytes(data: [u8; 16]) -> Result<Weapon, ItemParseError> { pub fn from_bytes(data: [u8; 16]) -> Result<Weapon, ItemParseError> {
let w = WeaponType::parse_type([data[0], data[1], data[2]]); let wep = WeaponType::parse_type([data[0], data[1], data[2]]);
if w.is_ok() { if let Ok(weapon) = wep {
let mut s = None; let mut special = None;
let mut t = true; let mut tekked = true;
let g = data[3]; let grind = data[3];
if data[4] >= 0x81 && data[4] <= 0xA8 { if data[4] >= 0x81 && data[4] <= 0xA8 {
s = WeaponSpecial::from(data[4] - 0x80); special = WeaponSpecial::from(data[4] - 0x80);
t = false; tekked = false;
} }
else if data[4] >= 0x01 && data[4] <= 0x28 { else if data[4] >= 0x01 && data[4] <= 0x28 {
s = WeaponSpecial::from(data[4]); special = WeaponSpecial::from(data[4]);
t = true; tekked = true;
} }
// else { // else {
// return Err(ItemParseError::InvalidSpecial) // return Err(ItemParseError::InvalidSpecial)
// } // }
let mut a = [ let mut attrs = [
None, None,
None, None,
None None
@ -1565,26 +1562,22 @@ impl Weapon {
for i in 0..3 { for i in 0..3 {
if data[2 * (3 + i)] >= 1 && data[2 * (3 + i)] <= 5 { if data[2 * (3 + i)] >= 1 && data[2 * (3 + i)] <= 5 {
a[i] = Some(WeaponAttribute{ attrs[i] = Some(WeaponAttribute{
attr: Attribute::from(data[2 * (3 + i)]).unwrap(), attr: Attribute::from(data[2 * (3 + i)]).unwrap(),
value: data[2 * (3 + i) + 1] as i8, value: data[2 * (3 + i) + 1] as i8,
}); });
} else { } else {
a[i] = None; attrs[i] = None;
// return Err(ItemParseError::InvalidAttribute) // return Err(ItemParseError::InvalidAttribute)
} }
} }
Ok(Weapon { Ok(Weapon {
weapon: w.unwrap(), weapon,
special: s, special,
grind: g, grind,
attrs:[ attrs,
a[0], tekked,
a[1],
a[2],
],
tekked: t,
}) })
} }
else { else {

View File

@ -28,7 +28,7 @@ use crate::entity::item::tool::Tool;
use crate::entity::item::mag::Mag; use crate::entity::item::mag::Mag;
use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel}; use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel};
use crate::login::login::{get_login_status, check_if_already_online}; use crate::login::login::{get_login_status};
use crate::common::interserver::AuthToken; use crate::common::interserver::AuthToken;
pub const CHARACTER_PORT: u16 = 12001; pub const CHARACTER_PORT: u16 = 12001;
@ -86,14 +86,14 @@ impl RecvServerPacket for RecvCharacterPacket {
pub enum SendCharacterPacket { pub enum SendCharacterPacket {
LoginResponse(LoginResponse), LoginResponse(LoginResponse),
LoginWelcome(LoginWelcome), LoginWelcome(LoginWelcome),
SendKeyAndTeamSettings(SendKeyAndTeamSettings), SendKeyAndTeamSettings(Box<SendKeyAndTeamSettings>),
CharAck(CharAck), CharAck(CharAck),
ChecksumAck(ChecksumAck), ChecksumAck(ChecksumAck),
CharacterPreview(CharacterPreview), CharacterPreview(CharacterPreview),
GuildcardDataHeader(GuildcardDataHeader), GuildcardDataHeader(GuildcardDataHeader),
GuildcardDataChunk(Box<GuildcardDataChunk>), GuildcardDataChunk(Box<GuildcardDataChunk>),
ParamDataHeader(ParamDataHeader), ParamDataHeader(ParamDataHeader),
ParamDataChunk(ParamDataChunk), ParamDataChunk(Box<ParamDataChunk>),
Timestamp(Timestamp), Timestamp(Timestamp),
ShipList(ShipList), ShipList(ShipList),
RedirectClient(RedirectClient), RedirectClient(RedirectClient),
@ -148,7 +148,7 @@ fn generate_param_data(path: &str) -> (ParamDataHeader, Vec<u8>) {
} }
(ParamDataHeader { (ParamDataHeader {
files: files files
}, buffer) }, buffer)
} }
@ -285,10 +285,12 @@ async fn new_character<EG: EntityGateway>(entity_gateway: &mut EG, user: &UserAc
}; };
entity_gateway.set_character_inventory(&character.id, &inventory).await?; entity_gateway.set_character_inventory(&character.id, &inventory).await?;
entity_gateway.set_character_bank(&character.id, &BankEntity::default(), BankName("".into())).await?; entity_gateway.set_character_bank(&character.id, &BankEntity::default(), BankName("".into())).await?;
let mut equipped = EquippedEntity::default(); let equipped = EquippedEntity {
equipped.weapon = Some(weapon.id); weapon: Some(weapon.id),
equipped.armor = Some(armor.id); armor: Some(armor.id),
equipped.mag = Some(mag.id); mag: Some(mag.id),
..Default::default()
};
entity_gateway.set_character_equips(&character.id, &equipped).await?; entity_gateway.set_character_equips(&character.id, &equipped).await?;
Ok(()) Ok(())
} }
@ -299,13 +301,13 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
let (param_header, param_data) = generate_param_data("data/param/"); let (param_header, param_data) = generate_param_data("data/param/");
CharacterServerState { CharacterServerState {
entity_gateway: entity_gateway, entity_gateway,
param_header: param_header, param_header,
param_data: param_data, param_data,
clients: HashMap::new(), clients: HashMap::new(),
ships: BTreeMap::new(), ships: BTreeMap::new(),
level_table: CharacterLevelTable::new(), level_table: CharacterLevelTable::default(),
auth_token: auth_token, auth_token,
authenticated_ships: BTreeSet::new(), authenticated_ships: BTreeSet::new(),
ship_sender: BTreeMap::new(), ship_sender: BTreeMap::new(),
connected_clients: BTreeMap::new(), connected_clients: BTreeMap::new(),
@ -336,7 +338,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
self.connected_clients.insert(user.id.clone(), ConnectedClient { self.connected_clients.insert(user.id, ConnectedClient {
ship_id: None, ship_id: None,
expires: None, //Some(chrono::Utc::now() + chrono::Duration::minutes(1)), expires: None, //Some(chrono::Utc::now() + chrono::Duration::minutes(1)),
}); });
@ -368,7 +370,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
let user = client.user.as_ref().unwrap(); let user = client.user.as_ref().unwrap();
let settings = match self.entity_gateway.get_user_settings_by_user(&user).await { let settings = match self.entity_gateway.get_user_settings_by_user(user).await {
Ok(settings) => settings, Ok(settings) => settings,
Err(_) => { Err(_) => {
let user_settings = NewUserSettingsEntity::new(user.id); let user_settings = NewUserSettingsEntity::new(user.id);
@ -378,7 +380,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
let pkt = SendKeyAndTeamSettings::new(settings.settings.key_config, let pkt = SendKeyAndTeamSettings::new(settings.settings.key_config,
settings.settings.joystick_config, 0, 0); settings.settings.joystick_config, 0, 0);
let pkt = SendCharacterPacket::SendKeyAndTeamSettings(pkt); let pkt = SendCharacterPacket::SendKeyAndTeamSettings(Box::new(pkt));
Ok(vec![pkt]) Ok(vec![pkt])
} }
@ -396,7 +398,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
vec![SendCharacterPacket::CharacterPreview(CharacterPreview { vec![SendCharacterPacket::CharacterPreview(CharacterPreview {
slot: select.slot, slot: select.slot,
character: SelectScreenCharacterBuilder::new() character: SelectScreenCharacterBuilder::new()
.character(&char) .character(char)
.level(level) .level(level)
.build() .build()
})] })]
@ -461,7 +463,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
let mut user = client.user.as_mut().unwrap(); let mut user = client.user.as_mut().unwrap();
user.flags = setflag.flags; user.flags = setflag.flags;
self.entity_gateway.save_user(&user).await.unwrap(); self.entity_gateway.save_user(user).await.unwrap();
Ok(None.into_iter()) Ok(None.into_iter())
} }
@ -477,10 +479,10 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
data[..end-start].copy_from_slice(&self.param_data[start..end]); data[..end-start].copy_from_slice(&self.param_data[start..end]);
Ok(vec![SendCharacterPacket::ParamDataChunk( Ok(vec![SendCharacterPacket::ParamDataChunk(
ParamDataChunk { Box::new(ParamDataChunk {
chunk: chunk as u32, chunk: chunk as u32,
data: data, data,
} })
)]) )])
} }
@ -490,7 +492,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
let mut user = client.user.as_mut().unwrap(); let mut user = client.user.as_mut().unwrap();
if user.flags == USERFLAG_NEWCHAR { if user.flags == USERFLAG_NEWCHAR {
new_character(&mut self.entity_gateway, &user, preview).await? new_character(&mut self.entity_gateway, user, preview).await?
} }
if user.flags == USERFLAG_DRESSINGROOM { if user.flags == USERFLAG_DRESSINGROOM {
// TODO: dressing room stuff // TODO: dressing room stuff
@ -499,7 +501,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
client.session.action = SessionAction::SelectCharacter; client.session.action = SessionAction::SelectCharacter;
client.session.character_slot = preview.slot as u8; client.session.character_slot = preview.slot as u8;
user.flags = 0; user.flags = 0;
self.entity_gateway.save_user(&user).await.unwrap(); self.entity_gateway.save_user(user).await.unwrap();
Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_char_select(user.guildcard, Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_char_select(user.guildcard,
user.team_id.unwrap_or(1), user.team_id.unwrap_or(1),
client.session)), client.session)),
@ -512,7 +514,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
fn select_ship(&mut self, id: ClientId, menuselect: &MenuSelect) -> Result<Vec<SendCharacterPacket>, anyhow::Error> { fn select_ship(&mut self, id: ClientId, menuselect: &MenuSelect) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
if menuselect.menu != SHIP_MENU_ID { if menuselect.menu != SHIP_MENU_ID {
Err(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item))?; return Err(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item).into());
} }
if let Some(client) = self.clients.get(&id) { if let Some(client) = self.clients.get(&id) {
@ -856,7 +858,7 @@ mod test {
#[async_std::test] #[async_std::test]
async fn test_character_create() { async fn test_character_create() {
let test_data = InMemoryGateway::new(); let test_data = InMemoryGateway::default();
let mut fake_user = ClientState::new(); let mut fake_user = ClientState::new();
fake_user.user = Some(UserAccountEntity { fake_user.user = Some(UserAccountEntity {
id: UserAccountId(3), id: UserAccountId(3),

View File

@ -101,8 +101,8 @@ pub struct LoginServerState<EG: EntityGateway> {
impl<EG: EntityGateway> LoginServerState<EG> { impl<EG: EntityGateway> LoginServerState<EG> {
pub fn new(entity_gateway: EG, character_server_ip: net::Ipv4Addr) -> LoginServerState<EG> { pub fn new(entity_gateway: EG, character_server_ip: net::Ipv4Addr) -> LoginServerState<EG> {
LoginServerState { LoginServerState {
entity_gateway: entity_gateway, entity_gateway,
character_server_ip: character_server_ip.into(), character_server_ip,
clients: HashMap::new(), clients: HashMap::new(),
} }
} }
@ -164,7 +164,7 @@ impl<EG: EntityGateway> ServerState for LoginServerState<EG> {
if let Some(username) = self.clients.remove(&id) { if let Some(username) = self.clients.remove(&id) {
if let Ok(mut user) = self.entity_gateway.get_user_by_name(username).await { if let Ok(mut user) = self.entity_gateway.get_user_by_name(username).await {
user.at_login = false; user.at_login = false;
self.entity_gateway.save_user(&user).await; self.entity_gateway.save_user(&user).await?;
} }
} }
Ok(Vec::new()) Ok(Vec::new())

View File

@ -1,2 +1,3 @@
#[allow(clippy::module_inception)]
pub mod login; pub mod login;
pub mod character; pub mod character;

View File

@ -1 +1,2 @@
#[allow(clippy::module_inception)]
pub mod patch; pub mod patch;

View File

@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use std::fs; use std::fs;
use std::io; use std::io;
use std::io::{Read}; use std::io::{Read};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use rand::Rng; use rand::Rng;
use crc::{crc32, Hasher32}; use crc::{crc32, Hasher32};
use libpso::{PacketParseError, PSOPacket}; use libpso::{PacketParseError, PSOPacket};
@ -60,7 +60,7 @@ impl PatchFileTree {
PatchFileTree::Directory(dir, files) => { PatchFileTree::Directory(dir, files) => {
v.push(PatchTreeIterItem::Directory(dir.clone())); v.push(PatchTreeIterItem::Directory(dir.clone()));
for file in files { for file in files {
v.append(&mut PatchFileTree::iter_dir(&file)); v.append(&mut PatchFileTree::iter_dir(file));
} }
v.push(PatchTreeIterItem::UpDirectory); v.push(PatchTreeIterItem::UpDirectory);
}, },
@ -146,10 +146,10 @@ pub struct PatchServerState {
impl PatchServerState { impl PatchServerState {
pub fn new(patch_file_tree: PatchFileTree, patch_file_lookup: HashMap<u32, PatchFile>, patch_motd: String) -> PatchServerState { pub fn new(patch_file_tree: PatchFileTree, patch_file_lookup: HashMap<u32, PatchFile>, patch_motd: String) -> PatchServerState {
PatchServerState { PatchServerState {
patch_file_tree: patch_file_tree, patch_file_tree,
patch_file_lookup: patch_file_lookup, patch_file_lookup,
patch_file_info: Vec::new(), patch_file_info: Vec::new(),
patch_motd: patch_motd, patch_motd,
} }
} }
} }
@ -197,7 +197,7 @@ impl ServerState for PatchServerState {
let p = vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)), let p = vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)),
SendPatchPacket::PatchStartList(PatchStartList {}) SendPatchPacket::PatchStartList(PatchStartList {})
]; ];
Box::new(p.into_iter().chain(SendFileIterator::new(&self)).map(move |pkt| (id, pkt))) Box::new(p.into_iter().chain(SendFileIterator::new(self)).map(move |pkt| (id, pkt)))
} }
}) })
} }
@ -214,18 +214,17 @@ fn load_patch_dir(basedir: &str, patchbase: &str, file_ids: &mut HashMap<u32, Pa
let mut dirs = Vec::new(); let mut dirs = Vec::new();
for p in paths { for p in paths {
let path = p.expect("not a real path").path(); let path = p.expect("not a real path").path();
if path.is_dir() {
let patch_path = path.strip_prefix(basedir).unwrap(); let patch_path = path.strip_prefix(basedir).unwrap();
if path.is_dir() {
dirs.push(load_patch_dir(path.to_str().unwrap(), patch_path.to_str().unwrap(), file_ids)); dirs.push(load_patch_dir(path.to_str().unwrap(), patch_path.to_str().unwrap(), file_ids));
} }
else { else {
let patch_path = path.strip_prefix(basedir).unwrap();
files.push(PatchFileTree::File(patch_path.to_path_buf(), file_ids.len() as u32)); files.push(PatchFileTree::File(patch_path.to_path_buf(), file_ids.len() as u32));
let (checksum, size) = get_checksum_and_size(&path).unwrap(); let (checksum, size) = get_checksum_and_size(&path).unwrap();
file_ids.insert(file_ids.len() as u32, PatchFile { file_ids.insert(file_ids.len() as u32, PatchFile {
path: path, path,
checksum: checksum, checksum,
size: size, size,
}); });
} }
} }
@ -264,7 +263,7 @@ fn get_file_list_packets(patch_file_tree: &PatchFileTree) -> Vec<SendPatchPacket
pkts pkts
} }
fn get_checksum_and_size(path: &PathBuf) -> Result<(u32, u32), PatchError> { fn get_checksum_and_size(path: &Path) -> Result<(u32, u32), PatchError> {
let file = fs::File::open(path)?; let file = fs::File::open(path)?;
let size = file.metadata().unwrap().len(); let size = file.metadata().unwrap().len();
let mut crc = crc32::Digest::new(crc32::IEEE); let mut crc = crc32::Digest::new(crc32::IEEE);
@ -307,7 +306,7 @@ impl SendFileIterator {
file_iter: Box::new(state.patch_file_tree.flatten().into_iter().filter(move |file| { file_iter: Box::new(state.patch_file_tree.flatten().into_iter().filter(move |file| {
match file { match file {
PatchTreeIterItem::File(_path, id) => { PatchTreeIterItem::File(_path, id) => {
file_ids_to_update.contains(&id) file_ids_to_update.contains(id)
}, },
_ => true, _ => true,
} }

View File

@ -9,16 +9,18 @@ pub struct CharacterBytesBuilder<'a> {
level: Option<u32>, level: Option<u32>,
} }
impl<'a> Default for CharacterBytesBuilder<'a> {
impl<'a> CharacterBytesBuilder<'a> { fn default() -> CharacterBytesBuilder<'a> {
pub fn new() -> CharacterBytesBuilder<'a> {
CharacterBytesBuilder { CharacterBytesBuilder {
character: None, character: None,
stats: None, stats: None,
level: None, level: None,
} }
} }
}
impl<'a> CharacterBytesBuilder<'a> {
pub fn character(self, character: &'a CharacterEntity) -> CharacterBytesBuilder<'a> { pub fn character(self, character: &'a CharacterEntity) -> CharacterBytesBuilder<'a> {
CharacterBytesBuilder { CharacterBytesBuilder {
character: Some(character), character: Some(character),
@ -53,7 +55,7 @@ impl<'a> CharacterBytesBuilder<'a> {
dfp: stats.dfp + character.materials.def as u16 * 2, dfp: stats.dfp + character.materials.def as u16 * 2,
ata: stats.ata, ata: stats.ata,
lck: stats.lck + character.materials.luck as u16 * 2, lck: stats.lck + character.materials.luck as u16 * 2,
level: level, level,
section_id: character.section_id.into(), section_id: character.section_id.into(),
ch_class: character.char_class.into(), ch_class: character.char_class.into(),
costume: character.appearance.costume, costume: character.appearance.costume,
@ -89,9 +91,8 @@ pub struct FullCharacterBytesBuilder<'a> {
option_flags: Option<u32>, option_flags: Option<u32>,
} }
impl<'a> Default for FullCharacterBytesBuilder<'a> {
impl<'a> FullCharacterBytesBuilder<'a> { fn default() -> FullCharacterBytesBuilder<'a> {
pub fn new() -> FullCharacterBytesBuilder<'a> {
FullCharacterBytesBuilder { FullCharacterBytesBuilder {
character: None, character: None,
stats: None, stats: None,
@ -105,7 +106,10 @@ impl<'a> FullCharacterBytesBuilder<'a> {
option_flags: None, option_flags: None,
} }
} }
}
impl<'a> FullCharacterBytesBuilder<'a> {
pub fn character(self, character: &'a CharacterEntity) -> FullCharacterBytesBuilder<'a> { pub fn character(self, character: &'a CharacterEntity) -> FullCharacterBytesBuilder<'a> {
FullCharacterBytesBuilder { FullCharacterBytesBuilder {
character: Some(character), character: Some(character),
@ -196,9 +200,9 @@ impl<'a> FullCharacterBytesBuilder<'a> {
inventory_items[11].material_count = character.materials.luck as u8; inventory_items[11].material_count = character.materials.luck as u8;
character::FullCharacter { character::FullCharacter {
character: CharacterBytesBuilder::new() character: CharacterBytesBuilder::default()
.character(&character) .character(character)
.stats(&stats) .stats(stats)
.level(level - 1) .level(level - 1)
.build(), .build(),
inventory: character::Inventory { inventory: character::Inventory {
@ -217,7 +221,7 @@ impl<'a> FullCharacterBytesBuilder<'a> {
symbol_chats: *symbol_chat, symbol_chats: *symbol_chat,
tech_menu: *tech_menu, tech_menu: *tech_menu,
bank: bank.as_client_bank_items(), bank: bank.as_client_bank_items(),
option_flags: option_flags, option_flags,
..character::FullCharacter::default() ..character::FullCharacter::default()
} }
} }

View File

@ -170,7 +170,7 @@ impl BoxDropTable {
else { else {
None None
} }
}).nth(0) }).next()
} }
fn random_box_drop<R: Rng>(&self, map_area: &MapArea, rng: &mut R) -> Option<ItemDropType> { fn random_box_drop<R: Rng>(&self, map_area: &MapArea, rng: &mut R) -> Option<ItemDropType> {

View File

@ -232,9 +232,9 @@ impl AttributeTable {
let area_percent_patterns: AreaPercentPatterns = load_data_file(episode, difficulty, section_id, "area_percent_pattern.toml"); let area_percent_patterns: AreaPercentPatterns = load_data_file(episode, difficulty, section_id, "area_percent_pattern.toml");
AttributeTable { AttributeTable {
attribute_rates: attribute_rates, attribute_rates,
percent_rates: percent_rates, percent_rates,
area_percent_patterns: area_percent_patterns, area_percent_patterns,
} }
} }
@ -258,7 +258,7 @@ impl AttributeTable {
let percent = ((value + 1) * 5) as i8; let percent = ((value + 1) * 5) as i8;
Some(WeaponAttribute { Some(WeaponAttribute {
attr: attr, attr,
value: percent value: percent
}) })
} }
@ -266,30 +266,24 @@ impl AttributeTable {
fn attributes<R: Rng>(&self, percent_pattern: &AttributePercentPattern, attribute_rate: &AttributeRate, rng: &mut R) -> [Option<WeaponAttribute>; 3] { fn attributes<R: Rng>(&self, percent_pattern: &AttributePercentPattern, attribute_rate: &AttributeRate, rng: &mut R) -> [Option<WeaponAttribute>; 3] {
let mut percents = vec![ let mut percents = vec![
percent_pattern.attribute1.and_then(|pattern_type| { percent_pattern.attribute1.and_then(|pattern_type| {
self.generate_attribute(&pattern_type, &attribute_rate, rng) self.generate_attribute(&pattern_type, attribute_rate, rng)
}), }),
percent_pattern.attribute2.and_then(|pattern_type| { percent_pattern.attribute2.and_then(|pattern_type| {
self.generate_attribute(&pattern_type, &attribute_rate, rng) self.generate_attribute(&pattern_type, attribute_rate, rng)
}), }),
percent_pattern.attribute3.and_then(|pattern_type| { percent_pattern.attribute3.and_then(|pattern_type| {
self.generate_attribute(&pattern_type, &attribute_rate, rng) self.generate_attribute(&pattern_type, attribute_rate, rng)
}), }),
]; ];
percents.sort_by_key(|p| { percents.sort_by_key(|p| {
match p { p.as_ref().map(|a| a.attr)
Some(a) => Some(a.attr),
None => None,
}
}); });
percents.dedup_by_key(|p| { percents.dedup_by_key(|p| {
match p { p.as_ref().map(|a| a.attr)
Some(a) => Some(a.attr),
None => None,
}
}); });
percents.iter() percents.iter()
.fold(([None; 3], 0), |(mut acc, index), p| { // one day I'll be able to collece into an array .fold(([None; 3], 0), |(mut acc, index), p| { // one day I'll be able to collece into an array
if let Some(_) = p { if p.is_some() {
acc[index] = *p; acc[index] = *p;
(acc, index + 1) (acc, index + 1)
} }
@ -412,7 +406,7 @@ impl GenericWeaponTable {
rank_table.insert(WeaponDropType::Wand, vec![WeaponType::Wand, WeaponType::Staff, WeaponType::Baton, WeaponType::Scepter]); rank_table.insert(WeaponDropType::Wand, vec![WeaponType::Wand, WeaponType::Staff, WeaponType::Baton, WeaponType::Scepter]);
GenericWeaponTable { GenericWeaponTable {
rank_table: rank_table, rank_table,
weapon_ratio: WeaponRatios::new(episode, difficulty, section_id), weapon_ratio: WeaponRatios::new(episode, difficulty, section_id),
grind_rates: GrindRates::new(episode, difficulty, section_id), grind_rates: GrindRates::new(episode, difficulty, section_id),
attribute_table: AttributeTable::new(episode, difficulty, section_id), attribute_table: AttributeTable::new(episode, difficulty, section_id),

View File

@ -152,7 +152,7 @@ impl<R: Rng + SeedableRng> DropTable<R> {
return None; return None;
} }
if let Some(item) = self.rare_table.get_drop(map_area, &monster, &mut self.rng) { if let Some(item) = self.rare_table.get_drop(map_area, monster, &mut self.rng) {
return Some(item); return Some(item);
} }

View File

@ -30,18 +30,17 @@ pub enum RareDropItem {
impl RareDropItem { impl RareDropItem {
pub fn from_string(name: String) -> RareDropItem { pub fn from_string(name: String) -> RareDropItem {
let parse_funcs: [Box<dyn Fn(&String) -> Option<RareDropItem>>; 6] = [ let parse_funcs: [Box<dyn Fn(&String) -> Option<RareDropItem>>; 6] = [
Box::new(|i| Some(RareDropItem::Weapon(str::parse::<WeaponType>(&i).ok()?))), Box::new(|i| Some(RareDropItem::Weapon(str::parse::<WeaponType>(i).ok()?))),
Box::new(|i| Some(RareDropItem::Armor(str::parse::<ArmorType>(&i).ok()?))), Box::new(|i| Some(RareDropItem::Armor(str::parse::<ArmorType>(i).ok()?))),
Box::new(|i| Some(RareDropItem::Shield(str::parse::<ShieldType>(&i).ok()?))), Box::new(|i| Some(RareDropItem::Shield(str::parse::<ShieldType>(i).ok()?))),
Box::new(|i| Some(RareDropItem::Unit(str::parse::<UnitType>(&i).ok()?))), Box::new(|i| Some(RareDropItem::Unit(str::parse::<UnitType>(i).ok()?))),
Box::new(|i| Some(RareDropItem::Tool(str::parse::<ToolType>(&i).ok()?))), Box::new(|i| Some(RareDropItem::Tool(str::parse::<ToolType>(i).ok()?))),
Box::new(|i| Some(RareDropItem::Mag(str::parse::<MagType>(&i).ok()?))), Box::new(|i| Some(RareDropItem::Mag(str::parse::<MagType>(i).ok()?))),
]; ];
for parse in parse_funcs.iter() { for parse in parse_funcs.iter() {
match parse(&name) { if let Some (k) = parse(&name) {
Some(k) => return k, return k
None => {},
} }
} }
@ -88,7 +87,7 @@ impl RareDropTable {
}).collect(); }).collect();
RareDropTable { RareDropTable {
rates: rates, rates,
attribute_table: AttributeTable::new(episode, difficulty, section_id), attribute_table: AttributeTable::new(episode, difficulty, section_id),
armor_stats: GenericArmorTable::new(episode, difficulty, section_id), armor_stats: GenericArmorTable::new(episode, difficulty, section_id),
shield_stats: GenericShieldTable::new(episode, difficulty, section_id), shield_stats: GenericShieldTable::new(episode, difficulty, section_id),
@ -99,7 +98,7 @@ impl RareDropTable {
match item { match item {
RareDropItem::Weapon(weapon) => { RareDropItem::Weapon(weapon) => {
ItemDropType::Weapon(Weapon { ItemDropType::Weapon(Weapon {
weapon: weapon, weapon,
special: None, special: None,
grind: 0, grind: 0,
attrs: self.attribute_table.generate_rare_attributes(map_area, rng), attrs: self.attribute_table.generate_rare_attributes(map_area, rng),
@ -109,7 +108,7 @@ impl RareDropTable {
}, },
RareDropItem::Armor(armor) => { RareDropItem::Armor(armor) => {
ItemDropType::Armor(Armor { ItemDropType::Armor(Armor {
armor: armor, armor,
dfp: self.armor_stats.dfp_modifier(&armor, rng) as u8, dfp: self.armor_stats.dfp_modifier(&armor, rng) as u8,
evp: self.armor_stats.evp_modifier(&armor, rng) as u8, evp: self.armor_stats.evp_modifier(&armor, rng) as u8,
slots: self.armor_stats.slots(map_area, rng) as u8, slots: self.armor_stats.slots(map_area, rng) as u8,
@ -117,20 +116,20 @@ impl RareDropTable {
}, },
RareDropItem::Shield(shield) => { RareDropItem::Shield(shield) => {
ItemDropType::Shield(Shield { ItemDropType::Shield(Shield {
shield: shield, shield,
dfp: self.shield_stats.dfp_modifier(&shield, rng) as u8, dfp: self.shield_stats.dfp_modifier(&shield, rng) as u8,
evp: self.shield_stats.evp_modifier(&shield, rng) as u8, evp: self.shield_stats.evp_modifier(&shield, rng) as u8,
}) })
}, },
RareDropItem::Unit(unit) => { RareDropItem::Unit(unit) => {
ItemDropType::Unit(Unit { ItemDropType::Unit(Unit {
unit: unit, unit,
modifier: None, modifier: None,
}) })
}, },
RareDropItem::Tool(tool) => { RareDropItem::Tool(tool) => {
ItemDropType::Tool(Tool { ItemDropType::Tool(Tool {
tool: tool, tool,
}) })
}, },
RareDropItem::Mag(_mag) => { RareDropItem::Mag(_mag) => {
@ -151,7 +150,7 @@ impl RareDropTable {
else { else {
None None
} }
}).nth(0) }).next()
}) })
} }
} }

View File

@ -172,9 +172,9 @@ pub fn mag_stats() -> HashMap<MagType, MagStats> {
pub fn mag_feed_tables() -> MagFeedTables { pub fn mag_feed_tables() -> MagFeedTables {
let mag_feed_tables: BTreeMap<String, Vec<BTreeMap<String, MagFeedStats>>> = load_data_file("data/item_stats/mag_feed_table.toml"); let mag_feed_tables: BTreeMap<String, Vec<BTreeMap<String, MagFeedStats>>> = load_data_file("data/item_stats/mag_feed_table.toml");
MagFeedTables(mag_feed_tables.get("feedtable").unwrap().into_iter() MagFeedTables(mag_feed_tables.get("feedtable").unwrap().iter()
.map(|feed_table| { .map(|feed_table| {
MagFeedTable(feed_table.into_iter() MagFeedTable(feed_table.iter()
.map(|(tool, feed_stats)| { .map(|(tool, feed_stats)| {
(tool.parse().unwrap(), *feed_stats) (tool.parse().unwrap(), *feed_stats)
}).collect()) }).collect())

View File

@ -167,7 +167,7 @@ impl CharacterBank {
items.sort(); items.sort();
CharacterBank { CharacterBank {
item_id_counter: 0, item_id_counter: 0,
items: items, items,
} }
} }
@ -178,16 +178,15 @@ impl CharacterBank {
self.item_id_counter = base_item_id + self.items.len() as u32 + 1; self.item_id_counter = base_item_id + self.items.len() as u32 + 1;
} }
pub fn get_item_handle_by_id<'a>(&'a mut self, item_id: ClientItemId) -> Option<BankItemHandle<'a>> { pub fn get_item_handle_by_id(&mut self, item_id: ClientItemId) -> Option<BankItemHandle> {
let (index, _) = self.items.iter() let (index, _) = self.items.iter()
.enumerate() .enumerate()
.filter(|(_, item)| { .find(|(_, item)| {
item.item_id() == item_id item.item_id() == item_id
}) })?;
.nth(0)?;
Some(BankItemHandle { Some(BankItemHandle {
bank: self, bank: self,
index: index, index,
}) })
} }
@ -222,8 +221,8 @@ impl CharacterBank {
}, },
}; };
character::BankItem { character::BankItem {
data1: data1, data1,
data2: data2, data2,
item_id: item.item_id().0, item_id: item.item_id().0,
amount: amount as u16, amount: amount as u16,
flags: 1, flags: 1,

View File

@ -162,11 +162,13 @@ impl<'a> FloorItemHandle<'a> {
#[derive(Debug)] #[derive(Debug)]
pub struct RoomFloorItems(Vec<FloorItem>); pub struct RoomFloorItems(Vec<FloorItem>);
impl RoomFloorItems { impl Default for RoomFloorItems {
pub fn new() -> RoomFloorItems { fn default() -> RoomFloorItems {
RoomFloorItems(Vec::new()) RoomFloorItems(Vec::new())
} }
}
impl RoomFloorItems {
pub fn add_item(&mut self, item: FloorItem) { pub fn add_item(&mut self, item: FloorItem) {
self.0.push(item); self.0.push(item);
} }
@ -179,14 +181,14 @@ impl RoomFloorItems {
let index = self.0.iter().position(|item| item.item_id() == item_id)?; let index = self.0.iter().position(|item| item.item_id() == item_id)?;
Some(FloorItemHandle { Some(FloorItemHandle {
floor: self, floor: self,
index: index, index,
}) })
} }
pub fn take_item_by_id(&mut self, item_id: ClientItemId) -> Option<FloorItem> { pub fn take_item_by_id(&mut self, item_id: ClientItemId) -> Option<FloorItem> {
self.0 self.0
.drain_filter(|i| i.item_id() == item_id) .drain_filter(|i| i.item_id() == item_id)
.nth(0) .next()
} }
pub fn drop_individual_inventory_item(&mut self, individual_inventory_item: IndividualInventoryItem, item_drop_location: (MapArea, f32, f32, f32)) -> &IndividualFloorItem { pub fn drop_individual_inventory_item(&mut self, individual_inventory_item: IndividualInventoryItem, item_drop_location: (MapArea, f32, f32, f32)) -> &IndividualFloorItem {
@ -232,7 +234,7 @@ impl RoomFloorItems {
self.0.push(FloorItem::Stacked(StackedFloorItem { self.0.push(FloorItem::Stacked(StackedFloorItem {
entity_ids: consumed_item.entity_ids(), entity_ids: consumed_item.entity_ids(),
item_id: new_item_id, item_id: new_item_id,
tool: tool, tool,
map_area: item_drop_location.0, map_area: item_drop_location.0,
x: item_drop_location.1, x: item_drop_location.1,
y: item_drop_location.2, y: item_drop_location.2,

View File

@ -82,6 +82,11 @@ pub enum InventoryItemAddToError {
ExceedsCapacity, ExceedsCapacity,
} }
#[derive(Error, Debug, Clone)]
#[error("")]
pub enum InventoryAddError {
}
impl InventoryItem { impl InventoryItem {
pub fn entity_ids(&self) -> Vec<ItemEntityId> { pub fn entity_ids(&self) -> Vec<ItemEntityId> {
match self { match self {
@ -153,12 +158,8 @@ impl InventoryItem {
// TODO: result // TODO: result
// TOOD: delete? // TOOD: delete?
pub fn combine_stacks(&mut self, other_stacked_item: &mut StackedFloorItem) { pub fn combine_stacks(&mut self, other_stacked_item: &mut StackedFloorItem) {
match self { if let InventoryItem::Stacked(self_stacked_item) = self {
InventoryItem::Stacked(self_stacked_item) => {
self_stacked_item.entity_ids.append(&mut other_stacked_item.entity_ids); self_stacked_item.entity_ids.append(&mut other_stacked_item.entity_ids);
},
_ => {
}
} }
} }
@ -338,8 +339,8 @@ impl<'a> InventoryItemHandle<'a> {
}) })
.ok_or(InventoryItemConsumeError::InvalidAmount)?; .ok_or(InventoryItemConsumeError::InvalidAmount)?;
Ok(ConsumedItem::Stacked(StackedConsumedItem { Ok(ConsumedItem::Stacked(StackedConsumedItem {
entity_ids: entity_ids, entity_ids,
tool: tool, tool,
})) }))
} }
} }
@ -364,7 +365,7 @@ impl CharacterInventory {
pub fn new(items: Vec<InventoryItem>, equipped: &EquippedEntity) -> CharacterInventory { pub fn new(items: Vec<InventoryItem>, equipped: &EquippedEntity) -> CharacterInventory {
CharacterInventory{ CharacterInventory{
item_id_counter: 0, item_id_counter: 0,
items: items, items,
equipped: equipped.clone(), equipped: equipped.clone(),
} }
} }
@ -393,7 +394,7 @@ impl CharacterInventory {
inventory[slot].data1[4] = self.equipped.unit.iter() inventory[slot].data1[4] = self.equipped.unit.iter()
.enumerate() .enumerate()
.find(|(_, u_id)| **u_id == Some(individual_item.entity_id)) .find(|(_, u_id)| **u_id == Some(individual_item.entity_id))
.map(|(a, b)| a) .map(|(a, _)| a)
.unwrap_or(0) as u8 .unwrap_or(0) as u8
} }
inventory[slot].equipped = 1; inventory[slot].equipped = 1;
@ -412,106 +413,100 @@ impl CharacterInventory {
self.items.len() self.items.len()
} }
pub fn get_item_handle_by_id<'a>(&'a mut self, item_id: ClientItemId) -> Option<InventoryItemHandle<'a>> { pub fn get_item_handle_by_id(&mut self, item_id: ClientItemId) -> Option<InventoryItemHandle> {
let (slot, _) = self.items.iter() let (slot, _) = self.items.iter()
.enumerate() .enumerate()
.filter(|(_, item)| { .find(|(_, item)| {
item.item_id() == item_id item.item_id() == item_id
}) })?;
.nth(0)?;
Some(InventoryItemHandle { Some(InventoryItemHandle {
inventory: self, inventory: self,
slot: slot, slot,
}) })
} }
pub fn get_equipped_mag_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> { pub fn get_equipped_mag_handle(&mut self) -> Option<InventoryItemHandle> {
let (slot, _) = self.items.iter() let (slot, _) = self.items.iter()
.enumerate() .enumerate()
.filter(|(_, item)| { .find(|(_, item)| {
if let InventoryItem::Individual(individual_inventory_item) = item { if let InventoryItem::Individual(individual_inventory_item) = item {
if let ItemDetail::Mag(_) = &individual_inventory_item.item { if let ItemDetail::Mag(_) = &individual_inventory_item.item {
return self.equipped.is_equipped(&individual_inventory_item.entity_id) return self.equipped.is_equipped(&individual_inventory_item.entity_id)
} }
} }
false false
}) })?;
.nth(0)?;
Some(InventoryItemHandle { Some(InventoryItemHandle {
inventory: self, inventory: self,
slot: slot, slot,
}) })
} }
pub fn get_equipped_armor_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> { pub fn get_equipped_armor_handle(&mut self) -> Option<InventoryItemHandle> {
let (slot, _) = self.items.iter() let (slot, _) = self.items.iter()
.enumerate() .enumerate()
.filter(|(_, item)| { .find(|(_, item)| {
if let InventoryItem::Individual(individual_inventory_item) = item { if let InventoryItem::Individual(individual_inventory_item) = item {
if let ItemDetail::Armor(_) = &individual_inventory_item.item { if let ItemDetail::Armor(_) = &individual_inventory_item.item {
return self.equipped.is_equipped(&individual_inventory_item.entity_id) return self.equipped.is_equipped(&individual_inventory_item.entity_id)
} }
} }
false false
}) })?;
.nth(0)?;
Some(InventoryItemHandle { Some(InventoryItemHandle {
inventory: self, inventory: self,
slot: slot, slot,
}) })
} }
pub fn get_equipped_shield_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> { pub fn get_equipped_shield_handle(&mut self) -> Option<InventoryItemHandle> {
let (slot, _) = self.items.iter() let (slot, _) = self.items.iter()
.enumerate() .enumerate()
.filter(|(_, item)| { .find(|(_, item)| {
if let InventoryItem::Individual(individual_inventory_item) = item { if let InventoryItem::Individual(individual_inventory_item) = item {
if let ItemDetail::Shield(_) = &individual_inventory_item.item { if let ItemDetail::Shield(_) = &individual_inventory_item.item {
return self.equipped.is_equipped(&individual_inventory_item.entity_id) return self.equipped.is_equipped(&individual_inventory_item.entity_id)
} }
} }
false false
}) })?;
.nth(0)?;
Some(InventoryItemHandle { Some(InventoryItemHandle {
inventory: self, inventory: self,
slot: slot, slot,
}) })
} }
pub fn get_equipped_weapon_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> { pub fn get_equipped_weapon_handle(&mut self) -> Option<InventoryItemHandle> {
let (slot, _) = self.items.iter() let (slot, _) = self.items.iter()
.enumerate() .enumerate()
.filter(|(_, item)| { .find(|(_, item)| {
if let InventoryItem::Individual(individual_inventory_item) = item { if let InventoryItem::Individual(individual_inventory_item) = item {
if let ItemDetail::Weapon(_) = &individual_inventory_item.item { if let ItemDetail::Weapon(_) = &individual_inventory_item.item {
return self.equipped.is_equipped(&individual_inventory_item.entity_id) return self.equipped.is_equipped(&individual_inventory_item.entity_id)
} }
} }
false false
}) })?;
.nth(0)?;
Some(InventoryItemHandle { Some(InventoryItemHandle {
inventory: self, inventory: self,
slot: slot, slot,
}) })
} }
pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&InventoryItem> { pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&InventoryItem> {
self.items.iter() self.items.iter()
.filter(|item| { .find(|item| {
item.item_id() == item_id item.item_id() == item_id
}) })
.nth(0)
} }
pub fn take_item_by_id(&mut self, item_id: ClientItemId) -> Option<InventoryItem> { pub fn take_item_by_id(&mut self, item_id: ClientItemId) -> Option<InventoryItem> {
self.items self.items
.drain_filter(|i| i.item_id() == item_id) .drain_filter(|i| i.item_id() == item_id)
.nth(0) .next()
} }
pub fn add_item(&mut self, item: InventoryItem) -> Result<(), ()> { // TODO: errors pub fn add_item(&mut self, item: InventoryItem) -> Result<(), InventoryAddError> { // TODO: errors
// TODO: check slot conflict? // TODO: check slot conflict?
self.items.push(item); self.items.push(item);
Ok(()) Ok(())

View File

@ -1,12 +1,11 @@
use crate::ship::items::ClientItemId; use crate::ship::items::ClientItemId;
use std::collections::{HashMap, BTreeMap}; use std::collections::HashMap;
use thiserror::Error; use thiserror::Error;
use crate::entity::gateway::EntityGateway; use crate::entity::gateway::EntityGateway;
use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel}; use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel};
use crate::entity::item::{ItemDetail, ItemLocation, BankName}; use crate::entity::item::{ItemDetail, ItemLocation, BankName};
use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, EquippedEntity, InventoryEntity, BankItemEntity, BankEntity}; use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, BankItemEntity};
use crate::entity::item::tool::{Tool, ToolType}; use crate::entity::item::tool::{Tool, ToolType};
use crate::entity::item::unit;
use crate::entity::item::weapon; use crate::entity::item::weapon;
use crate::ship::map::MapArea; use crate::ship::map::MapArea;
use crate::ship::ship::ItemDropLocation; use crate::ship::ship::ItemDropLocation;
@ -71,8 +70,8 @@ pub struct ItemManager {
room_item_id_counter: HashMap<RoomId, Box<dyn FnMut() -> ClientItemId + Send>>, room_item_id_counter: HashMap<RoomId, Box<dyn FnMut() -> ClientItemId + Send>>,
} }
impl ItemManager { impl Default for ItemManager {
pub fn new() -> ItemManager { fn default() -> ItemManager {
ItemManager { ItemManager {
id_counter: 0, id_counter: 0,
character_inventory: HashMap::new(), character_inventory: HashMap::new(),
@ -83,7 +82,9 @@ impl ItemManager {
room_item_id_counter: HashMap::new(), room_item_id_counter: HashMap::new(),
} }
} }
}
impl ItemManager {
pub fn next_global_item_id(&mut self) -> ClientItemId { pub fn next_global_item_id(&mut self) -> ClientItemId {
self.id_counter += 1; self.id_counter += 1;
ClientItemId(self.id_counter) ClientItemId(self.id_counter)
@ -110,11 +111,11 @@ impl ItemManager {
entity_ids: items.iter().map(|i| i.id).collect(), entity_ids: items.iter().map(|i| i.id).collect(),
item_id: self.next_global_item_id(), item_id: self.next_global_item_id(),
tool: items.get(0) tool: items.get(0)
.ok_or(ItemManagerError::StackedItemError(items.clone()))? .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))?
.item .item
.clone() .clone()
.as_tool() .as_tool()
.ok_or(ItemManagerError::StackedItemError(items.clone()))? .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))?
}) })
}, },
}) })
@ -137,11 +138,11 @@ impl ItemManager {
entity_ids: items.iter().map(|i| i.id).collect(), entity_ids: items.iter().map(|i| i.id).collect(),
item_id: self.next_global_item_id(), item_id: self.next_global_item_id(),
tool: items.get(0) tool: items.get(0)
.ok_or(ItemManagerError::StackedItemError(items.clone()))? .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))?
.item .item
.clone() .clone()
.as_tool() .as_tool()
.ok_or(ItemManagerError::StackedItemError(items.clone()))? .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))?
}) })
}, },
}) })
@ -160,18 +161,15 @@ impl ItemManager {
inventory.initialize_item_ids(base_inventory_id); inventory.initialize_item_ids(base_inventory_id);
let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000; let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000;
let default_bank = self.character_bank.get_mut(&character.id); let default_bank = self.character_bank.get_mut(&character.id);
match default_bank { if let Some(default_bank ) = default_bank {
Some(default_bank) => {
default_bank.initialize_item_ids(base_bank_id); default_bank.initialize_item_ids(base_bank_id);
},
None => {},
} }
self.character_room.insert(character.id, room_id); self.character_room.insert(character.id, room_id);
self.character_floor.insert(character.id, RoomFloorItems::new()); self.character_floor.insert(character.id, RoomFloorItems::default());
self.room_floor.entry(room_id).or_insert(RoomFloorItems::new()); self.room_floor.entry(room_id).or_insert_with(RoomFloorItems::default);
let mut inc = 0x00810000; let mut inc = 0x00810000;
self.room_item_id_counter.entry(room_id).or_insert(Box::new(move || { self.room_item_id_counter.entry(room_id).or_insert_with(|| Box::new(move || {
inc += 1; inc += 1;
ClientItemId(inc) ClientItemId(inc)
})); }));
@ -202,13 +200,11 @@ impl ItemManager {
pub fn remove_character_from_room(&mut self, character: &CharacterEntity) { pub fn remove_character_from_room(&mut self, character: &CharacterEntity) {
self.character_inventory.remove(&character.id); self.character_inventory.remove(&character.id);
self.character_floor.remove(&character.id); self.character_floor.remove(&character.id);
self.character_room.remove(&character.id) if let Some(room) = self.character_room.remove(&character.id).as_ref() {
.as_ref() if self.character_room.iter().any(|(_, r)| r == room) {
.map(|room| {
if self.character_room.iter().find(|(_, r)| *r == room).is_none() {
self.room_floor.remove(room); self.room_floor.remove(room);
} }
}); }
} }
pub fn get_floor_item_by_id(&self, character: &CharacterEntity, item_id: ClientItemId) -> Result<(&FloorItem, FloorType), anyhow::Error> { pub fn get_floor_item_by_id(&self, character: &CharacterEntity, item_id: ClientItemId) -> Result<(&FloorItem, FloorType), anyhow::Error> {
@ -220,7 +216,7 @@ impl ItemManager {
.or_else(|| { .or_else(|| {
shared_floor.get_item_by_id(item_id).map(|item| (item, FloorType::Shared)) shared_floor.get_item_by_id(item_id).map(|item| (item, FloorType::Shared))
}) })
.ok_or(ItemManagerError::NoSuchItemId(item_id).into()) .ok_or_else(|| ItemManagerError::NoSuchItemId(item_id).into())
} }
pub async fn character_picks_up_item<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &mut CharacterEntity, item_id: ClientItemId) pub async fn character_picks_up_item<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &mut CharacterEntity, item_id: ClientItemId)
@ -228,7 +224,7 @@ impl ItemManager {
let local_floor = self.character_floor.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let local_floor = self.character_floor.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let shared_floor = self.room_floor.get_mut(&room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let floor_item = local_floor.get_item_handle_by_id(item_id) let floor_item = local_floor.get_item_handle_by_id(item_id)
.or_else(|| { .or_else(|| {
@ -238,16 +234,16 @@ impl ItemManager {
let trigger_create_item = match floor_item.item() { let trigger_create_item = match floor_item.item() {
Some(FloorItem::Individual(individual_floor_item)) => { Some(FloorItem::Individual(individual_floor_item)) => {
let new_inventory_item = inventory.pick_up_individual_floor_item(&individual_floor_item); let new_inventory_item = inventory.pick_up_individual_floor_item(individual_floor_item);
match new_inventory_item { match new_inventory_item {
Some((new_inventory_item, slot)) => { Some((new_inventory_item, _slot)) => {
entity_gateway.change_item_location( entity_gateway.change_item_location(
&new_inventory_item.entity_id, &new_inventory_item.entity_id,
ItemLocation::Inventory { ItemLocation::Inventory {
character_id: character.id, character_id: character.id,
} }
).await?; ).await?;
if let Some(_) = new_inventory_item.mag() { if new_inventory_item.mag().is_some() {
entity_gateway.change_mag_owner(&new_inventory_item.entity_id, character).await?; entity_gateway.change_mag_owner(&new_inventory_item.entity_id, character).await?;
} }
}, },
@ -258,13 +254,13 @@ impl ItemManager {
TriggerCreateItem::Yes TriggerCreateItem::Yes
}, },
Some(FloorItem::Stacked(stacked_floor_item)) => { Some(FloorItem::Stacked(stacked_floor_item)) => {
let new_inventory_item = inventory.pick_up_stacked_floor_item(&stacked_floor_item); let new_inventory_item = inventory.pick_up_stacked_floor_item(stacked_floor_item);
match new_inventory_item { match new_inventory_item {
Some((new_inventory_item, slot)) => { Some((new_inventory_item, _slot)) => {
for entity_id in &new_inventory_item.entity_ids { for entity_id in &new_inventory_item.entity_ids {
entity_gateway.change_item_location( entity_gateway.change_item_location(
&entity_id, entity_id,
ItemLocation::Inventory { ItemLocation::Inventory {
character_id: character.id, character_id: character.id,
} }
@ -288,7 +284,7 @@ impl ItemManager {
return Err(ItemManagerError::CouldNotAddToInventory(item_id).into()); return Err(ItemManagerError::CouldNotAddToInventory(item_id).into());
} }
character.meseta = std::cmp::min(character.meseta + meseta_floor_item.meseta.0, 999999); character.meseta = std::cmp::min(character.meseta + meseta_floor_item.meseta.0, 999999);
entity_gateway.save_character(&character).await?; entity_gateway.save_character(character).await?;
TriggerCreateItem::No TriggerCreateItem::No
}, },
None => { None => {
@ -340,7 +336,7 @@ impl ItemManager {
}).await?; }).await?;
FloorItem::Individual(IndividualFloorItem { FloorItem::Individual(IndividualFloorItem {
entity_id: entity.id, entity_id: entity.id,
item_id: item_id, item_id,
item: item_detail, item: item_detail,
map_area: item_drop.map_area, map_area: item_drop.map_area,
x: item_drop.x, x: item_drop.x,
@ -361,8 +357,8 @@ impl ItemManager {
}).await?; }).await?;
FloorItem::Stacked(StackedFloorItem { FloorItem::Stacked(StackedFloorItem {
entity_ids: vec![entity.id], entity_ids: vec![entity.id],
item_id: item_id, item_id,
tool: tool, tool,
map_area: item_drop.map_area, map_area: item_drop.map_area,
x: item_drop.x, x: item_drop.x,
y: item_drop.y, y: item_drop.y,
@ -371,8 +367,8 @@ impl ItemManager {
}, },
ItemOrMeseta::Meseta(meseta) => { ItemOrMeseta::Meseta(meseta) => {
FloorItem::Meseta(MesetaFloorItem { FloorItem::Meseta(MesetaFloorItem {
item_id: item_id, item_id,
meseta: meseta, meseta,
map_area: item_drop.map_area, map_area: item_drop.map_area,
x: item_drop.x, x: item_drop.x,
y: item_drop.y, y: item_drop.y,
@ -381,9 +377,9 @@ impl ItemManager {
}, },
}; };
self.character_floor.entry(character.id).or_insert(RoomFloorItems::new()).add_item(floor_item); self.character_floor.entry(character.id).or_insert_with(RoomFloorItems::default).add_item(floor_item);
// TODO: make these real errors // TODO: make these real errors
self.character_floor.get(&character.id).ok_or(ItemManagerError::Idunnoman)?.get_item_by_id(item_id).ok_or(ItemManagerError::Idunnoman.into()) self.character_floor.get(&character.id).ok_or(ItemManagerError::Idunnoman)?.get_item_by_id(item_id).ok_or_else(|| ItemManagerError::Idunnoman.into())
} }
pub async fn player_drop_item_on_shared_floor<EG: EntityGateway>(&mut self, pub async fn player_drop_item_on_shared_floor<EG: EntityGateway>(&mut self,
@ -395,7 +391,7 @@ impl ItemManager {
-> Result<(), anyhow::Error> { -> Result<(), anyhow::Error> {
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let shared_floor = self.room_floor.get_mut(&room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let dropped_inventory_item = inventory.take_item_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; let dropped_inventory_item = inventory.take_item_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?;
@ -439,16 +435,16 @@ impl ItemManager {
amount: u32) amount: u32)
-> Result<FloorItem, anyhow::Error> { -> Result<FloorItem, anyhow::Error> {
let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let shared_floor = self.room_floor.get_mut(&room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?;
if character.meseta < amount { if character.meseta < amount {
return Err(ItemManagerError::CouldNotDropMeseta.into()) return Err(ItemManagerError::CouldNotDropMeseta.into())
} }
character.meseta -= amount; character.meseta -= amount;
entity_gateway.save_character(&character).await?; entity_gateway.save_character(character).await?;
let item_id = self.room_item_id_counter.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); let item_id = self.room_item_id_counter.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?();
let floor_item = FloorItem::Meseta(MesetaFloorItem { let floor_item = FloorItem::Meseta(MesetaFloorItem {
item_id: item_id, item_id,
meseta: Meseta(amount), meseta: Meseta(amount),
map_area: drop_location.map_area, map_area: drop_location.map_area,
x: drop_location.x, x: drop_location.x,
@ -470,7 +466,7 @@ impl ItemManager {
-> Result<&StackedFloorItem, anyhow::Error> { -> Result<&StackedFloorItem, anyhow::Error> {
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let shared_floor = self.room_floor.get_mut(&room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let item_to_split = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; let item_to_split = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?;
@ -574,13 +570,13 @@ impl ItemManager {
let inventory_item = inventory.withdraw_item(item_to_withdraw, amount).ok_or(ItemManagerError::Idunnoman)?; let inventory_item = inventory.withdraw_item(item_to_withdraw, amount).ok_or(ItemManagerError::Idunnoman)?;
match inventory_item { match inventory_item {
(InventoryItem::Individual(individual_inventory_item), slot) => { (InventoryItem::Individual(individual_inventory_item), _slot) => {
entity_gateway.change_item_location(&individual_inventory_item.entity_id, entity_gateway.change_item_location(&individual_inventory_item.entity_id,
ItemLocation::Inventory { ItemLocation::Inventory {
character_id: character.id, character_id: character.id,
}).await?; }).await?;
}, },
(InventoryItem::Stacked(stacked_inventory_item), slot) => { (InventoryItem::Stacked(stacked_inventory_item), _slot) => {
for entity_id in &stacked_inventory_item.entity_ids { for entity_id in &stacked_inventory_item.entity_ids {
entity_gateway.change_item_location(entity_id, entity_gateway.change_item_location(entity_id,
ItemLocation::Inventory { ItemLocation::Inventory {
@ -594,7 +590,7 @@ impl ItemManager {
entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
entity_gateway.set_character_bank(&character.id, &bank.as_bank_entity(&character.id, &BankName("".into())), BankName("".into())).await?; entity_gateway.set_character_bank(&character.id, &bank.as_bank_entity(&character.id, &BankName("".into())), BankName("".into())).await?;
inventory.slot(inventory_item_slot).ok_or(ItemManagerError::Idunnoman.into()) inventory.slot(inventory_item_slot).ok_or_else(|| ItemManagerError::Idunnoman.into())
} }
pub async fn player_feeds_mag_item<EG: EntityGateway>(&mut self, pub async fn player_feeds_mag_item<EG: EntityGateway>(&mut self,
@ -771,8 +767,8 @@ impl ItemManager {
} }
let floor_item = StackedFloorItem { let floor_item = StackedFloorItem {
entity_ids: item_entities.into_iter().map(|i| i.id).collect(), entity_ids: item_entities.into_iter().map(|i| i.id).collect(),
item_id: item_id, item_id,
tool: tool, tool,
// TODO: this is gonna choke if I ever require the item being near the player for pickup // TODO: this is gonna choke if I ever require the item being near the player for pickup
map_area: MapArea::Pioneer2Ep1, map_area: MapArea::Pioneer2Ep1,
x: 0.0, x: 0.0,
@ -780,7 +776,7 @@ impl ItemManager {
z: 0.0, z: 0.0,
}; };
let item_id = { let item_id = {
let (picked_up_item, slot) = inventory.pick_up_stacked_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; let (picked_up_item, _slot) = inventory.pick_up_stacked_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?;
for entity_id in &picked_up_item.entity_ids { for entity_id in &picked_up_item.entity_ids {
entity_gateway.change_item_location(entity_id, entity_gateway.change_item_location(entity_id,
ItemLocation::Inventory { ItemLocation::Inventory {
@ -798,7 +794,7 @@ impl ItemManager {
}).await?; }).await?;
let floor_item = IndividualFloorItem { let floor_item = IndividualFloorItem {
entity_id: item_entity.id, entity_id: item_entity.id,
item_id: item_id, item_id,
item: ItemDetail::Tool(tool), item: ItemDetail::Tool(tool),
// TODO: this is gonna choke if I ever require the item being near the player for pickup // TODO: this is gonna choke if I ever require the item being near the player for pickup
map_area: MapArea::Pioneer2Ep1, map_area: MapArea::Pioneer2Ep1,
@ -807,7 +803,7 @@ impl ItemManager {
z: 0.0, z: 0.0,
}; };
let item_id = { let item_id = {
let (picked_up_item, slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; let (picked_up_item, _slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?;
entity_gateway.change_item_location(&picked_up_item.entity_id, entity_gateway.change_item_location(&picked_up_item.entity_id,
ItemLocation::Inventory { ItemLocation::Inventory {
character_id: character.id, character_id: character.id,
@ -817,14 +813,14 @@ impl ItemManager {
inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))?
} }
}, },
item_detail @ _ => { item_detail => {
let item_entity = entity_gateway.create_item(NewItemEntity { let item_entity = entity_gateway.create_item(NewItemEntity {
location: ItemLocation::Shop, location: ItemLocation::Shop,
item: item_detail.clone(), item: item_detail.clone(),
}).await?; }).await?;
let floor_item = IndividualFloorItem { let floor_item = IndividualFloorItem {
entity_id: item_entity.id, entity_id: item_entity.id,
item_id: item_id, item_id,
item: item_detail, item: item_detail,
// TODO: this is gonna choke if I ever require the item being near the player for pickup // TODO: this is gonna choke if I ever require the item being near the player for pickup
map_area: MapArea::Pioneer2Ep1, map_area: MapArea::Pioneer2Ep1,
@ -833,7 +829,7 @@ impl ItemManager {
z: 0.0, z: 0.0,
}; };
let item_id = { let item_id = {
let (picked_up_item, slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; let (picked_up_item, _slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?;
entity_gateway.change_item_location(&picked_up_item.entity_id, entity_gateway.change_item_location(&picked_up_item.entity_id,
ItemLocation::Inventory { ItemLocation::Inventory {
character_id: character.id, character_id: character.id,
@ -881,7 +877,7 @@ impl ItemManager {
let sorted_inventory_items: Vec<InventoryItem> = item_ids.iter() let sorted_inventory_items: Vec<InventoryItem> = item_ids.iter()
.filter(|&client_item_id| *client_item_id < 0xFFFFFFFF) .filter(|&client_item_id| *client_item_id < 0xFFFFFFFF)
.map(|&client_item_id| inventory.get_item_by_id(ClientItemId(client_item_id))) .map(|&client_item_id| inventory.get_item_by_id(ClientItemId(client_item_id)))
.filter(|&x| x.is_some() == true) .filter(|&x| x.is_some())
.map(|x| x.cloned().unwrap()) .map(|x| x.cloned().unwrap())
.collect(); .collect();
@ -914,10 +910,10 @@ impl ItemManager {
entity_gateway.add_weapon_modifier(&entity_id, tek).await?; entity_gateway.add_weapon_modifier(&entity_id, tek).await?;
inventory.add_item(InventoryItem::Individual(IndividualInventoryItem { inventory.add_item(InventoryItem::Individual(IndividualInventoryItem {
entity_id: entity_id, entity_id,
item_id: item_id, item_id,
item: ItemDetail::Weapon(weapon.clone()), item: ItemDetail::Weapon(weapon.clone()),
})); }))?;
entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;

View File

@ -155,8 +155,7 @@ impl ClientLocation {
let l = self.lobbies.get_mut(lobby.0).ok_or(JoinLobbyError::LobbyDoesNotExist)?; let l = self.lobbies.get_mut(lobby.0).ok_or(JoinLobbyError::LobbyDoesNotExist)?;
let (index, empty_slot) = l.0.iter_mut() let (index, empty_slot) = l.0.iter_mut()
.enumerate() .enumerate()
.filter(|(_, k)| k.is_none()) .find(|(_, k)| k.is_none())
.nth(0)
.ok_or(JoinLobbyError::LobbyFull)?; .ok_or(JoinLobbyError::LobbyFull)?;
*empty_slot = Some(AreaClient { *empty_slot = Some(AreaClient {
client: id, client: id,
@ -173,10 +172,9 @@ impl ClientLocation {
let new_lobby = LobbyId((lobby.0 + lobby_index) % 15); let new_lobby = LobbyId((lobby.0 + lobby_index) % 15);
(new_lobby, self.add_client_to_lobby(id, new_lobby)) (new_lobby, self.add_client_to_lobby(id, new_lobby))
}) })
.filter(|(_, lobby_option)| { .find(|(_, lobby_option)| {
lobby_option.is_ok() lobby_option.is_ok()
}) })
.nth(0)
.ok_or(JoinLobbyError::LobbyFull)?; .ok_or(JoinLobbyError::LobbyFull)?;
Ok(l.0) Ok(l.0)
@ -185,8 +183,7 @@ impl ClientLocation {
pub fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> { pub fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
let (index, empty_slot) = self.rooms.iter_mut() let (index, empty_slot) = self.rooms.iter_mut()
.enumerate() .enumerate()
.filter(|(_, r)| r.is_none()) .find(|(_, r)| r.is_none())
.nth(0)
.ok_or(CreateRoomError::NoOpenSlots)?; .ok_or(CreateRoomError::NoOpenSlots)?;
*empty_slot = Some(Room([None; 4])); *empty_slot = Some(Room([None; 4]));
self.add_client_to_room(id, RoomId(index)).map_err(|_err| CreateRoomError::JoinError)?; self.add_client_to_room(id, RoomId(index)).map_err(|_err| CreateRoomError::JoinError)?;
@ -201,8 +198,7 @@ impl ClientLocation {
.ok_or(JoinRoomError::RoomDoesNotExist)?; .ok_or(JoinRoomError::RoomDoesNotExist)?;
let (index, empty_slot) = r.0.iter_mut() let (index, empty_slot) = r.0.iter_mut()
.enumerate() .enumerate()
.filter(|(_, k)| k.is_none()) .find(|(_, k)| k.is_none())
.nth(0)
.ok_or(JoinRoomError::RoomFull)?; .ok_or(JoinRoomError::RoomFull)?;
*empty_slot = Some(AreaClient { *empty_slot = Some(AreaClient {
client: id, client: id,
@ -252,7 +248,7 @@ impl ClientLocation {
let mut r = self.rooms[room.0] let mut r = self.rooms[room.0]
.as_ref() .as_ref()
.ok_or(GetLeaderError::InvalidArea)? .ok_or(GetLeaderError::InvalidArea)?
.0.iter().flat_map(|k| k) .0.iter().flatten()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
r.sort_by_key(|k| k.time_join); r.sort_by_key(|k| k.time_join);
let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?; let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?;
@ -261,7 +257,7 @@ impl ClientLocation {
pub fn get_lobby_leader(&self, lobby: LobbyId) -> Result<AreaClient, GetLeaderError> { pub fn get_lobby_leader(&self, lobby: LobbyId) -> Result<AreaClient, GetLeaderError> {
let mut l = self.lobbies[lobby.0] let mut l = self.lobbies[lobby.0]
.0.iter().flat_map(|k| k) .0.iter().flatten()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
l.sort_by_key(|k| k.time_join); l.sort_by_key(|k| k.time_join);
let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?; let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?;
@ -319,15 +315,13 @@ impl ClientLocation {
RoomLobby::Room(room) => { RoomLobby::Room(room) => {
self.get_clients_in_room(*room).map_err(|_| GetClientsError::InvalidArea)? self.get_clients_in_room(*room).map_err(|_| GetClientsError::InvalidArea)?
.into_iter() .into_iter()
.filter(|c| c.client == id) .find(|c| c.client == id)
.nth(0)
.ok_or(GetClientsError::InvalidClient) .ok_or(GetClientsError::InvalidClient)
}, },
RoomLobby::Lobby(lobby) => { RoomLobby::Lobby(lobby) => {
self.get_clients_in_lobby(*lobby).map_err(|_| GetClientsError::InvalidArea)? self.get_clients_in_lobby(*lobby).map_err(|_| GetClientsError::InvalidArea)?
.into_iter() .into_iter()
.filter(|c| c.client == id) .find(|c| c.client == id)
.nth(0)
.ok_or(GetClientsError::InvalidClient) .ok_or(GetClientsError::InvalidClient)
} }
} }
@ -361,8 +355,10 @@ impl ClientLocation {
let area = self.client_location.get_mut(&id).ok_or(ClientRemovalError::ClientNotInArea)?; let area = self.client_location.get_mut(&id).ok_or(ClientRemovalError::ClientNotInArea)?;
let client_list = match area { let client_list = match area {
RoomLobby::Room(room) => { RoomLobby::Room(room) => {
self.rooms[room.0].as_mut().map_or(None, |r| { self.rooms[room.0]
Some(r.0.iter_mut()) .as_mut()
.map(|r| {
r.0.iter_mut()
}) })
}, },
RoomLobby::Lobby(lobby) => { RoomLobby::Lobby(lobby) => {

View File

@ -291,13 +291,15 @@ pub struct MapAreaLookupBuilder {
map_areas: HashMap<u16, MapArea>, map_areas: HashMap<u16, MapArea>,
} }
impl MapAreaLookupBuilder { impl Default for MapAreaLookupBuilder {
pub fn new() -> MapAreaLookupBuilder { fn default() -> MapAreaLookupBuilder {
MapAreaLookupBuilder { MapAreaLookupBuilder {
map_areas: HashMap::new() map_areas: HashMap::new()
} }
} }
}
impl MapAreaLookupBuilder {
pub fn add(mut self, value: u16, map_area: MapArea) -> MapAreaLookupBuilder { pub fn add(mut self, value: u16, map_area: MapArea) -> MapAreaLookupBuilder {
self.map_areas.insert(value, map_area); self.map_areas.insert(value, map_area);
self self

View File

@ -252,8 +252,8 @@ impl MapEnemy {
}; };
Ok(MapEnemy { Ok(MapEnemy {
monster: monster, monster,
map_area: map_area.clone(), map_area: *map_area,
hp: 0, hp: 0,
dropped_item: false, dropped_item: false,
gave_exp: false, gave_exp: false,
@ -263,8 +263,8 @@ impl MapEnemy {
pub fn new(monster: MonsterType, map_area: MapArea) -> MapEnemy { pub fn new(monster: MonsterType, map_area: MapArea) -> MapEnemy {
MapEnemy { MapEnemy {
monster: monster, monster,
map_area: map_area, map_area,
hp: 0, hp: 0,
dropped_item: false, dropped_item: false,
gave_exp: false, gave_exp: false,

View File

@ -17,14 +17,14 @@ pub fn objects_from_stream(cursor: &mut impl Read, episode: &Episode, map_area:
let mut object_data = Vec::new(); let mut object_data = Vec::new();
while let Ok(raw_object) = RawMapObject::from_byte_stream(cursor) { while let Ok(raw_object) = RawMapObject::from_byte_stream(cursor) {
let object = MapObject::from_raw(raw_object.clone(), *episode, map_area); let object = MapObject::from_raw(raw_object, *episode, map_area);
object_data.push(object.ok()); object_data.push(object.ok());
} }
object_data object_data
} }
fn objects_from_map_data(path: PathBuf, episode: &Episode, map_area: &MapArea) -> Vec<Option<MapObject>> { fn objects_from_map_data(path: PathBuf, episode: &Episode, map_area: &MapArea) -> Vec<Option<MapObject>> {
let mut cursor = File::open(path.clone()).unwrap(); let mut cursor = File::open(path).unwrap();
objects_from_stream(&mut cursor, episode, map_area) objects_from_stream(&mut cursor, episode, map_area)
} }
@ -32,8 +32,7 @@ fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) ->
let enemy = MapEnemy::from_raw(raw_enemy, episode, map_area); let enemy = MapEnemy::from_raw(raw_enemy, episode, map_area);
enemy enemy
.map_or(vec![None], |monster| { .map_or(vec![None], |monster| {
let mut monsters = Vec::new(); let mut monsters = vec![Some(monster)];
monsters.push(Some(monster));
match monster.monster { match monster.monster {
MonsterType::Monest => { MonsterType::Monest => {
@ -275,13 +274,13 @@ impl Maps {
let maps = Maps { let maps = Maps {
enemy_data: map_variants.iter().fold(Vec::new(), |mut enemy_data, map_variant| { enemy_data: map_variants.iter().fold(Vec::new(), |mut enemy_data, map_variant| {
enemy_data.append(&mut enemy_data_from_map_data(&map_variant, &room_mode.episode())); enemy_data.append(&mut enemy_data_from_map_data(map_variant, &room_mode.episode()));
enemy_data enemy_data
}), }),
object_data: map_variants.iter().map(|map_variant| { object_data: map_variants.iter().map(|map_variant| {
objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map)
}).flatten().collect(), }).flatten().collect(),
map_variants: map_variants, map_variants,
}; };
maps maps
} }

View File

@ -159,8 +159,8 @@ impl MapObject {
}; };
Ok(MapObject { Ok(MapObject {
object: object, object,
map: map_area.clone(), map: *map_area,
dropped_item: false, dropped_item: false,
}) })
} }

View File

@ -75,10 +75,10 @@ impl MapVariant {
}; };
MapVariant { MapVariant {
map: map, map,
mode: mode, mode,
major: major, major,
minor: minor, minor,
} }
} }
else { else {
@ -136,10 +136,10 @@ impl MapVariant {
}; };
MapVariant { MapVariant {
map: map, map,
mode: mode, mode,
major: major, major,
minor: minor, minor,
} }
} }
} }
@ -198,9 +198,9 @@ impl MapVariant {
MapArea::Forest1 => format!("data/maps/map_forest01_0{}_offe.dat", self.minor*2), MapArea::Forest1 => format!("data/maps/map_forest01_0{}_offe.dat", self.minor*2),
MapArea::Forest2 => { MapArea::Forest2 => {
match self.minor { match self.minor {
0 => format!("data/maps/map_forest02_00_offe.dat"), 0 => "data/maps/map_forest02_00_offe.dat".into(),
1 => format!("data/maps/map_forest02_03_offe.dat"), 1 => "data/maps/map_forest02_03_offe.dat".into(),
2 => format!("data/maps/map_forest02_04_offe.dat"), 2 => "data/maps/map_forest02_04_offe.dat".into(),
_ => unreachable!() _ => unreachable!()
}}, }},
MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}_offe.dat", self.major, self.minor), MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}_offe.dat", self.major, self.minor),
@ -302,9 +302,9 @@ impl MapVariant {
MapArea::Forest1 => format!("data/maps/map_forest01_0{}o.dat", self.minor*2), MapArea::Forest1 => format!("data/maps/map_forest01_0{}o.dat", self.minor*2),
MapArea::Forest2 => { MapArea::Forest2 => {
match self.minor { match self.minor {
0 => format!("data/maps/map_forest02_00o.dat"), 0 => "data/maps/map_forest02_00o.dat".into(),
1 => format!("data/maps/map_forest02_03o.dat"), 1 => "data/maps/map_forest02_03o.dat".into(),
2 => format!("data/maps/map_forest02_04o.dat"), 2 => "data/maps/map_forest02_04o.dat".into(),
_ => unreachable!() _ => unreachable!()
}}, }},
MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}o.dat", self.major, self.minor), MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}o.dat", self.major, self.minor),

View File

@ -1,3 +1,4 @@
#[allow(clippy::module_inception)]
pub mod ship; pub mod ship;
pub mod location; pub mod location;
pub mod character; pub mod character;

View File

@ -18,7 +18,7 @@ pub fn join_lobby(id: ClientId,
let playerinfo = lobby_clients.iter() let playerinfo = lobby_clients.iter()
.map(|area_client| { .map(|area_client| {
let client = clients.get(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client)).unwrap(); let client = clients.get(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client)).unwrap();
player_info(0x100, &client, area_client, item_manager, level_table) player_info(0x100, client, area_client, item_manager, level_table)
}); });
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap();
@ -55,7 +55,7 @@ pub fn add_to_lobby(id: ClientId,
block: client.block as u16, block: client.block as u16,
event: 0, event: 0,
padding: 0, padding: 0,
playerinfo: player_info(0x100, &client, &area_client, item_manager, level_table), playerinfo: player_info(0x100, client, &area_client, item_manager, level_table),
}) })
} }

View File

@ -12,8 +12,8 @@ use crate::ship::shops::ShopItem;
pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDrop, ShipError> { pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDrop, ShipError> {
let item_bytes = item_drop.as_client_bytes(); let item_bytes = item_drop.as_client_bytes();
Ok(ItemDrop { Ok(ItemDrop {
client: client, client,
target: target, target,
map_area: item_drop.map_area().area_value(), map_area: item_drop.map_area().area_value(),
variety: 0, variety: 0,
unknown: 0, unknown: 0,
@ -101,7 +101,7 @@ pub fn character_gained_exp(area_client: AreaClient, exp: u32) -> GiveCharacterE
GiveCharacterExp { GiveCharacterExp {
client: area_client.local_client.id(), client: area_client.local_client.id(),
target: 0, target: 0,
exp: exp, exp,
} }
} }
@ -138,12 +138,12 @@ pub fn player_no_longer_has_item(area_client: AreaClient, item_id: ClientItemId,
client: area_client.local_client.id(), client: area_client.local_client.id(),
target: 0, target: 0,
item_id: item_id.0, item_id: item_id.0,
amount: amount, amount,
} }
} }
pub fn shop_list<I: ShopItem>(shop_type: u8, items: &Vec<I>) -> ShopList { pub fn shop_list<I: ShopItem>(shop_type: u8, items: &[I]) -> ShopList {
let items = items.into_iter() let items = items.iter()
.enumerate() .enumerate()
.map(|(i, item)| { .map(|(i, item)| {
ShopListItem { ShopListItem {
@ -157,10 +157,10 @@ pub fn shop_list<I: ShopItem>(shop_type: u8, items: &Vec<I>) -> ShopList {
ShopList { ShopList {
client: 0, client: 0,
target: 0, target: 0,
shop_type: shop_type, shop_type,
num_items: 0, num_items: 0,
unused: 0, unused: 0,
items: items, items,
} }
} }

View File

@ -14,7 +14,7 @@ use crate::ship::items::ItemManager;
pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader { pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader {
PlayerHeader { PlayerHeader {
tag: tag, tag,
guildcard: client.user.id.0, guildcard: client.user.id.0,
_unknown1: [0; 5], _unknown1: [0; 5],
client_id: area_client.local_client.id() as u32, client_id: area_client.local_client.id() as u32,
@ -26,7 +26,7 @@ pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -
pub fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, item_manager: &ItemManager, level_table: &CharacterLevelTable) -> PlayerInfo { pub fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, item_manager: &ItemManager, level_table: &CharacterLevelTable) -> PlayerInfo {
let (level, stats) = level_table.get_stats_from_exp(client.character.char_class, client.character.exp); let (level, stats) = level_table.get_stats_from_exp(client.character.char_class, client.character.exp);
let inventory = item_manager.get_character_inventory(&client.character).unwrap(); let inventory = item_manager.get_character_inventory(&client.character).unwrap();
let character = CharacterBytesBuilder::new() let character = CharacterBytesBuilder::default()
.character(&client.character) .character(&client.character)
.stats(&stats) .stats(&stats)
.level(level - 1) .level(level - 1)
@ -40,6 +40,6 @@ pub fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, ite
language: 0, // TODO: account language language: 0, // TODO: account language
items: inventory.as_client_inventory_items(), items: inventory.as_client_inventory_items(),
}, },
character: character, character,
} }
} }

View File

@ -22,7 +22,7 @@ pub fn quest_category_list(quests: &QuestList) -> QuestCategoryList {
} }
} }
pub fn quest_list(category_id: u32, quests: &Vec<Quest>) -> QuestOptionList { pub fn quest_list(category_id: u32, quests: &[Quest]) -> QuestOptionList {
let quest_entries = quests.iter() let quest_entries = quests.iter()
.map(|quest| { .map(|quest| {
QuestEntry { QuestEntry {
@ -59,9 +59,9 @@ pub fn quest_header(quest_menu_select: &QuestMenuSelect, data_blob: &[u8], suffi
pub fn quest_chunk(chunk_num: u32, filename: [u8; 16], blob: [u8; 0x400], blob_length: usize) -> QuestChunk { pub fn quest_chunk(chunk_num: u32, filename: [u8; 16], blob: [u8; 0x400], blob_length: usize) -> QuestChunk {
QuestChunk { QuestChunk {
chunk_num: chunk_num, chunk_num,
filename: filename, filename,
blob: blob, blob,
blob_length: blob_length as u32, blob_length: blob_length as u32,
unknown: 0, unknown: 0,
} }

View File

@ -20,7 +20,7 @@ pub fn join_room(id: ClientId,
let header_client = clients.get(&c.client).ok_or(ShipError::ClientNotFound(id))?; let header_client = clients.get(&c.client).ok_or(ShipError::ClientNotFound(id))?;
let header_area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; let header_area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
acc.map(|mut a| { acc.map(|mut a| {
a[i] = player_header(0x10000, &header_client, &header_area_client); a[i] = player_header(0x10000, header_client, &header_area_client);
a a
}) })
})?; })?;
@ -30,7 +30,7 @@ pub fn join_room(id: ClientId,
Ok(JoinRoom { Ok(JoinRoom {
flag: all_clients.len() as u32, flag: all_clients.len() as u32,
maps: room.maps.map_headers(), maps: room.maps.map_headers(),
players: players, players,
client: area_client.local_client.id(), client: area_client.local_client.id(),
leader: leader.local_client.id(), leader: leader.local_client.id(),
one: 1, one: 1,
@ -67,7 +67,7 @@ pub fn add_to_room(_id: ClientId,
block: 0, block: 0,
event: 0, event: 0,
padding: 0, padding: 0,
playerinfo: player_info(0x10000, client, &area_client, item_manager, level_table), playerinfo: player_info(0x10000, client, area_client, item_manager, level_table),
}) })
} }

View File

@ -1,19 +1,10 @@
use libpso::packet::login::{ShipList, ShipListEntry}; use libpso::packet::login::{ShipList, ShipListEntry};
use libpso::packet::ship::*;
use crate::common::serverstate::ClientId;
use crate::common::leveltable::CharacterLevelTable;
use crate::ship::ship::{ShipError, ClientState, Clients};
use crate::ship::location::{ClientLocation, RoomId, AreaClient, ClientLocationError};
use crate::ship::room::RoomState;
use crate::ship::items::ItemManager;
use crate::ship::packet::builder::{player_header, player_info};
use libpso::utf8_to_utf16_array; use libpso::utf8_to_utf16_array;
use crate::common::interserver::Ship; use crate::common::interserver::Ship;
use libpso::packet::ship::BLOCK_MENU_ID;
use crate::login::character::SHIP_MENU_ID; use crate::login::character::SHIP_MENU_ID;
pub fn ship_list(ships: &Vec<Ship>) -> ShipList { pub fn ship_list(ships: &[Ship]) -> ShipList {
let ships = ships.iter() let ships = ships.iter()
.enumerate() .enumerate()
.map(|(i, ship)| { .map(|(i, ship)| {

View File

@ -2,18 +2,19 @@ use libpso::packet::login::{Login, LoginResponse, AccountStatus, Session};
use libpso::packet::ship::*; use libpso::packet::ship::*;
use crate::common::serverstate::ClientId; use crate::common::serverstate::ClientId;
use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients};
use crate::login::login::{get_login_status, check_if_already_online}; use crate::login::login::get_login_status;
use crate::entity::gateway::EntityGateway; use crate::entity::gateway::EntityGateway;
use crate::ship::items::ItemManager; use crate::ship::items::ItemManager;
use crate::common::interserver::ShipMessage; use crate::common::interserver::ShipMessage;
#[allow(clippy::too_many_arguments)]
pub async fn validate_login<EG: EntityGateway>(id: ClientId, pub async fn validate_login<EG: EntityGateway>(id: ClientId,
pkt: &Login, pkt: &Login,
entity_gateway: &mut EG, entity_gateway: &mut EG,
clients: &mut Clients, clients: &mut Clients,
item_manager: &mut ItemManager, item_manager: &mut ItemManager,
shipgate_sender: &Option<Box<dyn Fn(ShipMessage) + Send + Sync>>, shipgate_sender: &Option<Box<dyn Fn(ShipMessage) + Send + Sync>>,
ship_name: &String, ship_name: &str,
num_blocks: usize) num_blocks: usize)
-> Result<Vec<SendShipPacket>, anyhow::Error> { -> Result<Vec<SendShipPacket>, anyhow::Error> {
Ok(match get_login_status(entity_gateway, pkt).await { Ok(match get_login_status(entity_gateway, pkt).await {
@ -32,10 +33,10 @@ pub async fn validate_login<EG: EntityGateway>(id: ClientId,
item_manager.load_character(entity_gateway, &character).await?; item_manager.load_character(entity_gateway, &character).await?;
if let Some(shipgate_sender) = shipgate_sender.as_ref() { if let Some(shipgate_sender) = shipgate_sender.as_ref() {
shipgate_sender(ShipMessage::AddUser(user.id.clone())); shipgate_sender(ShipMessage::AddUser(user.id));
} }
clients.insert(id, ClientState::new(user, settings, character, pkt.session)); clients.insert(id, ClientState::new(user, settings, character, pkt.session));
vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(&&ship_name, num_blocks))] vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(ship_name, num_blocks))]
}, },
Err(err) => { Err(err) => {
vec![SendShipPacket::LoginResponse(LoginResponse::by_status(err, Session::new()))] vec![SendShipPacket::LoginResponse(LoginResponse::by_status(err, Session::new()))]

View File

@ -65,7 +65,7 @@ pub fn guildcard_send(id: ClientId,
class: client.character.char_class.into(), class: client.character.char_class.into(),
}), }),
}; };
send_to_client(id, target as u8, msg, &client_location) send_to_client(id, target as u8, msg, client_location)
} }
pub async fn request_item<EG>(id: ClientId, pub async fn request_item<EG>(id: ClientId,
@ -110,7 +110,7 @@ where
}; };
let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?;
let floor_item = item_manager.enemy_drop_item_on_local_floor(entity_gateway, &client.character, item_drop).await?; let floor_item = item_manager.enemy_drop_item_on_local_floor(entity_gateway, &client.character, item_drop).await?;
let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &floor_item)?; let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, floor_item)?;
item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))); item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg)))));
} }
@ -135,7 +135,7 @@ where
// TODO: should not need to fetch the item here to construct this packet // TODO: should not need to fetch the item here to construct this packet
let (item, floor_type) = item_manager.get_floor_item_by_id(&client.character, ClientItemId(pickup_item.item_id))?; let (item, floor_type) = item_manager.get_floor_item_by_id(&client.character, ClientItemId(pickup_item.item_id))?;
let remove_item = builder::message::remove_item_from_floor(area_client, &item)?; let remove_item = builder::message::remove_item_from_floor(area_client, item)?;
let create_item = match item { let create_item = match item {
FloorItem::Individual(individual_floor_item) => Some(builder::message::create_item(area_client, item.item_id(), &individual_floor_item.item)?), FloorItem::Individual(individual_floor_item) => Some(builder::message::create_item(area_client, item.item_id(), &individual_floor_item.item)?),
FloorItem::Stacked(stacked_floor_item) => Some(builder::message::create_item(area_client, item.item_id(), &item::ItemDetail::Tool(stacked_floor_item.tool))?), FloorItem::Stacked(stacked_floor_item) => Some(builder::message::create_item(area_client, item.item_id(), &item::ItemDetail::Tool(stacked_floor_item.tool))?),
@ -216,7 +216,7 @@ EG: EntityGateway
}; };
let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?;
let floor_item = item_manager.enemy_drop_item_on_local_floor(entity_gateway, &client.character, item_drop).await?; // TODO: unwrap let floor_item = item_manager.enemy_drop_item_on_local_floor(entity_gateway, &client.character, item_drop).await?; // TODO: unwrap
let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, &floor_item)?; let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, floor_item)?;
item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))) item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg)))))
} }
@ -233,7 +233,7 @@ pub async fn send_bank_list(id: ClientId,
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
let bank_items = item_manager.get_character_bank(&client.character)?; let bank_items = item_manager.get_character_bank(&client.character)?;
let bank_items_pkt = builder::message::bank_item_list(&bank_items, client.character.bank_meseta); let bank_items_pkt = builder::message::bank_item_list(bank_items, client.character.bank_meseta);
Ok(Box::new(vec![(id, SendShipPacket::BankItemList(bank_items_pkt))].into_iter())) Ok(Box::new(vec![(id, SendShipPacket::BankItemList(bank_items_pkt))].into_iter()))
} }
@ -277,7 +277,7 @@ where
} }
else { else {
let item_added_to_inventory = item_manager.player_withdraws_item(entity_gateway, &client.character, ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as usize).await?; let item_added_to_inventory = item_manager.player_withdraws_item(entity_gateway, &client.character, ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as usize).await?;
let item_created = builder::message::create_withdrawn_inventory_item(area_client, &item_added_to_inventory)?; let item_created = builder::message::create_withdrawn_inventory_item(area_client, item_added_to_inventory)?;
vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(item_created)))] vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(item_created)))]
} }
}, },
@ -357,18 +357,12 @@ where
}, },
SHOP_OPTION_TOOL => { SHOP_OPTION_TOOL => {
let item = client.tool_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?; let item = client.tool_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?;
let remove = match item { let remove = matches!(item, ToolShopItem::Tech(_));
ToolShopItem::Tech(_) => true,
_ => false,
};
(item, remove) (item, remove)
}, },
SHOP_OPTION_ARMOR => { SHOP_OPTION_ARMOR => {
let item = client.armor_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?; let item = client.armor_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?;
let remove = match item { let remove = matches!(item, ArmorShopItem::Unit(_));
ArmorShopItem::Unit(_) => true,
_ => false,
};
(item, remove) (item, remove)
}, },
_ => { _ => {

View File

@ -24,12 +24,12 @@ pub fn block_selected(id: ClientId,
let inventory = item_manager.get_character_inventory(&client.character).unwrap(); let inventory = item_manager.get_character_inventory(&client.character).unwrap();
let bank = item_manager.get_character_bank(&client.character).unwrap(); let bank = item_manager.get_character_bank(&client.character).unwrap();
let fc = FullCharacterBytesBuilder::new() let fc = FullCharacterBytesBuilder::default()
.character(&client.character) .character(&client.character)
.stats(&stats) .stats(&stats)
.level(level) .level(level)
.inventory(&inventory) .inventory(inventory)
.bank(&bank) .bank(bank)
.key_config(&client.settings.settings.key_config) .key_config(&client.settings.settings.key_config)
.joystick_config(&client.settings.settings.joystick_config) .joystick_config(&client.settings.settings.joystick_config)
.symbol_chat(&client.settings.settings.symbol_chats) .symbol_chat(&client.settings.settings.symbol_chats)
@ -63,6 +63,7 @@ pub fn send_player_to_lobby(id: ClientId,
.map(|c| (c.client, SendShipPacket::AddToLobby(addto.clone())))).collect()) .map(|c| (c.client, SendShipPacket::AddToLobby(addto.clone())))).collect())
} }
#[allow(clippy::too_many_arguments)]
pub async fn change_lobby<EG: EntityGateway>(id: ClientId, pub async fn change_lobby<EG: EntityGateway>(id: ClientId,
requested_lobby: u32, requested_lobby: u32,
client_location: &mut ClientLocation, client_location: &mut ClientLocation,
@ -81,7 +82,7 @@ pub async fn change_lobby<EG: EntityGateway>(id: ClientId,
} }
}, },
RoomLobby::Room(old_room) => { RoomLobby::Room(old_room) => {
if client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError {err.into()})?.len() == 0 { if client_location.get_client_neighbors(id)?.is_empty() {
ship_rooms[old_room.0] = None; ship_rooms[old_room.0] = None;
} }
item_manager.remove_character_from_room(&client.character); item_manager.remove_character_from_room(&client.character);
@ -90,7 +91,7 @@ pub async fn change_lobby<EG: EntityGateway>(id: ClientId,
let leave_lobby = packet::builder::lobby::remove_from_lobby(id, client_location)?; let leave_lobby = packet::builder::lobby::remove_from_lobby(id, client_location)?;
let old_neighbors = client_location.get_client_neighbors(id).unwrap(); let old_neighbors = client_location.get_client_neighbors(id).unwrap();
let mut lobby = LobbyId(requested_lobby as usize); let mut lobby = LobbyId(requested_lobby as usize);
if let Err(_) = client_location.add_client_to_lobby(id, lobby) { if client_location.add_client_to_lobby(id, lobby).is_err() {
match prev_area { match prev_area {
RoomLobby::Lobby(_lobby) => { RoomLobby::Lobby(_lobby) => {
let dialog = SmallDialog::new(String::from("Lobby is full.")); let dialog = SmallDialog::new(String::from("Lobby is full."));

View File

@ -1,12 +1,11 @@
use libpso::packet::ship::*; use libpso::packet::ship::*;
use libpso::packet::messages::*; use libpso::packet::messages::*;
use crate::entity::gateway::EntityGateway; use crate::entity::gateway::EntityGateway;
use crate::entity::item::{ItemType};
use crate::common::serverstate::ClientId; use crate::common::serverstate::ClientId;
use crate::common::leveltable::CharacterLevelTable; use crate::common::leveltable::CharacterLevelTable;
use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients, ItemDropLocation}; use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients, ItemDropLocation};
use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::location::{ClientLocation, ClientLocationError};
use crate::ship::items::{ItemManager, ClientItemId, InventoryItem}; use crate::ship::items::{ItemManager, ClientItemId};
use crate::ship::packet::builder; use crate::ship::packet::builder;
pub async fn request_exp<EG: EntityGateway>(id: ClientId, pub async fn request_exp<EG: EntityGateway>(id: ClientId,
@ -26,7 +25,7 @@ pub async fn request_exp<EG: EntityGateway>(id: ClientId,
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?; .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?;
let monster = room.maps.enemy_by_id(request_exp.enemy_id as usize)?; let monster = room.maps.enemy_by_id(request_exp.enemy_id as usize)?;
let monster_stats = room.monster_stats.get(&monster.monster).ok_or(ShipError::UnknownMonster(monster.monster.clone()))?; let monster_stats = room.monster_stats.get(&monster.monster).ok_or(ShipError::UnknownMonster(monster.monster))?;
let exp_gain = if request_exp.last_hitter == 1 { let exp_gain = if request_exp.last_hitter == 1 {
monster_stats.exp monster_stats.exp

View File

@ -17,8 +17,8 @@ fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType)
let filename = array_to_utf8(*filename_bytes).map_err(|_| ShipError::InvalidQuestFilename("NOT UTF8".to_string()))?; let filename = array_to_utf8(*filename_bytes).map_err(|_| ShipError::InvalidQuestFilename("NOT UTF8".to_string()))?;
let (filename, suffix) = { let (filename, suffix) = {
let mut s = filename.splitn(2, '.'); let mut s = filename.splitn(2, '.');
(s.next().ok_or(ShipError::InvalidQuestFilename(filename.to_owned()))?, (s.next().ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?,
s.next().ok_or(ShipError::InvalidQuestFilename(filename.to_owned()))?) s.next().ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?)
}; };
let datatype = match suffix { let datatype = match suffix {
@ -29,8 +29,8 @@ fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType)
let (category, quest) = { let (category, quest) = {
let mut s = filename.splitn(2, '-'); let mut s = filename.splitn(2, '-');
(s.next().and_then(|k| k.parse().ok()).ok_or(ShipError::InvalidQuestFilename(filename.to_owned()))?, (s.next().and_then(|k| k.parse().ok()).ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?,
s.next().and_then(|k| k.parse().ok()).ok_or(ShipError::InvalidQuestFilename(filename.to_owned()))?) s.next().and_then(|k| k.parse().ok()).ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?)
}; };
Ok((category, quest, datatype)) Ok((category, quest, datatype))
@ -63,7 +63,7 @@ pub fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, quest
q.id == questdetailrequest.quest as u16 q.id == questdetailrequest.quest as u16
}).ok_or(ShipError::InvalidQuest(questdetailrequest.quest as u32))?; }).ok_or(ShipError::InvalidQuest(questdetailrequest.quest as u32))?;
let qd = quest::quest_detail(&quest); let qd = quest::quest_detail(quest);
Ok(Box::new(vec![(id, SendShipPacket::QuestDetail(qd))].into_iter())) Ok(Box::new(vec![(id, SendShipPacket::QuestDetail(qd))].into_iter()))
} }
@ -91,9 +91,9 @@ pub fn load_quest(id: ClientId, questmenuselect: &QuestMenuSelect, quests: &Ques
let area_clients = client_location.get_all_clients_by_client(id).map_err(|err| -> ClientLocationError { err.into() })?; let area_clients = client_location.get_all_clients_by_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
area_clients.iter().for_each(|c| { area_clients.iter().for_each(|c| {
clients.get_mut(&c.client).map(|client| { if let Some(client) = clients.get_mut(&c.client) {
client.done_loading_quest = false; client.done_loading_quest = false;
}); }
}); });
Ok(Box::new(area_clients.into_iter().map(move |c| { Ok(Box::new(area_clients.into_iter().map(move |c| {
vec![(c.client, SendShipPacket::QuestHeader(bin.clone())), (c.client, SendShipPacket::QuestHeader(dat.clone()))] vec![(c.client, SendShipPacket::QuestHeader(bin.clone())), (c.client, SendShipPacket::QuestHeader(dat.clone()))]

View File

@ -66,8 +66,8 @@ pub fn join_room(id: ClientId,
let original_area = client_location.get_area(id).unwrap(); let original_area = client_location.get_area(id).unwrap();
let original_neighbors = client_location.get_client_neighbors(id).unwrap(); let original_neighbors = client_location.get_client_neighbors(id).unwrap();
let room = rooms.get(pkt.item as usize) let room = rooms.get(pkt.item as usize)
.ok_or_else(|| ShipError::InvalidRoom(pkt.item))?.as_ref() .ok_or(ShipError::InvalidRoom(pkt.item))?.as_ref()
.ok_or_else(|| ShipError::InvalidRoom(pkt.item))?; .ok_or(ShipError::InvalidRoom(pkt.item))?;
if room.bursting { if room.bursting {
return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))].into_iter())) return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))].into_iter()))
} }
@ -81,8 +81,8 @@ pub fn join_room(id: ClientId,
item_manager.add_character_to_room(room_id, &client.character, area_client); item_manager.add_character_to_room(room_id, &client.character, area_client);
let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?; let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
let join_room = builder::room::join_room(id, clients, client_location, room_id, &room)?; let join_room = builder::room::join_room(id, clients, client_location, room_id, room)?;
let add_to = builder::room::add_to_room(id, &client, &area_client, &leader, item_manager, level_table, room_id)?; let add_to = builder::room::add_to_room(id, client, &area_client, &leader, item_manager, level_table, room_id)?;
let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap();
room.bursting = true; room.bursting = true;
@ -90,7 +90,7 @@ pub fn join_room(id: ClientId,
let mut result: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = Box::new( let mut result: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = Box::new(
vec![(id, SendShipPacket::JoinRoom(join_room))] vec![(id, SendShipPacket::JoinRoom(join_room))]
.into_iter() .into_iter()
.chain(original_room_clients.clone().into_iter() .chain(original_room_clients.into_iter()
.map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone()))) .map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone())))
)); ));
@ -109,9 +109,9 @@ pub fn done_bursting(id: ClientId,
-> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> { -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
let area = client_location.get_area(id).unwrap(); let area = client_location.get_area(id).unwrap();
if let RoomLobby::Room(room_id) = area { if let RoomLobby::Room(room_id) = area {
rooms.get_mut(room_id.0).unwrap().as_mut().map(|room| { if let Some(room) = rooms.get_mut(room_id.0).unwrap().as_mut() {
room.bursting = false; room.bursting = false;
}); }
} }
let area_client = client_location.get_local_client(id).unwrap(); // TODO: unwrap let area_client = client_location.get_local_client(id).unwrap(); // TODO: unwrap
Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() // TODO: unwrap Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() // TODO: unwrap

View File

@ -2,10 +2,10 @@ use libpso::packet::ship::*;
use libpso::packet::login::RedirectClient; use libpso::packet::login::RedirectClient;
use crate::common::serverstate::ClientId; use crate::common::serverstate::ClientId;
use crate::common::interserver::Ship; use crate::common::interserver::Ship;
use crate::ship::ship::{SendShipPacket, ShipError, Clients}; use crate::ship::ship::{SendShipPacket, ShipError};
use crate::ship::packet::builder; use crate::ship::packet::builder;
pub fn ship_list(id: ClientId, ship_list: &Vec<Ship>) pub fn ship_list(id: ClientId, ship_list: &[Ship])
-> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> { -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
Box::new(vec![(id, SendShipPacket::ShipList(builder::ship::ship_list(ship_list)))].into_iter()) Box::new(vec![(id, SendShipPacket::ShipList(builder::ship::ship_list(ship_list)))].into_iter())
} }
@ -15,7 +15,7 @@ pub fn block_list(id: ClientId, shipname: &str, num_blocks: usize)
Box::new(vec![(id, SendShipPacket::ShipBlockList(ShipBlockList::new(shipname, num_blocks)))].into_iter()) Box::new(vec![(id, SendShipPacket::ShipBlockList(ShipBlockList::new(shipname, num_blocks)))].into_iter())
} }
pub fn selected_ship(id: ClientId, menuselect: &MenuSelect, ship_list: &Vec<Ship>) pub fn selected_ship(id: ClientId, menuselect: &MenuSelect, ship_list: &[Ship])
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> { -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
let ship = ship_list.get(menuselect.item as usize).ok_or(ShipError::InvalidShip(menuselect.item as usize))?; let ship = ship_list.get(menuselect.item as usize).ok_or(ShipError::InvalidShip(menuselect.item as usize))?;
let ip = u32::from_ne_bytes(ship.ip.octets()); let ip = u32::from_ne_bytes(ship.ip.octets());

View File

@ -73,18 +73,18 @@ fn read_dat_section_header<T: Read + Seek>(cursor: &mut T, episode: &Episode, ma
match header { match header {
DAT_OBJECT_HEADER_ID => { DAT_OBJECT_HEADER_ID => {
let mut obj_data = vec![0u8; length as usize]; let mut obj_data = vec![0u8; length as usize];
cursor.read(&mut obj_data)?; cursor.read_exact(&mut obj_data)?;
let mut obj_cursor = Cursor::new(obj_data); let mut obj_cursor = Cursor::new(obj_data);
let objects = objects_from_stream(&mut obj_cursor, episode, &map_area); let objects = objects_from_stream(&mut obj_cursor, episode, map_area);
Ok(DatBlock::Object(objects)) Ok(DatBlock::Object(objects))
}, },
DAT_ENEMY_HEADER_ID => { DAT_ENEMY_HEADER_ID => {
let mut enemy_data = vec![0u8; length as usize]; let mut enemy_data = vec![0u8; length as usize];
cursor.read(&mut enemy_data)?; cursor.read_exact(&mut enemy_data)?;
let mut enemy_cursor = Cursor::new(enemy_data); let mut enemy_cursor = Cursor::new(enemy_data);
let enemies = enemy_data_from_stream(&mut enemy_cursor, &map_area, episode); let enemies = enemy_data_from_stream(&mut enemy_cursor, map_area, episode);
Ok(DatBlock::Enemy(enemies)) Ok(DatBlock::Enemy(enemies))
}, },
@ -100,14 +100,14 @@ fn quest_episode(bin: &[u8]) -> Option<Episode> {
for bytes in bin.windows(3) { for bytes in bin.windows(3) {
// set_episode // set_episode
if bytes[0] == 0xF8 && bytes[1] == 0xBC { if bytes[0] == 0xF8 && bytes[1] == 0xBC {
return Some(Episode::from_quest(bytes[2]).ok()?) return Episode::from_quest(bytes[2]).ok()
} }
} }
None None
} }
fn map_area_mappings(bin: &[u8]) -> MapAreaLookup { fn map_area_mappings(bin: &[u8]) -> MapAreaLookup {
let mut map_areas = MapAreaLookupBuilder::new(); let mut map_areas = MapAreaLookupBuilder::default();
for bytes in bin.windows(4) { for bytes in bin.windows(4) {
// BB_Map_Designate // BB_Map_Designate
if bytes[0] == 0xF9 && bytes[1] == 0x51 { if bytes[0] == 0xF9 && bytes[1] == 0x51 {
@ -121,6 +121,7 @@ fn map_area_mappings(bin: &[u8]) -> MapAreaLookup {
map_areas.build() map_areas.build()
} }
#[allow(clippy::type_complexity)]
fn parse_dat(dat: &[u8], episode: &Episode, map_areas: &MapAreaLookup) -> Result<(Vec<Option<MapEnemy>>, Vec<Option<MapObject>>), ParseDatError> { fn parse_dat(dat: &[u8], episode: &Episode, map_areas: &MapAreaLookup) -> Result<(Vec<Option<MapEnemy>>, Vec<Option<MapObject>>), ParseDatError> {
let mut cursor = Cursor::new(dat); let mut cursor = Cursor::new(dat);
@ -185,21 +186,21 @@ impl Quest {
let (enemies, objects) = parse_dat(&dat, &episode, &map_areas)?; let (enemies, objects) = parse_dat(&dat, &episode, &map_areas)?;
let mut prs_bin = LegacyPrsEncoder::new(Vec::new()); let mut prs_bin = LegacyPrsEncoder::new(Vec::new());
prs_bin.write(&bin)?; prs_bin.write_all(&bin)?;
let mut prs_dat = LegacyPrsEncoder::new(Vec::new()); let mut prs_dat = LegacyPrsEncoder::new(Vec::new());
prs_dat.write(&dat)?; prs_dat.write_all(&dat)?;
Ok(Quest { Ok(Quest {
name: name, name,
description: description, description,
full_description: full_description, full_description,
id: id, id,
language: language, language,
bin_blob: prs_bin.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?, bin_blob: prs_bin.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?,
dat_blob: prs_dat.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?, dat_blob: prs_dat.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?,
enemies: enemies, enemies,
objects: objects, objects,
map_areas: map_areas, map_areas,
}) })
} }
} }

View File

@ -40,9 +40,9 @@ impl TryFrom<u8> for Episode {
} }
} }
impl Into<u8> for Episode { impl From<Episode> for u8 {
fn into(self) -> u8 { fn from(other: Episode) -> u8 {
match self { match other {
Episode::One => 1, Episode::One => 1,
Episode::Two => 2, Episode::Two => 2,
Episode::Four => 3, Episode::Four => 3,
@ -83,9 +83,9 @@ impl TryFrom<u8> for Difficulty {
} }
} }
impl Into<u8> for Difficulty { impl From<Difficulty> for u8 {
fn into(self) -> u8 { fn from(other: Difficulty) -> u8 {
match self { match other {
Difficulty::Normal => 0, Difficulty::Normal => 0,
Difficulty::Hard => 1, Difficulty::Hard => 1,
Difficulty::VeryHard => 2, Difficulty::VeryHard => 2,
@ -232,13 +232,13 @@ impl RoomState {
}; };
Ok(RoomState { Ok(RoomState {
monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode.clone()))?), monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode))?),
mode: room_mode, mode: room_mode,
random_seed: rand::thread_rng().gen(), random_seed: rand::thread_rng().gen(),
name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(), name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(),
password: create_room.password, password: create_room.password,
maps: Maps::new(room_mode), maps: Maps::new(room_mode),
section_id: section_id, section_id,
drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)), drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)),
bursting: false, bursting: false,
map_areas: MapAreaLookup::new(&room_mode.episode()), map_areas: MapAreaLookup::new(&room_mode.episode()),

View File

@ -262,10 +262,10 @@ pub struct ClientState {
impl ClientState { impl ClientState {
pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, session: Session) -> ClientState { pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, session: Session) -> ClientState {
ClientState { ClientState {
user: user, user,
settings: settings, settings,
character: character, character,
session: session, session,
block: 0, block: 0,
item_drop_location: None, item_drop_location: None,
done_loading_quest: false, done_loading_quest: false,
@ -287,8 +287,8 @@ pub struct ItemShops {
pub armor_shop: ArmorShop<rand_chacha::ChaCha20Rng>, pub armor_shop: ArmorShop<rand_chacha::ChaCha20Rng>,
} }
impl ItemShops { impl Default for ItemShops {
pub fn new() -> ItemShops { fn default() -> ItemShops {
let difficulty = [room::Difficulty::Normal, room::Difficulty::Hard, room::Difficulty::VeryHard, room::Difficulty::Ultimate]; let difficulty = [room::Difficulty::Normal, room::Difficulty::Hard, room::Difficulty::VeryHard, room::Difficulty::Ultimate];
let section_id = [SectionID::Viridia, SectionID::Greenill, SectionID::Skyly, SectionID::Bluefull, SectionID::Purplenum, let section_id = [SectionID::Viridia, SectionID::Greenill, SectionID::Skyly, SectionID::Bluefull, SectionID::Purplenum,
SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill]; SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill];
@ -301,9 +301,9 @@ impl ItemShops {
} }
ItemShops { ItemShops {
weapon_shop: weapon_shop, weapon_shop,
tool_shop: ToolShop::new(), tool_shop: ToolShop::default(),
armor_shop: ArmorShop::new(), armor_shop: ArmorShop::default(),
} }
} }
} }
@ -318,8 +318,8 @@ pub struct ShipServerStateBuilder<EG: EntityGateway> {
num_blocks: usize, num_blocks: usize,
} }
impl<EG: EntityGateway> ShipServerStateBuilder<EG> { impl<EG: EntityGateway> Default for ShipServerStateBuilder<EG> {
pub fn new() -> ShipServerStateBuilder<EG> { fn default() -> ShipServerStateBuilder<EG> {
ShipServerStateBuilder { ShipServerStateBuilder {
entity_gateway: None, entity_gateway: None,
name: None, name: None,
@ -329,7 +329,9 @@ impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
num_blocks: 2, num_blocks: 2,
} }
} }
}
impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
pub fn gateway(mut self, entity_gateway: EG) -> ShipServerStateBuilder<EG> { pub fn gateway(mut self, entity_gateway: EG) -> ShipServerStateBuilder<EG> {
self.entity_gateway = Some(entity_gateway); self.entity_gateway = Some(entity_gateway);
self self
@ -365,17 +367,17 @@ impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
ShipServerState { ShipServerState {
entity_gateway: self.entity_gateway.unwrap(), entity_gateway: self.entity_gateway.unwrap(),
clients: HashMap::new(), clients: HashMap::new(),
level_table: CharacterLevelTable::new(), level_table: CharacterLevelTable::default(),
name: self.name.unwrap_or("NAMENOTSET".into()), name: self.name.unwrap_or_else(|| "NAMENOTSET".into()),
item_manager: items::ItemManager::new(), item_manager: items::ItemManager::default(),
quests: quests::load_quests("data/quests.toml".into()).unwrap(), quests: quests::load_quests("data/quests.toml".into()).unwrap(),
ip: self.ip.unwrap_or(Ipv4Addr::new(127,0,0,1)), ip: self.ip.unwrap_or_else(|| Ipv4Addr::new(127,0,0,1)),
port: self.port.unwrap_or(SHIP_PORT), port: self.port.unwrap_or(SHIP_PORT),
shops: Box::new(ItemShops::new()), shops: Box::new(ItemShops::default()),
blocks: Blocks(blocks), blocks: Blocks(blocks),
auth_token: self.auth_token.unwrap_or(AuthToken("".into())), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())),
ship_list: Vec::new(), ship_list: Vec::new(),
shipgate_sender: None, shipgate_sender: None,
} }
@ -428,7 +430,7 @@ pub struct ShipServerState<EG: EntityGateway> {
impl<EG: EntityGateway> ShipServerState<EG> { impl<EG: EntityGateway> ShipServerState<EG> {
pub fn builder() -> ShipServerStateBuilder<EG> { pub fn builder() -> ShipServerStateBuilder<EG> {
ShipServerStateBuilder::new() ShipServerStateBuilder::default()
} }
pub fn set_sender(&mut self, sender: Box<dyn Fn(ShipMessage) + Send + Sync>) { pub fn set_sender(&mut self, sender: Box<dyn Fn(ShipMessage) + Send + Sync>) {
@ -443,7 +445,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
}, },
GameMessage::PlayerDropItem(player_drop_item) => { GameMessage::PlayerDropItem(player_drop_item) => {
let block = self.blocks.with_client(id, &self.clients)?; let block = self.blocks.with_client(id, &self.clients)?;
handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await? handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await?
}, },
GameMessage::DropCoordinates(drop_coordinates) => { GameMessage::DropCoordinates(drop_coordinates) => {
let block = self.blocks.with_client(id, &self.clients)?; let block = self.blocks.with_client(id, &self.clients)?;
@ -451,37 +453,37 @@ impl<EG: EntityGateway> ShipServerState<EG> {
}, },
GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => { GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => {
let block = self.blocks.with_client(id, &self.clients)?; let block = self.blocks.with_client(id, &self.clients)?;
handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut self.item_manager).await? handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
}, },
GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) | GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) |
GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) | GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) |
GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) | GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) |
GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => { GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => {
let block = self.blocks.with_client(id, &self.clients)?; let block = self.blocks.with_client(id, &self.clients)?;
handler::message::update_player_position(id, &msg, &mut self.clients, &mut block.client_location, &block.rooms)? handler::message::update_player_position(id, msg, &mut self.clients, &block.client_location, &block.rooms)?
}, },
GameMessage::ChargeAttack(charge_attack) => { GameMessage::ChargeAttack(charge_attack) => {
handler::message::charge_attack(id, charge_attack, &mut self.clients, &mut self.entity_gateway).await? handler::message::charge_attack(id, charge_attack, &mut self.clients, &mut self.entity_gateway).await?
}, },
GameMessage::PlayerUseItem(player_use_item) => { GameMessage::PlayerUseItem(player_use_item) => {
let block = self.blocks.with_client(id, &self.clients)?; let block = self.blocks.with_client(id, &self.clients)?;
handler::message::use_item(id, player_use_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut self.item_manager).await? handler::message::use_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
}, },
GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => {
handler::message::player_used_medical_center(id, &player_used_medical_center, &mut self.entity_gateway, &mut self.clients).await? handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &mut self.clients).await?
}, },
GameMessage::PlayerFeedMag(player_feed_mag) => { GameMessage::PlayerFeedMag(player_feed_mag) => {
let block = self.blocks.with_client(id, &self.clients)?; let block = self.blocks.with_client(id, &self.clients)?;
handler::message::player_feed_mag(id, &player_feed_mag, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut self.item_manager).await? handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_manager).await?
}, },
GameMessage::PlayerEquipItem(player_equip_item) => { GameMessage::PlayerEquipItem(player_equip_item) => {
handler::message::player_equips_item(id, &player_equip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await? handler::message::player_equips_item(id, player_equip_item, &mut self.entity_gateway, &self.clients, &mut self.item_manager).await?
}, },
GameMessage::PlayerUnequipItem(player_unequip_item) => { GameMessage::PlayerUnequipItem(player_unequip_item) => {
handler::message::player_unequips_item(id, &player_unequip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await? handler::message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_manager).await?
}, },
GameMessage::SortItems(sort_items) => { GameMessage::SortItems(sort_items) => {
handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await? handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_manager).await?
}, },
_ => { _ => {
let cmsg = msg.clone(); let cmsg = msg.clone();
@ -502,13 +504,13 @@ impl<EG: EntityGateway> ShipServerState<EG> {
handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients) handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients)
}, },
GameMessage::RequestItem(request_item) => { GameMessage::RequestItem(request_item) => {
handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await? handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await?
}, },
GameMessage::PickupItem(pickup_item) => { GameMessage::PickupItem(pickup_item) => {
handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut self.item_manager).await? handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
}, },
GameMessage::BoxDropRequest(box_drop_request) => { GameMessage::BoxDropRequest(box_drop_request) => {
handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await? handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await?
}, },
GameMessage::BankRequest(_bank_request) => { GameMessage::BankRequest(_bank_request) => {
handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_manager).await? handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_manager).await?
@ -626,7 +628,7 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
}, },
RecvShipPacket::PlayerChat(msg) => { RecvShipPacket::PlayerChat(msg) => {
let block = self.blocks.with_client(id, &self.clients)?; let block = self.blocks.with_client(id, &self.clients)?;
Box::new(handler::communication::player_chat(id, msg, &block.client_location, &self.clients)?.into_iter()) Box::new(handler::communication::player_chat(id, msg, &block.client_location, &self.clients)?)
}, },
RecvShipPacket::CreateRoom(create_room) => { RecvShipPacket::CreateRoom(create_room) => {
let block = self.blocks.with_client(id, &self.clients)?; let block = self.blocks.with_client(id, &self.clients)?;
@ -706,7 +708,7 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
let pkt = match block.client_location.get_area(id)? { let pkt = match block.client_location.get_area(id)? {
RoomLobby::Room(room) => { RoomLobby::Room(room) => {
if neighbors.len() == 0 { if neighbors.is_empty() {
block.rooms[room.0] = None; block.rooms[room.0] = None;
} }
let leader = block.client_location.get_room_leader(room)?; let leader = block.client_location.get_room_leader(room)?;
@ -719,7 +721,7 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
}; };
if let Some(shipgate_sender) = self.shipgate_sender.as_ref() { if let Some(shipgate_sender) = self.shipgate_sender.as_ref() {
shipgate_sender(ShipMessage::RemoveUser(client.user.id.clone())); shipgate_sender(ShipMessage::RemoveUser(client.user.id));
} }
block.client_location.remove_client_from_area(id); block.client_location.remove_client_from_area(id);
@ -748,7 +750,7 @@ impl<EG: EntityGateway> InterserverActor for ShipServerState<EG> {
(id, ShipMessage::Authenticate(self.auth_token.clone())), (id, ShipMessage::Authenticate(self.auth_token.clone())),
(id, ShipMessage::NewShip(Ship { (id, ShipMessage::NewShip(Ship {
name: self.name.clone(), name: self.name.clone(),
ip: self.ip.clone(), ip: self.ip,
port: self.port, port: self.port,
block_count: 2, block_count: 2,
})), })),
@ -768,7 +770,7 @@ impl<EG: EntityGateway> InterserverActor for ShipServerState<EG> {
LoginMessage::RequestUsers => { LoginMessage::RequestUsers => {
Ok(self.clients.iter() Ok(self.clients.iter()
.map(|(_, client)| { .map(|(_, client)| {
(id, ShipMessage::AddUser(client.user.id.clone())) (id, ShipMessage::AddUser(client.user.id))
}) })
.collect()) .collect())
} }

View File

@ -19,7 +19,7 @@ pub enum ArmorShopItem {
Unit(UnitType), Unit(UnitType),
} }
const ARMOR_MULTIPLIER: f32 = 0.799999952; const ARMOR_MULTIPLIER: f32 = 0.799_999_95;
const SHIELD_MULTIPLIER: f32 = 1.5; const SHIELD_MULTIPLIER: f32 = 1.5;
const UNIT_MULTIPLIER: f32 = 1000.0; const UNIT_MULTIPLIER: f32 = 1000.0;
@ -27,7 +27,7 @@ impl ShopItem for ArmorShopItem {
fn price(&self) -> usize { fn price(&self) -> usize {
match self { match self {
ArmorShopItem::Frame(frame, slot) => { ArmorShopItem::Frame(frame, slot) => {
ARMOR_STATS.get(&frame) ARMOR_STATS.get(frame)
.map(|frame_stats| { .map(|frame_stats| {
let mut price = (frame_stats.dfp + frame_stats.evp) as f32; let mut price = (frame_stats.dfp + frame_stats.evp) as f32;
price *= price; price *= price;
@ -39,7 +39,7 @@ impl ShopItem for ArmorShopItem {
.unwrap_or(0xFFFF) .unwrap_or(0xFFFF)
}, },
ArmorShopItem::Barrier(barrier) => { ArmorShopItem::Barrier(barrier) => {
SHIELD_STATS.get(&barrier) SHIELD_STATS.get(barrier)
.map(|barrier_stats| { .map(|barrier_stats| {
let mut price = (barrier_stats.dfp + barrier_stats.evp) as f32; let mut price = (barrier_stats.dfp + barrier_stats.evp) as f32;
price *= price; price *= price;
@ -50,7 +50,7 @@ impl ShopItem for ArmorShopItem {
.unwrap_or(0xFFFF) .unwrap_or(0xFFFF)
}, },
ArmorShopItem::Unit(unit) => { ArmorShopItem::Unit(unit) => {
UNIT_STATS.get(&unit) UNIT_STATS.get(unit)
.map(|unit_stats| { .map(|unit_stats| {
(unit_stats.stars as f32 * UNIT_MULTIPLIER) as usize (unit_stats.stars as f32 * UNIT_MULTIPLIER) as usize
}) })
@ -236,8 +236,8 @@ pub struct ArmorShop<R: Rng + SeedableRng> {
rng: R, rng: R,
} }
impl<R: Rng + SeedableRng> ArmorShop<R> { impl<R: Rng + SeedableRng> Default for ArmorShop<R> {
pub fn new() -> ArmorShop<R> { fn default() -> ArmorShop<R> {
ArmorShop { ArmorShop {
frame: load_frame_table(), frame: load_frame_table(),
barrier: load_barrier_table(), barrier: load_barrier_table(),
@ -245,7 +245,9 @@ impl<R: Rng + SeedableRng> ArmorShop<R> {
rng: R::from_entropy(), rng: R::from_entropy(),
} }
} }
}
impl<R: Rng + SeedableRng> ArmorShop<R> {
fn generate_frame_list(&mut self, character_level: usize) -> Vec<ArmorShopItem> { fn generate_frame_list(&mut self, character_level: usize) -> Vec<ArmorShopItem> {
let tier = self.frame.frame.iter() let tier = self.frame.frame.iter()
.filter(|t| t.level <= character_level) .filter(|t| t.level <= character_level)
@ -297,7 +299,7 @@ impl<R: Rng + SeedableRng> ArmorShop<R> {
}) })
.collect() .collect()
}) })
.unwrap_or(Vec::new()) .unwrap_or_else(Vec::new)
} }
pub fn generate_armor_list(&mut self, character_level: usize) -> Vec<ArmorShopItem> { pub fn generate_armor_list(&mut self, character_level: usize) -> Vec<ArmorShopItem> {
@ -316,12 +318,12 @@ mod test {
#[test] #[test]
fn test_loading_tool_shop() { fn test_loading_tool_shop() {
ArmorShop::<rand_chacha::ChaCha20Rng>::new(); ArmorShop::<rand_chacha::ChaCha20Rng>::default();
} }
#[test] #[test]
fn test_generating_some_armor() { fn test_generating_some_armor() {
let mut fs = ArmorShop::<rand_chacha::ChaCha20Rng>::new(); let mut fs = ArmorShop::<rand_chacha::ChaCha20Rng>::default();
for i in 0..200 { for i in 0..200 {
fs.generate_armor_list(i); fs.generate_armor_list(i);
} }

View File

@ -53,7 +53,7 @@ impl ShopItem for ToolShopItem {
fn price(&self) -> usize { fn price(&self) -> usize {
match self { match self {
ToolShopItem::Tool(tool) => { ToolShopItem::Tool(tool) => {
TOOL_STATS.get(&tool) TOOL_STATS.get(tool)
.map(|tool_stats| { .map(|tool_stats| {
tool_stats.price tool_stats.price
}) })
@ -146,7 +146,7 @@ fn load_tool_table() -> ToolTable {
let mut table: HashMap<String, Vec<ToolType>> = toml::from_str(s.as_str()).unwrap(); let mut table: HashMap<String, Vec<ToolType>> = toml::from_str(s.as_str()).unwrap();
ToolTable(table.remove("tools".into()).unwrap()) ToolTable(table.remove("tools").unwrap())
} }
fn load_tech_table() -> TechTable { fn load_tech_table() -> TechTable {
@ -156,7 +156,7 @@ fn load_tech_table() -> TechTable {
f.read_to_string(&mut s).unwrap(); f.read_to_string(&mut s).unwrap();
let mut table: HashMap<String, Vec<TechTierDeserialize>> = toml::from_str(s.as_str()).unwrap(); let mut table: HashMap<String, Vec<TechTierDeserialize>> = toml::from_str(s.as_str()).unwrap();
let techniques = table.remove("techniques".into()).unwrap(); let techniques = table.remove("techniques").unwrap();
let techniques = techniques.into_iter() let techniques = techniques.into_iter()
.map(|tech_tier| { .map(|tech_tier| {
TechTier { TechTier {
@ -194,15 +194,18 @@ pub struct ToolShop<R: Rng + SeedableRng> {
rng: R, rng: R,
} }
impl<R: Rng + SeedableRng> ToolShop<R> {
pub fn new() -> ToolShop<R> { impl<R: Rng + SeedableRng> Default for ToolShop<R> {
fn default() -> ToolShop<R> {
ToolShop { ToolShop {
tools: load_tool_table(), tools: load_tool_table(),
techs: load_tech_table(), techs: load_tech_table(),
rng: R::from_entropy(), rng: R::from_entropy(),
} }
} }
}
impl<R: Rng + SeedableRng> ToolShop<R> {
fn generate_tech_types(&mut self, character_level: usize) -> Vec<Technique> { fn generate_tech_types(&mut self, character_level: usize) -> Vec<Technique> {
let tier = self.techs.0.iter() let tier = self.techs.0.iter()
.filter(|t| t.level <= character_level) .filter(|t| t.level <= character_level)
@ -233,7 +236,7 @@ impl<R: Rng + SeedableRng> ToolShop<R> {
let tech_choice = WeightedIndex::new(tier.iter().map(|(_, e)| e.probability)).unwrap(); let tech_choice = WeightedIndex::new(tier.iter().map(|(_, e)| e.probability)).unwrap();
while techs.len() < number_of_techs { while techs.len() < number_of_techs {
let tech_detail = tier.get(tech_choice.sample(&mut self.rng)).unwrap(); let tech_detail = tier.get(tech_choice.sample(&mut self.rng)).unwrap();
if techs.iter().find(|t| *t == tech_detail.0).is_none() { if !techs.iter().any(|t| t == tech_detail.0) {
techs.push(*tech_detail.0); techs.push(*tech_detail.0);
} }
} }
@ -260,7 +263,7 @@ impl<R: Rng + SeedableRng> ToolShop<R> {
}; };
ToolShopItem::Tech(TechniqueDisk { ToolShopItem::Tech(TechniqueDisk {
tech: tech, tech,
level: level as u32, level: level as u32,
}) })
}) })
@ -269,7 +272,7 @@ impl<R: Rng + SeedableRng> ToolShop<R> {
pub fn generate_tool_list(&mut self, character_level: usize) -> Vec<ToolShopItem> { pub fn generate_tool_list(&mut self, character_level: usize) -> Vec<ToolShopItem> {
let mut tools = Vec::new().into_iter() let mut tools = Vec::new().into_iter()
.chain(self.tools.0.clone().into_iter().map(|t| ToolShopItem::Tool(t))) .chain(self.tools.0.clone().into_iter().map(ToolShopItem::Tool))
.chain(self.generate_techs(character_level).into_iter()) .chain(self.generate_techs(character_level).into_iter())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
tools.sort(); tools.sort();
@ -284,12 +287,12 @@ mod test {
#[test] #[test]
fn test_loading_tool_shop() { fn test_loading_tool_shop() {
ToolShop::<rand_chacha::ChaCha20Rng>::new(); ToolShop::<rand_chacha::ChaCha20Rng>::default();
} }
#[test] #[test]
fn test_generating_some_tools() { fn test_generating_some_tools() {
let mut ts = ToolShop::<rand_chacha::ChaCha20Rng>::new(); let mut ts = ToolShop::<rand_chacha::ChaCha20Rng>::default();
for i in 0..200 { for i in 0..200 {
ts.generate_tool_list(i); ts.generate_tool_list(i);
} }

View File

@ -32,14 +32,10 @@ pub struct WeaponShopItem {
impl PartialEq for WeaponShopItem { impl PartialEq for WeaponShopItem {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
if self.weapon == other.weapon && self.weapon == other.weapon &&
self.special == other.special && self.special == other.special &&
self.grind == other.grind && self.grind == other.grind &&
self.attributes == other.attributes { self.attributes == other.attributes
true
} else {
false
}
} }
} }
@ -247,7 +243,7 @@ fn load_weapon_table(difficulty: Difficulty, section_id: SectionID) -> WeaponTab
let mut table: HashMap<String, Vec<WeaponTableTier>> = toml::from_str(s.as_str()).unwrap(); let mut table: HashMap<String, Vec<WeaponTableTier>> = toml::from_str(s.as_str()).unwrap();
WeaponTable(table.remove("weapon_tier".into()).unwrap()) WeaponTable(table.remove("weapon_tier").unwrap())
} }
fn load_special_table() -> SpecialTable { fn load_special_table() -> SpecialTable {
@ -258,7 +254,7 @@ fn load_special_table() -> SpecialTable {
let mut table: HashMap<String, Vec<SpecialTier>> = toml::from_str(s.as_str()).unwrap(); let mut table: HashMap<String, Vec<SpecialTier>> = toml::from_str(s.as_str()).unwrap();
SpecialTable(table.remove("specials".into()).unwrap()) SpecialTable(table.remove("specials").unwrap())
} }
fn load_grind_table() -> GrindTable { fn load_grind_table() -> GrindTable {
@ -269,7 +265,7 @@ fn load_grind_table() -> GrindTable {
let mut table: HashMap<String, Vec<GrindTier>> = toml::from_str(s.as_str()).unwrap(); let mut table: HashMap<String, Vec<GrindTier>> = toml::from_str(s.as_str()).unwrap();
GrindTable(table.remove("grind".into()).unwrap()) GrindTable(table.remove("grind").unwrap())
} }
fn load_alt_grind_table() -> GrindTable { fn load_alt_grind_table() -> GrindTable {
@ -280,7 +276,7 @@ fn load_alt_grind_table() -> GrindTable {
let mut table: HashMap<String, Vec<GrindTier>> = toml::from_str(s.as_str()).unwrap(); let mut table: HashMap<String, Vec<GrindTier>> = toml::from_str(s.as_str()).unwrap();
GrindTable(table.remove("grind".into()).unwrap()) GrindTable(table.remove("grind").unwrap())
} }
fn load_attribute1_table() -> AttributeTable { fn load_attribute1_table() -> AttributeTable {
@ -291,7 +287,7 @@ fn load_attribute1_table() -> AttributeTable {
let mut table: HashMap<String, Vec<AttributeTier>> = toml::from_str(s.as_str()).unwrap(); let mut table: HashMap<String, Vec<AttributeTier>> = toml::from_str(s.as_str()).unwrap();
AttributeTable(table.remove("attributes".into()).unwrap()) AttributeTable(table.remove("attributes").unwrap())
} }
fn load_attribute2_table() -> AttributeTable { fn load_attribute2_table() -> AttributeTable {
@ -302,7 +298,7 @@ fn load_attribute2_table() -> AttributeTable {
let mut table: HashMap<String, Vec<AttributeTier>> = toml::from_str(s.as_str()).unwrap(); let mut table: HashMap<String, Vec<AttributeTier>> = toml::from_str(s.as_str()).unwrap();
AttributeTable(table.remove("attributes".into()).unwrap()) AttributeTable(table.remove("attributes").unwrap())
} }
fn number_of_weapons_to_generate(character_level: usize) -> usize { fn number_of_weapons_to_generate(character_level: usize) -> usize {
@ -333,8 +329,8 @@ pub struct WeaponShop<R: Rng + SeedableRng> {
impl<R: Rng + SeedableRng> WeaponShop<R> { impl<R: Rng + SeedableRng> WeaponShop<R> {
pub fn new(difficulty: Difficulty, section_id: SectionID) -> WeaponShop<R> { pub fn new(difficulty: Difficulty, section_id: SectionID) -> WeaponShop<R> {
WeaponShop { WeaponShop {
difficulty: difficulty, difficulty,
section_id: section_id, section_id,
weapon: load_weapon_table(difficulty, section_id), weapon: load_weapon_table(difficulty, section_id),
special: load_special_table(), special: load_special_table(),
grind: load_grind_table(), grind: load_grind_table(),
@ -381,8 +377,7 @@ impl<R: Rng + SeedableRng> WeaponShop<R> {
fn generate_alt_grind(&mut self, level: usize) -> usize { fn generate_alt_grind(&mut self, level: usize) -> usize {
let tier = self.alt_grind.0.iter() let tier = self.alt_grind.0.iter()
.filter(|t| t.level <= level) .find(|t| t.level <= level)
.nth(0)
.unwrap(); .unwrap();
self.rng.gen_range(tier.min, tier.max+1) self.rng.gen_range(tier.min, tier.max+1)
@ -410,7 +405,7 @@ impl<R: Rng + SeedableRng> WeaponShop<R> {
.choose(&mut self.rng)?; .choose(&mut self.rng)?;
Some(WeaponAttribute { Some(WeaponAttribute {
attr: attr, attr,
value: percent as i8, value: percent as i8,
}) })
} }
@ -437,54 +432,52 @@ impl<R: Rng + SeedableRng> WeaponShop<R> {
.choose(&mut self.rng)?; .choose(&mut self.rng)?;
Some(WeaponAttribute { Some(WeaponAttribute {
attr: attr, attr,
value: percent as i8, value: percent as i8,
}) })
} }
fn is_alt_grind(&self, weapon: &WeaponType) -> bool { fn is_alt_grind(&self, weapon: &WeaponType) -> bool {
match (self.section_id, weapon) { matches!((self.section_id, weapon),
(SectionID::Viridia, WeaponType::Shot) => true, (SectionID::Viridia, WeaponType::Shot) |
(SectionID::Viridia, WeaponType::Spread) => true, (SectionID::Viridia, WeaponType::Spread) |
(SectionID::Viridia, WeaponType::Cannon) => true, (SectionID::Viridia, WeaponType::Cannon) |
(SectionID::Viridia, WeaponType::Launcher) => true, (SectionID::Viridia, WeaponType::Launcher) |
(SectionID::Viridia, WeaponType::Arms) => true, (SectionID::Viridia, WeaponType::Arms) |
(SectionID::Greenill, WeaponType::Rifle) => true, (SectionID::Greenill, WeaponType::Rifle) |
(SectionID::Greenill, WeaponType::Sniper) => true, (SectionID::Greenill, WeaponType::Sniper) |
(SectionID::Greenill, WeaponType::Blaster) => true, (SectionID::Greenill, WeaponType::Blaster) |
(SectionID::Greenill, WeaponType::Beam) => true, (SectionID::Greenill, WeaponType::Beam) |
(SectionID::Greenill, WeaponType::Laser) => true, (SectionID::Greenill, WeaponType::Laser) |
(SectionID::Skyly, WeaponType::Sword) => true, (SectionID::Skyly, WeaponType::Sword) |
(SectionID::Skyly, WeaponType::Gigush) => true, (SectionID::Skyly, WeaponType::Gigush) |
(SectionID::Skyly, WeaponType::Breaker) => true, (SectionID::Skyly, WeaponType::Breaker) |
(SectionID::Skyly, WeaponType::Claymore) => true, (SectionID::Skyly, WeaponType::Claymore) |
(SectionID::Skyly, WeaponType::Calibur) => true, (SectionID::Skyly, WeaponType::Calibur) |
(SectionID::Bluefull, WeaponType::Partisan) => true, (SectionID::Bluefull, WeaponType::Partisan) |
(SectionID::Bluefull, WeaponType::Halbert) => true, (SectionID::Bluefull, WeaponType::Halbert) |
(SectionID::Bluefull, WeaponType::Glaive) => true, (SectionID::Bluefull, WeaponType::Glaive) |
(SectionID::Bluefull, WeaponType::Berdys) => true, (SectionID::Bluefull, WeaponType::Berdys) |
(SectionID::Bluefull, WeaponType::Gungnir) => true, (SectionID::Bluefull, WeaponType::Gungnir) |
(SectionID::Purplenum, WeaponType::Mechgun) => true, (SectionID::Purplenum, WeaponType::Mechgun) |
(SectionID::Purplenum, WeaponType::Assault) => true, (SectionID::Purplenum, WeaponType::Assault) |
(SectionID::Purplenum, WeaponType::Repeater) => true, (SectionID::Purplenum, WeaponType::Repeater) |
(SectionID::Purplenum, WeaponType::Gatling) => true, (SectionID::Purplenum, WeaponType::Gatling) |
(SectionID::Purplenum, WeaponType::Vulcan) => true, (SectionID::Purplenum, WeaponType::Vulcan) |
(SectionID::Pinkal, WeaponType::Cane) => true, (SectionID::Pinkal, WeaponType::Cane) |
(SectionID::Pinkal, WeaponType::Stick) => true, (SectionID::Pinkal, WeaponType::Stick) |
(SectionID::Pinkal, WeaponType::Mace) => true, (SectionID::Pinkal, WeaponType::Mace) |
(SectionID::Pinkal, WeaponType::Club) => true, (SectionID::Pinkal, WeaponType::Club) |
(SectionID::Oran, WeaponType::Dagger) => true, (SectionID::Oran, WeaponType::Dagger) |
(SectionID::Oran, WeaponType::Knife) => true, (SectionID::Oran, WeaponType::Knife) |
(SectionID::Oran, WeaponType::Blade) => true, (SectionID::Oran, WeaponType::Blade) |
(SectionID::Oran, WeaponType::Edge) => true, (SectionID::Oran, WeaponType::Edge) |
(SectionID::Oran, WeaponType::Ripper) => true, (SectionID::Oran, WeaponType::Ripper) |
(SectionID::Whitill, WeaponType::Slicer) => true, (SectionID::Whitill, WeaponType::Slicer) |
(SectionID::Whitill, WeaponType::Spinner) => true, (SectionID::Whitill, WeaponType::Spinner) |
(SectionID::Whitill, WeaponType::Cutter) => true, (SectionID::Whitill, WeaponType::Cutter) |
(SectionID::Whitill, WeaponType::Sawcer) => true, (SectionID::Whitill, WeaponType::Sawcer) |
(SectionID::Whitill, WeaponType::Diska) => true, (SectionID::Whitill, WeaponType::Diska))
_ => false,
}
} }
fn generate_weapon(&mut self, level: usize) -> WeaponShopItem { fn generate_weapon(&mut self, level: usize) -> WeaponShopItem {
@ -519,9 +512,9 @@ impl<R: Rng + SeedableRng> WeaponShop<R> {
}; };
WeaponShopItem { WeaponShopItem {
weapon: weapon, weapon,
grind: grind, grind,
special: special, special,
attributes: [attr1, attr2], attributes: [attr1, attr2],
} }
} }

View File

@ -13,7 +13,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_bank_items_sent_in_character_login() { async fn test_bank_items_sent_in_character_login() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -52,7 +52,7 @@ async fn test_bank_items_sent_in_character_login() {
#[async_std::test] #[async_std::test]
async fn test_request_bank_items() { async fn test_request_bank_items() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -104,7 +104,7 @@ async fn test_request_bank_items() {
#[async_std::test] #[async_std::test]
async fn test_request_stacked_bank_items() { async fn test_request_stacked_bank_items() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -151,7 +151,7 @@ async fn test_request_stacked_bank_items() {
#[async_std::test] #[async_std::test]
async fn test_request_bank_items_sorted() { async fn test_request_bank_items_sorted() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -229,7 +229,7 @@ async fn test_request_bank_items_sorted() {
#[async_std::test] #[async_std::test]
async fn test_deposit_individual_item() { async fn test_deposit_individual_item() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -308,7 +308,7 @@ async fn test_deposit_individual_item() {
#[async_std::test] #[async_std::test]
async fn test_deposit_stacked_item() { async fn test_deposit_stacked_item() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -372,7 +372,7 @@ async fn test_deposit_stacked_item() {
#[async_std::test] #[async_std::test]
async fn test_deposit_partial_stacked_item() { async fn test_deposit_partial_stacked_item() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -445,7 +445,7 @@ async fn test_deposit_partial_stacked_item() {
#[async_std::test] #[async_std::test]
async fn test_deposit_stacked_item_with_stack_already_in_bank() { async fn test_deposit_stacked_item_with_stack_already_in_bank() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -524,7 +524,7 @@ async fn test_deposit_stacked_item_with_stack_already_in_bank() {
#[async_std::test] #[async_std::test]
async fn test_deposit_stacked_item_with_full_stack_in_bank() { async fn test_deposit_stacked_item_with_full_stack_in_bank() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -603,7 +603,7 @@ async fn test_deposit_stacked_item_with_full_stack_in_bank() {
#[async_std::test] #[async_std::test]
async fn test_deposit_individual_item_in_full_bank() { async fn test_deposit_individual_item_in_full_bank() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -684,7 +684,7 @@ async fn test_deposit_individual_item_in_full_bank() {
#[async_std::test] #[async_std::test]
async fn test_deposit_stacked_item_in_full_bank() { async fn test_deposit_stacked_item_in_full_bank() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -764,7 +764,7 @@ async fn test_deposit_stacked_item_in_full_bank() {
#[async_std::test] #[async_std::test]
async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -858,7 +858,7 @@ async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() {
#[async_std::test] #[async_std::test]
async fn test_deposit_meseta() { async fn test_deposit_meseta() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.meseta = 300; char1.meseta = 300;
@ -895,7 +895,7 @@ async fn test_deposit_meseta() {
#[async_std::test] #[async_std::test]
async fn test_deposit_too_much_meseta() { async fn test_deposit_too_much_meseta() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.meseta = 300; char1.meseta = 300;
@ -934,7 +934,7 @@ async fn test_deposit_too_much_meseta() {
#[async_std::test] #[async_std::test]
async fn test_deposit_meseta_when_bank_is_maxed() { async fn test_deposit_meseta_when_bank_is_maxed() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.meseta = 300; char1.meseta = 300;
@ -973,7 +973,7 @@ async fn test_deposit_meseta_when_bank_is_maxed() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_individual_item() { async fn test_withdraw_individual_item() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -1039,7 +1039,7 @@ async fn test_withdraw_individual_item() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_stacked_item() { async fn test_withdraw_stacked_item() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -1103,7 +1103,7 @@ async fn test_withdraw_stacked_item() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_partial_stacked_item() { async fn test_withdraw_partial_stacked_item() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -1173,7 +1173,7 @@ async fn test_withdraw_partial_stacked_item() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { async fn test_withdraw_stacked_item_with_stack_already_in_inventory() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -1254,7 +1254,7 @@ async fn test_withdraw_stacked_item_with_stack_already_in_inventory() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_stacked_item_with_full_stack_in_inventory() { async fn test_withdraw_stacked_item_with_full_stack_in_inventory() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -1333,7 +1333,7 @@ async fn test_withdraw_stacked_item_with_full_stack_in_inventory() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_individual_item_in_full_inventory() { async fn test_withdraw_individual_item_in_full_inventory() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -1410,7 +1410,7 @@ async fn test_withdraw_individual_item_in_full_inventory() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_stacked_item_in_full_inventory() { async fn test_withdraw_stacked_item_in_full_inventory() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -1491,7 +1491,7 @@ async fn test_withdraw_stacked_item_in_full_inventory() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -1587,7 +1587,7 @@ async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_meseta() { async fn test_withdraw_meseta() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.bank_meseta = 300; char1.bank_meseta = 300;
@ -1624,7 +1624,7 @@ async fn test_withdraw_meseta() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_too_much_meseta() { async fn test_withdraw_too_much_meseta() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.meseta = 999980; char1.meseta = 999980;
@ -1662,7 +1662,7 @@ async fn test_withdraw_too_much_meseta() {
#[async_std::test] #[async_std::test]
async fn test_withdraw_meseta_inventory_is_maxed() { async fn test_withdraw_meseta_inventory_is_maxed() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.meseta = 999999; char1.meseta = 999999;

View File

@ -10,7 +10,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_save_options() { async fn test_save_options() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;

View File

@ -13,7 +13,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_character_gains_exp() { async fn test_character_gains_exp() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -50,7 +50,7 @@ async fn test_character_gains_exp() {
#[async_std::test] #[async_std::test]
async fn test_character_levels_up() { async fn test_character_levels_up() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 49; char1.exp = 49;
@ -83,14 +83,14 @@ async fn test_character_levels_up() {
assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 2, ..})}))); assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 2, ..})})));
let leveltable = CharacterLevelTable::new(); let leveltable = CharacterLevelTable::default();
let c1 = ship.clients.get(&ClientId(1)).unwrap(); let c1 = ship.clients.get(&ClientId(1)).unwrap();
assert!(leveltable.get_level_from_exp(c1.character.char_class, c1.character.exp) == 2); assert!(leveltable.get_level_from_exp(c1.character.char_class, c1.character.exp) == 2);
} }
#[async_std::test] #[async_std::test]
async fn test_character_levels_up_multiple_times() { async fn test_character_levels_up_multiple_times() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -134,7 +134,7 @@ async fn test_character_levels_up_multiple_times() {
#[async_std::test] #[async_std::test]
async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;

View File

@ -12,7 +12,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_equip_unit_from_equip_menu() { async fn test_equip_unit_from_equip_menu() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -98,7 +98,7 @@ async fn test_equip_unit_from_equip_menu() {
#[async_std::test] #[async_std::test]
async fn test_unequip_armor_with_units() { async fn test_unequip_armor_with_units() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -175,7 +175,7 @@ async fn test_unequip_armor_with_units() {
#[async_std::test] #[async_std::test]
async fn test_sort_items() { async fn test_sort_items() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;

View File

@ -12,7 +12,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_pick_up_item_stack_of_items_already_in_inventory() { async fn test_pick_up_item_stack_of_items_already_in_inventory() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -94,7 +94,7 @@ async fn test_pick_up_item_stack_of_items_already_in_inventory() {
#[async_std::test] #[async_std::test]
async fn test_pick_up_item_stack_of_items_not_already_held() { async fn test_pick_up_item_stack_of_items_not_already_held() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -156,7 +156,7 @@ async fn test_pick_up_item_stack_of_items_not_already_held() {
#[async_std::test] #[async_std::test]
async fn test_pick_up_meseta_when_inventory_full() { async fn test_pick_up_meseta_when_inventory_full() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -235,7 +235,7 @@ async fn test_pick_up_meseta_when_inventory_full() {
#[async_std::test] #[async_std::test]
async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() { async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -327,7 +327,7 @@ async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() {
#[async_std::test] #[async_std::test]
async fn test_can_not_pick_up_item_when_inventory_full() { async fn test_can_not_pick_up_item_when_inventory_full() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -423,7 +423,7 @@ async fn test_can_not_pick_up_item_when_inventory_full() {
#[async_std::test] #[async_std::test]
async fn test_can_not_drop_more_meseta_than_is_held() { async fn test_can_not_drop_more_meseta_than_is_held() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -464,7 +464,7 @@ async fn test_can_not_drop_more_meseta_than_is_held() {
#[async_std::test] #[async_std::test]
async fn test_pick_up_stack_that_would_exceed_stack_limit() { async fn test_pick_up_stack_that_would_exceed_stack_limit() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -544,7 +544,7 @@ async fn test_pick_up_stack_that_would_exceed_stack_limit() {
#[async_std::test] #[async_std::test]
async fn test_can_not_pick_up_meseta_when_full() { async fn test_can_not_pick_up_meseta_when_full() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -602,7 +602,7 @@ async fn test_can_not_pick_up_meseta_when_full() {
#[async_std::test] #[async_std::test]
async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -659,7 +659,7 @@ async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() {
#[async_std::test] #[async_std::test]
async fn test_player_drops_partial_stack_and_other_player_picks_it_up() { async fn test_player_drops_partial_stack_and_other_player_picks_it_up() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await;

View File

@ -14,7 +14,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_use_monomate() { async fn test_use_monomate() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -64,7 +64,7 @@ async fn test_use_monomate() {
#[async_std::test] #[async_std::test]
async fn test_use_monomate_twice() { async fn test_use_monomate_twice() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -119,7 +119,7 @@ async fn test_use_monomate_twice() {
#[async_std::test] #[async_std::test]
async fn test_use_last_monomate() { async fn test_use_last_monomate() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -164,7 +164,7 @@ async fn test_use_last_monomate() {
#[async_std::test] #[async_std::test]
async fn test_use_nonstackable_tool() { async fn test_use_nonstackable_tool() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -202,7 +202,7 @@ async fn test_use_nonstackable_tool() {
#[async_std::test] #[async_std::test]
async fn test_use_materials() { async fn test_use_materials() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;

View File

@ -13,7 +13,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_mag_feed() { async fn test_mag_feed() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -92,7 +92,7 @@ async fn test_mag_feed() {
#[async_std::test] #[async_std::test]
async fn test_mag_change_owner() { async fn test_mag_change_owner() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -160,7 +160,7 @@ async fn test_mag_change_owner() {
#[async_std::test] #[async_std::test]
async fn test_mag_cell() { async fn test_mag_cell() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;

View File

@ -13,7 +13,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_item_ids_reset_when_rejoining_rooms() { async fn test_item_ids_reset_when_rejoining_rooms() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await;

View File

@ -13,7 +13,7 @@ use common::*;
#[async_std::test] #[async_std::test]
async fn test_player_opens_weapon_shop() { async fn test_player_opens_weapon_shop() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -43,7 +43,7 @@ async fn test_player_opens_weapon_shop() {
#[async_std::test] #[async_std::test]
async fn test_player_opens_tool_shop() { async fn test_player_opens_tool_shop() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -73,7 +73,7 @@ async fn test_player_opens_tool_shop() {
#[async_std::test] #[async_std::test]
async fn test_player_opens_armor_shop() { async fn test_player_opens_armor_shop() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -103,7 +103,7 @@ async fn test_player_opens_armor_shop() {
#[async_std::test] #[async_std::test]
async fn test_player_buys_from_weapon_shop() { async fn test_player_buys_from_weapon_shop() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -142,7 +142,7 @@ async fn test_player_buys_from_weapon_shop() {
#[async_std::test] #[async_std::test]
async fn test_player_buys_from_tool_shop() { async fn test_player_buys_from_tool_shop() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -180,7 +180,7 @@ async fn test_player_buys_from_tool_shop() {
#[async_std::test] #[async_std::test]
async fn test_player_buys_multiple_from_tool_shop() { async fn test_player_buys_multiple_from_tool_shop() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -222,7 +222,7 @@ async fn test_player_buys_multiple_from_tool_shop() {
#[async_std::test] #[async_std::test]
async fn test_player_buys_from_armor_shop() { async fn test_player_buys_from_armor_shop() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -264,7 +264,7 @@ async fn test_player_sells_to_shop() {
#[async_std::test] #[async_std::test]
async fn test_other_clients_see_purchase() { async fn test_other_clients_see_purchase() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -307,7 +307,7 @@ async fn test_other_clients_see_purchase() {
#[async_std::test] #[async_std::test]
async fn test_other_clients_see_stacked_purchase() { async fn test_other_clients_see_stacked_purchase() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
@ -361,7 +361,7 @@ async fn test_other_clients_see_stacked_purchase() {
#[async_std::test] #[async_std::test]
async fn test_buying_item_without_enough_mseseta() { async fn test_buying_item_without_enough_mseseta() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
@ -397,7 +397,7 @@ async fn test_buying_item_without_enough_mseseta() {
#[async_std::test] #[async_std::test]
async fn test_player_double_buys_from_tool_shop() { async fn test_player_double_buys_from_tool_shop() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -463,7 +463,7 @@ async fn test_player_double_buys_from_tool_shop() {
#[async_std::test] #[async_std::test]
async fn test_techs_disappear_from_shop_when_bought() { async fn test_techs_disappear_from_shop_when_bought() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;
@ -525,7 +525,7 @@ async fn test_techs_disappear_from_shop_when_bought() {
// TOOD: this is not deterministic and can randomly fail // TOOD: this is not deterministic and can randomly fail
#[async_std::test] #[async_std::test]
async fn test_units_disappear_from_shop_when_bought() { async fn test_units_disappear_from_shop_when_bought() {
let mut entity_gateway = InMemoryGateway::new(); let mut entity_gateway = InMemoryGateway::default();
let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
char1.exp = 80000000; char1.exp = 80000000;