diff --git a/.drone.yml b/.drone.yml index ae267b5..49ef008 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,12 +1,24 @@ --- kind: pipeline type: docker -name: test elseware +name: test elseware concurrency: limit: 1 +environment: + CARGO_INCREMENTAL: false + steps: +- name: clean cache + image: rustlang/rust:nightly + volumes: + - name: cache + path: /usr/local/cargo + - name: target-cache + path: /drone/src/target + commands: + - cargo prune - name: build image: rustlang/rust:nightly volumes: @@ -33,7 +45,7 @@ steps: - name: target-cache path: /drone/src/target commands: - - cargo test + - cargo test --jobs 1 volumes: - name: cache diff --git a/Cargo.toml b/Cargo.toml index c2e511d..bbda680 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,46 @@ version = "0.1.0" authors = ["Jake Probst "] edition = "2021" -[dependencies] -libpso = { git = "http://git.sharnoth.com/jake/libpso" } +[workspace] +members = [ + "src/client", + "src/drops", + "src/entity", + "src/items", + "src/location", + "src/maps", + "src/networking", + "src/pktbuilder", + "src/quests", + "src/room", + "src/shops", + "src/stats", + "src/trade", + "src/patch_server", + "src/login_server", + "src/ship_server", +] + +[workspace.dependencies] +entity = { path = "./src/entity" } +maps = { path = "./src/maps" } +networking = { path = "./src/networking" } +shops = { path = "./src/shops" } +stats = { path = "./src/stats" } +items = { path = "./src/items" } +pktbuilder = { path = "./src/pktbuilder" } +quests = { path = "./src/quests" } +location = { path = "./src/location" } +client = { path = "./src/client" } +drops = { path = "./src/drops" } +trade = { path = "./src/trade" } +room = { path = "./src/room" } +patch_server = { path = "./src/patch_server" } +login_server = { path = "./src/login_server" } +ship_server = { path = "./src/ship_server" } + +libpso = { git = "http://git.sharnoth.com/jake/libpso", rev="90246b6" } + async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" rand = "0.7.3" @@ -27,9 +65,33 @@ ages-prs = "0.1" async-trait = "0.1.51" async-recursion= "1.0.0" lazy_static = "1.4.0" -barrel = { version = "0.6.5", features = ["pg"] } refinery = { version = "0.5.0", features = ["postgres"] } sqlx = { version = "0.6.2", features = ["runtime-async-std-native-tls", "postgres", "json", "chrono"] } strum = "0.19.5" strum_macros = "0.19" anyhow = { version = "1.0.68", features = ["backtrace"] } + +[dependencies] +entity = { workspace = true } +maps = { workspace = true } +networking = { workspace = true } +patch_server = { workspace = true } +login_server = { workspace = true } +ship_server = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +bcrypt = { workspace = true } +chrono = { workspace = true } +fern = { workspace = true } +futures = { workspace = true } +log = { workspace = true } + +[dev-dependencies] +drops = { workspace = true } +shops = { workspace = true } +items = { workspace = true } +quests = { workspace = true } +stats = { workspace = true } +async-trait = { workspace = true } \ No newline at end of file diff --git a/src/bin/login.rs b/src/bin/login.rs index f8b6b94..8f8832b 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -1,8 +1,8 @@ use log::{info}; -use elseware::entity::gateway::postgres::PostgresGateway; -use elseware::login::login::LoginServerState; -use elseware::login::character::CharacterServerState; -use elseware::common::interserver::AuthToken; +use entity::gateway::postgres::PostgresGateway; +use login_server::login::LoginServerState; +use login_server::character::CharacterServerState; +use networking::interserver::AuthToken; fn main() { let colors = fern::colors::ColoredLevelConfig::new() @@ -38,17 +38,17 @@ fn main() { let login_state = LoginServerState::new(entity_gateway.clone(), charserv_ip); let login_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await; + networking::mainloop::run_server(login_state, login_server::login::LOGIN_PORT).await; }); let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token)); let sub_char_state = char_state.clone(); let character_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await; + networking::mainloop::run_server(sub_char_state, login_server::character::CHARACTER_PORT).await; }); let inter_character_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_listen(char_state, elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_listen(char_state, login_server::login::COMMUNICATION_PORT).await; }); info!("[auth/character] starting server"); diff --git a/src/bin/main.rs b/src/bin/main.rs index 0a3ada0..ec67554 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,18 +1,18 @@ use std::net::Ipv4Addr; use log::{info}; -use elseware::common::interserver::AuthToken; -use elseware::login::login::LoginServerState; -use elseware::login::character::CharacterServerState; -use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd}; -use elseware::ship::ship::{ShipServerStateBuilder, ShipEvent}; +use networking::interserver::AuthToken; +use login_server::login::LoginServerState; +use login_server::character::CharacterServerState; +use patch_server::{PatchServerState, generate_patch_tree, load_config, load_motd}; +use ship_server::ShipServerStateBuilder; -#[allow(unused_imports)] -use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; -use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; -use elseware::entity::character::NewCharacterEntity; -use elseware::entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; -use elseware::entity::item; +use maps::Holiday; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; +use entity::character::NewCharacterEntity; +use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; +use entity::item; fn setup_logger() { let colors = fern::colors::ColoredLevelConfig::new() @@ -338,73 +338,73 @@ fn main() { let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str()); let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd); let patch_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(patch_state, patch_config.port).await; + networking::mainloop::run_server(patch_state, patch_config.port).await; }); info!("[auth] starting server"); let login_state = LoginServerState::new(entity_gateway.clone(), "127.0.0.1".parse().unwrap()); let login_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await; + networking::mainloop::run_server(login_state, login_server::login::LOGIN_PORT).await; }); info!("[character] starting server"); let char_state = CharacterServerState::new(entity_gateway.clone(), AuthToken("".into())); let sub_char_state = char_state.clone(); let character_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await; + networking::mainloop::run_server(sub_char_state, login_server::character::CHARACTER_PORT).await; }); let sub_char_state = char_state.clone(); let inter_character_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_listen(sub_char_state, elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_listen(sub_char_state, login_server::login::COMMUNICATION_PORT).await; }); info!("[ship] starting servers"); let ship_state = ShipServerStateBuilder::default() .name("US/Sona-Nyl".into()) .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT) - .event(ShipEvent::Halloween) + .port(ship_server::SHIP_PORT) + .event(Holiday::Halloween) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); let ship_loop1 = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await; + networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT).await; }); let sub_ship_state = ship_state.clone(); let inter_ship_loop1 = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await; }); let ship_state = ShipServerStateBuilder::default() .name("EU/Dylath-Leen".into()) .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT+2000) - .event(ShipEvent::Christmas) + .port(ship_server::SHIP_PORT+2000) + .event(Holiday::Christmas) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); let ship_loop2 = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+2000).await; + networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT+2000).await; }); let sub_ship_state = ship_state.clone(); let inter_ship_loop2 = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await; }); let ship_state = ShipServerStateBuilder::default() .name("JP/Thalarion".into()) .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT+3000) + .port(ship_server::SHIP_PORT+3000) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); let ship_loop3 = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+3000).await; + networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT+3000).await; }); let sub_ship_state = ship_state.clone(); let inter_ship_loop3 = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await; }); futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop, diff --git a/src/bin/patch.rs b/src/bin/patch.rs index e7304d8..c38f025 100644 --- a/src/bin/patch.rs +++ b/src/bin/patch.rs @@ -1,5 +1,5 @@ -use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config_env, load_motd}; -use log::{info}; +use patch_server::{PatchServerState, generate_patch_tree, load_config_env, load_motd}; +use log::info; fn main() { info!("[patch] starting server"); @@ -9,10 +9,8 @@ fn main() { let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd); let patch_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(patch_state, patch_config.port).await; + networking::mainloop::run_server(patch_state, patch_config.port).await; }); - async_std::task::block_on(async move { - patch_loop.await - }); + async_std::task::block_on(patch_loop); } diff --git a/src/bin/ship.rs b/src/bin/ship.rs index ff1ccc6..b664bda 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -1,7 +1,7 @@ -use log::{info}; -use elseware::entity::gateway::postgres::PostgresGateway; -use elseware::ship::ship::ShipServerStateBuilder; -use elseware::common::interserver::AuthToken; +use log::info; +use entity::gateway::postgres::PostgresGateway; +use ship_server::ShipServerStateBuilder; +use networking::interserver::AuthToken; fn main() { let colors = fern::colors::ColoredLevelConfig::new() @@ -40,7 +40,7 @@ fn main() { let ship_state = ShipServerStateBuilder::default() .name(ship_name) .ip(ip) - .port(elseware::ship::ship::SHIP_PORT) + .port(ship_server::SHIP_PORT) .gateway(entity_gateway) .auth_token(AuthToken(shipgate_token)) .build(); @@ -49,10 +49,10 @@ fn main() { let sub_ship_state = ship_state.clone(); let ship_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await; + networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT).await; }); let inter_ship_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_connect(ship_state, shipgate_ip, elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_connect(ship_state, shipgate_ip, login_server::login::COMMUNICATION_PORT).await; }); info!("[auth/character] starting server"); diff --git a/src/client/Cargo.toml b/src/client/Cargo.toml new file mode 100644 index 0000000..12f9698 --- /dev/null +++ b/src/client/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "client" +version = "0.1.0" +edition = "2021" + + +[dependencies] +entity = { workspace = true } +maps = { workspace = true } +networking = { workspace = true } +shops = { workspace = true } +items = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +futures = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } +chrono = { workspace = true } diff --git a/src/ship/client.rs b/src/client/src/lib.rs similarity index 83% rename from src/ship/client.rs rename to src/client/src/lib.rs index 5495309..fc91a37 100644 --- a/src/ship/client.rs +++ b/src/client/src/lib.rs @@ -6,15 +6,20 @@ use futures::future::BoxFuture; use libpso::packet::ship::*; use libpso::packet::login::Session; -use crate::common::serverstate::ClientId; -use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; -use crate::entity::character::CharacterEntity; -use crate::entity::item; +use networking::serverstate::ClientId; +use entity::account::{UserAccountEntity, UserSettingsEntity}; +use entity::character::CharacterEntity; +use entity::item; -use crate::ship::ship::ShipError; -use crate::ship::items; -use crate::ship::map::MapArea; -use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; +use maps::area::MapArea; +use shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; + + +#[derive(thiserror::Error, Debug)] +pub enum ClientError { + #[error("not found {0}")] + NotFound(ClientId), +} #[derive(Clone, Default)] @@ -46,7 +51,7 @@ impl Clients { .await; let client = clients .get(&client_id) - .ok_or_else(|| ShipError::ClientNotFound(client_id))? + .ok_or(ClientError::NotFound(client_id))? .read() .await; @@ -69,17 +74,14 @@ impl Clients { for (cindex, client_id) in client_ids.iter().enumerate() { let c = clients .get(client_id) - .ok_or_else(|| ShipError::ClientNotFound(*client_id))? + .ok_or(ClientError::NotFound(*client_id))? .read() .await; client_states[cindex].write(c); } let client_states = unsafe { - // TODO: this should just be a normal transmute but due to compiler limitations it - // does not yet work with const generics - // https://github.com/rust-lang/rust/issues/61956 - std::mem::transmute_copy::<_, [RwLockReadGuard; N]>(&client_states) + std::mem::transmute_copy(&client_states) }; Ok(func(client_states).await) @@ -95,7 +97,7 @@ impl Clients { .await; let mut client = clients .get(&client_id) - .ok_or_else(|| ShipError::ClientNotFound(client_id))? + .ok_or(ClientError::NotFound(client_id))? .write() .await; diff --git a/src/common/mod.rs b/src/common/mod.rs deleted file mode 100644 index d02076e..0000000 --- a/src/common/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -pub mod cipherkeys; -pub mod serverstate; -pub mod mainloop; -pub mod leveltable; -pub mod interserver; - -// https://www.reddit.com/r/rust/comments/33xhhu/how_to_create_an_array_of_structs_that_havent/ -#[macro_export] -macro_rules! init_array( - ($ty:ty, $len:expr, $val:expr) => ( - { - let mut array: [$ty; $len] = unsafe { std::mem::uninitialized() }; - for i in array.iter_mut() { - unsafe { ::std::ptr::write(i, $val); } - } - array - } - ) -); diff --git a/src/drops/Cargo.toml b/src/drops/Cargo.toml new file mode 100644 index 0000000..199e7c6 --- /dev/null +++ b/src/drops/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "drops" +version = "0.1.0" +edition = "2021" + + +[dependencies] +entity = { workspace = true } +maps = { workspace = true } +stats = { workspace = true } + +rand = { workspace = true } +rand_chacha = { workspace = true } +serde = { workspace = true } +enum-utils = { workspace = true } +toml = { workspace = true } +chrono = { workspace = true } \ No newline at end of file diff --git a/src/ship/drops/box_drop_table.rs b/src/drops/src/box_drop_table.rs similarity index 91% rename from src/ship/drops/box_drop_table.rs rename to src/drops/src/box_drop_table.rs index ae75b58..01f41eb 100644 --- a/src/ship/drops/box_drop_table.rs +++ b/src/drops/src/box_drop_table.rs @@ -2,18 +2,17 @@ use rand::{Rng}; use rand::distributions::{WeightedIndex, Distribution}; use serde::{Serialize, Deserialize}; -use crate::entity::character::SectionID; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::map::{MapObject, MapObjectType, FixedBoxDropType}; -use crate::ship::drops::rare_drop_table::{RareDropTable, RareDropItem}; -use crate::ship::drops::generic_weapon::GenericWeaponTable; -use crate::ship::drops::generic_armor::GenericArmorTable; -use crate::ship::drops::generic_shield::GenericShieldTable; -use crate::ship::drops::generic_unit::GenericUnitTable; -use crate::ship::drops::tool_table::ToolTable; -use crate::entity::item::ItemDetail; +use entity::character::SectionID; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use maps::object::{MapObject, MapObjectType, FixedBoxDropType}; +use crate::rare_drop_table::{RareDropTable, RareDropItem}; +use crate::generic_weapon::GenericWeaponTable; +use crate::generic_armor::GenericArmorTable; +use crate::generic_shield::GenericShieldTable; +use crate::generic_unit::GenericUnitTable; +use crate::tool_table::ToolTable; #[derive(Debug, Serialize, Deserialize)] struct BoxDropRate { @@ -177,7 +176,7 @@ impl BoxDropTable { self.rare_drop(map_area, rng).or_else(|| { let rate = self.box_rates.rates_by_area(map_area); let type_weights = WeightedIndex::new([rate.weapon_rate, rate.armor_rate, rate.shield_rate, rate.unit_rate, - rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap(); + rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap(); let btype = type_weights.sample(rng); match btype { 0 => self.weapon_table.get_drop(map_area, rng), @@ -204,7 +203,7 @@ impl BoxDropTable { FixedBoxDropType::Specific(value) => { let mut buf: [u8; 16] = [0; 16]; buf[0..4].copy_from_slice(&u32::to_be_bytes(value)); - ItemDetail::parse_item_from_bytes(buf) + ItemDropType::parse_item_from_bytes(buf) }, } } diff --git a/src/ship/drops/generic_armor.rs b/src/drops/src/generic_armor.rs similarity index 90% rename from src/ship/drops/generic_armor.rs rename to src/drops/src/generic_armor.rs index 667aadc..82e9a58 100644 --- a/src/ship/drops/generic_armor.rs +++ b/src/drops/src/generic_armor.rs @@ -1,14 +1,14 @@ use std::collections::HashMap; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::armor::{ArmorType, Armor}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{armor_stats, ArmorStats}; +use entity::character::SectionID; +use entity::item::armor::{ArmorType, Armor}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use stats::items::{armor_stats, ArmorStats}; #[derive(Debug, Serialize, Deserialize)] @@ -47,7 +47,7 @@ impl GenericArmorTable { fn armor_type(&self, area_map: &MapArea, rng: &mut R) -> ArmorType { let rank_weights = WeightedIndex::new([self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2, - self.rank_rates.rank3, self.rank_rates.rank4]).unwrap(); + self.rank_rates.rank3, self.rank_rates.rank4]).unwrap(); let rank = rank_weights.sample(rng) as i32; let armor_level = std::cmp::max(0i32, self.armor_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32); match armor_level { @@ -81,7 +81,7 @@ impl GenericArmorTable { pub fn slots(&self, _area_map: &MapArea, rng: &mut R) -> usize { let slot_weights = WeightedIndex::new([self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2, - self.slot_rates.slot3, self.slot_rates.slot4]).unwrap(); + self.slot_rates.slot3, self.slot_rates.slot4]).unwrap(); slot_weights.sample(rng) } diff --git a/src/ship/drops/generic_shield.rs b/src/drops/src/generic_shield.rs similarity index 91% rename from src/ship/drops/generic_shield.rs rename to src/drops/src/generic_shield.rs index 8d17e26..c7bbf1f 100644 --- a/src/ship/drops/generic_shield.rs +++ b/src/drops/src/generic_shield.rs @@ -1,14 +1,14 @@ use std::collections::HashMap; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::shield::{ShieldType, Shield}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{shield_stats, ShieldStats}; +use entity::item::shield::{ShieldType, Shield}; +use entity::character::SectionID; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use stats::items::{shield_stats, ShieldStats}; #[derive(Debug, Serialize, Deserialize)] @@ -37,7 +37,7 @@ impl GenericShieldTable { fn shield_type(&self, area_map: &MapArea, rng: &mut R) -> ShieldType { let rank_weights = WeightedIndex::new([self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2, - self.rank_rates.rank3, self.rank_rates.rank4]).unwrap(); + self.rank_rates.rank3, self.rank_rates.rank4]).unwrap(); let rank = rank_weights.sample(rng) as i32; let shield_level = std::cmp::max(0i32, self.shield_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32); match shield_level { diff --git a/src/ship/drops/generic_unit.rs b/src/drops/src/generic_unit.rs similarity index 92% rename from src/ship/drops/generic_unit.rs rename to src/drops/src/generic_unit.rs index 73bc4a6..cc1caa0 100644 --- a/src/ship/drops/generic_unit.rs +++ b/src/drops/src/generic_unit.rs @@ -1,14 +1,14 @@ use std::collections::BTreeMap; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::seq::IteratorRandom; -use crate::entity::item::unit::{UnitType, Unit, UnitModifier}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{unit_stats, UnitStats}; +use entity::character::SectionID; +use entity::item::unit::{UnitType, Unit, UnitModifier}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use stats::items::{unit_stats, UnitStats}; diff --git a/src/ship/drops/generic_weapon.rs b/src/drops/src/generic_weapon.rs similarity index 98% rename from src/ship/drops/generic_weapon.rs rename to src/drops/src/generic_weapon.rs index 290b267..557130c 100644 --- a/src/ship/drops/generic_weapon.rs +++ b/src/drops/src/generic_weapon.rs @@ -1,14 +1,14 @@ use std::collections::{HashMap, BTreeMap}; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; use rand::seq::SliceRandom; -use crate::entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; +use entity::character::SectionID; +use entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; diff --git a/src/ship/drops/mod.rs b/src/drops/src/lib.rs similarity index 76% rename from src/ship/drops/mod.rs rename to src/drops/src/lib.rs index 5d8062c..32a14db 100644 --- a/src/ship/drops/mod.rs +++ b/src/drops/src/lib.rs @@ -5,7 +5,6 @@ // to their drops -mod drop_table; pub mod rare_drop_table; mod generic_weapon; mod generic_armor; @@ -22,19 +21,19 @@ use std::io::Read; use serde::{Serialize, Deserialize}; use rand::{Rng, SeedableRng}; -use crate::ship::monster::MonsterType; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::generic_weapon::GenericWeaponTable; -use crate::ship::drops::generic_armor::GenericArmorTable; -use crate::ship::drops::generic_shield::GenericShieldTable; -use crate::ship::drops::generic_unit::GenericUnitTable; -use crate::ship::drops::tool_table::ToolTable; -use crate::ship::drops::rare_drop_table::RareDropTable; -use crate::ship::drops::box_drop_table::BoxDropTable; -use crate::ship::map::MapObject; -use crate::entity::item::{weapon, armor, shield, unit, mag, tool, tech}; +use maps::monster::MonsterType; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; +use crate::generic_weapon::GenericWeaponTable; +use crate::generic_armor::GenericArmorTable; +use crate::generic_shield::GenericShieldTable; +use crate::generic_unit::GenericUnitTable; +use crate::tool_table::ToolTable; +use crate::rare_drop_table::RareDropTable; +use crate::box_drop_table::BoxDropTable; +use maps::object::MapObject; +use entity::item::{ItemType, weapon, armor, shield, unit, mag, tool, tech, esweapon}; fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf { @@ -55,18 +54,6 @@ pub fn load_data_file(episode: Episode, difficul toml::from_str::(s.as_str()).unwrap() } -// this is just copypaste -pub fn load_rare_monster_file(episode: Episode) -> T { - // TODO: where does the rare monster toml file actually live - let mut path = PathBuf::from("data/battle_param/"); - path.push(episode.to_string().to_lowercase() + "_rare_monster.toml"); - - let mut f = File::open(path).unwrap(); - let mut s = String::new(); - f.read_to_string(&mut s); - toml::from_str::(s.as_str()).unwrap() -} - #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub enum MonsterDropType { #[serde(rename = "weapon")] @@ -102,6 +89,28 @@ pub enum ItemDropType { Meseta(u32), } +impl ItemDropType { + pub fn parse_item_from_bytes(data: [u8; 16]) -> Option { + let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon) + .or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor)) + .or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield)) + .or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit)) + .or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag)) + .or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool)) + .or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?; + + match item_type { + ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)), + ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)), + ItemType::Shield(_s) => Some(ItemDropType::Shield(shield::Shield::from_bytes(data).ok()?)), + ItemType::Unit(_u) => Some(ItemDropType::Unit(unit::Unit::from_bytes(data).ok()?)), + ItemType::Mag(_m) => Some(ItemDropType::Mag(mag::Mag::from_bytes(data).ok()?)), + ItemType::Tool(_t) => Some(ItemDropType::Tool(tool::Tool::from_bytes(data).ok()?)), + _ => None, + } + } +} + #[derive(Clone, Debug)] pub struct ItemDrop { pub map_area: MapArea, @@ -112,7 +121,12 @@ pub struct ItemDrop { } -pub struct DropTable { +pub trait DropTable { + fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option; + fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option; +} + +pub struct StandardDropTable { monster_stats: HashMap, rare_table: RareDropTable, weapon_table: GenericWeaponTable, @@ -124,11 +138,12 @@ pub struct DropTable { rng: rand_chacha::ChaCha20Rng, } -impl DropTable { - pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable { +impl StandardDropTable { + #[allow(clippy::new_ret_no_self)] + pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box { let monster_stats: HashMap = load_data_file(episode, difficulty, section_id, "monster_dar.toml"); - - DropTable { + + Box::new(StandardDropTable { monster_stats: monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect(), rare_table: RareDropTable::new(episode, difficulty, section_id), weapon_table: GenericWeaponTable::new(episode, difficulty, section_id), @@ -138,7 +153,7 @@ impl DropTable { tool_table: ToolTable::new(episode, difficulty, section_id), box_table: BoxDropTable::new(episode, difficulty, section_id), rng: rand_chacha::ChaCha20Rng::from_entropy(), - } + }) } pub fn builder() -> DropTableBuilder { @@ -168,8 +183,10 @@ impl DropTable { MonsterDropType::None => None, } } +} - pub fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option { +impl DropTable for StandardDropTable { + fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option { let monster_stat = *self.monster_stats.get(monster)?; let drop_anything = self.rng.gen_range(0, 100); @@ -182,7 +199,7 @@ impl DropTable { } let drop_type = self.rng.gen_range(0, 3); - + match drop_type { 0 => { self.generate_meseta(&monster_stat) @@ -197,7 +214,7 @@ impl DropTable { } } - pub fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option { + fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option { self.box_table.get_drop(map_area, object, &mut self.rng) } } @@ -244,8 +261,8 @@ impl DropTableBuilder { self } - pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable { - DropTable { + pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box { + Box::new(StandardDropTable { monster_stats: self.monster_stats.unwrap_or_else(|| { let monster_stats: HashMap = load_data_file(episode, difficulty, section_id, "monster_dar.toml"); monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect() @@ -258,11 +275,10 @@ impl DropTableBuilder { tool_table: self.tool_table.unwrap_or_else(|| ToolTable::new(episode, difficulty, section_id)), box_table: self.box_table.unwrap_or_else(|| BoxDropTable::new(episode, difficulty, section_id)), rng: self.rng.unwrap_or_else(rand_chacha::ChaCha20Rng::from_entropy), - } + }) } } - #[cfg(test)] mod test { use super::*; diff --git a/src/ship/drops/rare_drop_table.rs b/src/drops/src/rare_drop_table.rs similarity index 90% rename from src/ship/drops/rare_drop_table.rs rename to src/drops/src/rare_drop_table.rs index 51151ba..b9ab745 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/drops/src/rare_drop_table.rs @@ -1,20 +1,20 @@ use std::collections::HashMap; use rand::Rng; use serde::{Serialize, Deserialize}; -use crate::entity::item::weapon::{Weapon, WeaponType}; -use crate::entity::item::armor::{Armor, ArmorType}; -use crate::entity::item::shield::{Shield, ShieldType}; -use crate::entity::item::unit::{Unit, UnitType}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::mag::{Mag, MagType}; -use crate::entity::character::SectionID; -use crate::ship::monster::MonsterType; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::drops::generic_weapon::AttributeTable; -use crate::ship::drops::generic_armor::GenericArmorTable; -use crate::ship::drops::generic_shield::GenericShieldTable; +use entity::item::weapon::{Weapon, WeaponType}; +use entity::item::armor::{Armor, ArmorType}; +use entity::item::shield::{Shield, ShieldType}; +use entity::item::unit::{Unit, UnitType}; +use entity::item::tool::{Tool, ToolType}; +use entity::item::mag::{Mag, MagType}; +use entity::character::SectionID; +use maps::monster::MonsterType; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use crate::generic_weapon::AttributeTable; +use crate::generic_armor::GenericArmorTable; +use crate::generic_shield::GenericShieldTable; type ItemParseFn = Box Option>; diff --git a/src/ship/drops/tech_table.rs b/src/drops/src/tech_table.rs similarity index 95% rename from src/ship/drops/tech_table.rs rename to src/drops/src/tech_table.rs index 6e6396f..9b1101b 100644 --- a/src/ship/drops/tech_table.rs +++ b/src/drops/src/tech_table.rs @@ -3,11 +3,11 @@ use serde::{Serialize, Deserialize}; use rand::{Rng}; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::tech::{Technique, TechniqueDisk}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; +use entity::item::tech::{Technique, TechniqueDisk}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; +use crate::{ItemDropType, load_data_file}; diff --git a/src/ship/drops/tool_table.rs b/src/drops/src/tool_table.rs similarity index 94% rename from src/ship/drops/tool_table.rs rename to src/drops/src/tool_table.rs index 69a14cd..9645c34 100644 --- a/src/ship/drops/tool_table.rs +++ b/src/drops/src/tool_table.rs @@ -1,14 +1,14 @@ -use std::collections::{BTreeMap}; +use std::collections::BTreeMap; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::drops::tech_table::TechniqueTable; +use entity::item::tool::{Tool, ToolType}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; +use crate::{ItemDropType, load_data_file}; +use crate::tech_table::TechniqueTable; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, enum_utils::FromStr)] diff --git a/src/entity/Cargo.toml b/src/entity/Cargo.toml new file mode 100644 index 0000000..ce90e98 --- /dev/null +++ b/src/entity/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "entity" +version = "0.1.0" +edition = "2021" + +[dependencies] +libpso = { workspace = true } +maps = { workspace = true } +chrono = { workspace = true } +anyhow = { workspace = true } +async-std = { workspace = true } +sqlx = { workspace = true } +thiserror = { workspace = true } +serde = { workspace = true } +async-trait = { workspace = true } +enum-utils = { workspace = true } +derive_more = { workspace = true } +refinery = { workspace = true } +lazy_static = { workspace = true } +futures = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } +toml = { workspace = true } diff --git a/src/entity/gateway/postgres/migrations/mod.rs b/src/entity/gateway/postgres/migrations/mod.rs deleted file mode 100644 index 533298a..0000000 --- a/src/entity/gateway/postgres/migrations/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -use refinery::include_migration_mods; - -include_migration_mods!("src/entity/gateway/postgres/migrations"); diff --git a/src/entity/account.rs b/src/entity/src/account.rs similarity index 100% rename from src/entity/account.rs rename to src/entity/src/account.rs diff --git a/src/entity/character.rs b/src/entity/src/character.rs similarity index 98% rename from src/entity/character.rs rename to src/entity/src/character.rs index 080bb1b..d766f28 100644 --- a/src/entity/character.rs +++ b/src/entity/src/character.rs @@ -4,8 +4,8 @@ use serde::{Serialize, Deserialize}; use libpso::packet::ship::{UpdateConfig, WriteInfoboard}; use libpso::character::settings::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU}; -use crate::entity::item::tech::Technique; -use crate::entity::account::UserAccountId; +use crate::item::tech::Technique; +use crate::account::UserAccountId; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, enum_utils::FromStr, derive_more::Display, Serialize, Deserialize, Default)] pub enum CharacterClass { @@ -223,7 +223,7 @@ impl CharacterInfoboard { } pub fn update_infoboard(&mut self, new_board: &WriteInfoboard) { - self.board = libpso::utf8_to_utf16_array!(new_board.message, 172); + self.board = libpso::util::utf8_to_utf16_array(&new_board.message); } } diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/src/gateway/entitygateway.rs similarity index 98% rename from src/entity/gateway/entitygateway.rs rename to src/entity/src/gateway/entitygateway.rs index df922ac..4f7ae67 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/src/gateway/entitygateway.rs @@ -1,10 +1,10 @@ use thiserror::Error; use futures::future::{Future, BoxFuture}; -use crate::entity::account::*; -use crate::entity::character::*; -use crate::entity::item::*; -use crate::entity::room::*; +use crate::account::*; +use crate::character::*; +use crate::item::*; +use crate::room::*; // TODO: better granularity? diff --git a/src/entity/gateway/inmemory.rs b/src/entity/src/gateway/inmemory.rs similarity index 99% rename from src/entity/gateway/inmemory.rs rename to src/entity/src/gateway/inmemory.rs index 50a650e..970beed 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/src/gateway/inmemory.rs @@ -2,11 +2,11 @@ use std::collections::BTreeMap; use std::convert::TryInto; use futures::future::{Future, BoxFuture}; -use crate::entity::account::*; -use crate::entity::character::*; -use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; -use crate::entity::item::*; -use crate::entity::room::*; +use crate::account::*; +use crate::character::*; +use crate::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; +use crate::item::*; +use crate::room::*; use async_std::sync::{Arc, Mutex}; diff --git a/src/entity/gateway/mod.rs b/src/entity/src/gateway/mod.rs similarity index 100% rename from src/entity/gateway/mod.rs rename to src/entity/src/gateway/mod.rs diff --git a/src/entity/gateway/postgres/migrations/V0001__initial.sql b/src/entity/src/gateway/postgres/migrations/V0001__initial.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0001__initial.sql rename to src/entity/src/gateway/postgres/migrations/V0001__initial.sql diff --git a/src/entity/gateway/postgres/migrations/V0002__equips.sql b/src/entity/src/gateway/postgres/migrations/V0002__equips.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0002__equips.sql rename to src/entity/src/gateway/postgres/migrations/V0002__equips.sql diff --git a/src/entity/gateway/postgres/migrations/V0003__item_notes.sql b/src/entity/src/gateway/postgres/migrations/V0003__item_notes.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0003__item_notes.sql rename to src/entity/src/gateway/postgres/migrations/V0003__item_notes.sql diff --git a/src/entity/gateway/postgres/migrations/V0004__meseta.sql b/src/entity/src/gateway/postgres/migrations/V0004__meseta.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0004__meseta.sql rename to src/entity/src/gateway/postgres/migrations/V0004__meseta.sql diff --git a/src/entity/gateway/postgres/migrations/V0005__trade.sql b/src/entity/src/gateway/postgres/migrations/V0005__trade.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0005__trade.sql rename to src/entity/src/gateway/postgres/migrations/V0005__trade.sql diff --git a/src/entity/gateway/postgres/migrations/V0006__playtime.sql b/src/entity/src/gateway/postgres/migrations/V0006__playtime.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0006__playtime.sql rename to src/entity/src/gateway/postgres/migrations/V0006__playtime.sql diff --git a/src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql b/src/entity/src/gateway/postgres/migrations/V0007__player_keyconfig.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql rename to src/entity/src/gateway/postgres/migrations/V0007__player_keyconfig.sql diff --git a/src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql b/src/entity/src/gateway/postgres/migrations/V0008__playtime_not_null.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql rename to src/entity/src/gateway/postgres/migrations/V0008__playtime_not_null.sql diff --git a/src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql b/src/entity/src/gateway/postgres/migrations/V0009__no_player_keyconfig.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql rename to src/entity/src/gateway/postgres/migrations/V0009__no_player_keyconfig.sql diff --git a/src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql b/src/entity/src/gateway/postgres/migrations/V0010__char_create_timestamp.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql rename to src/entity/src/gateway/postgres/migrations/V0010__char_create_timestamp.sql diff --git a/src/entity/gateway/postgres/migrations/V0011__shared_bank.sql b/src/entity/src/gateway/postgres/migrations/V0011__shared_bank.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0011__shared_bank.sql rename to src/entity/src/gateway/postgres/migrations/V0011__shared_bank.sql diff --git a/src/entity/gateway/postgres/migrations/V0012__room.sql b/src/entity/src/gateway/postgres/migrations/V0012__room.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0012__room.sql rename to src/entity/src/gateway/postgres/migrations/V0012__room.sql diff --git a/src/entity/gateway/postgres/migrations/V0013__room2.sql b/src/entity/src/gateway/postgres/migrations/V0013__room2.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0013__room2.sql rename to src/entity/src/gateway/postgres/migrations/V0013__room2.sql diff --git a/src/entity/src/gateway/postgres/migrations/mod.rs b/src/entity/src/gateway/postgres/migrations/mod.rs new file mode 100644 index 0000000..fd67f6f --- /dev/null +++ b/src/entity/src/gateway/postgres/migrations/mod.rs @@ -0,0 +1,3 @@ +use refinery::include_migration_mods; + +include_migration_mods!("src/gateway/postgres/migrations"); diff --git a/src/entity/gateway/postgres/mod.rs b/src/entity/src/gateway/postgres/mod.rs similarity index 100% rename from src/entity/gateway/postgres/mod.rs rename to src/entity/src/gateway/postgres/mod.rs diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/src/gateway/postgres/models.rs similarity index 98% rename from src/entity/gateway/postgres/models.rs rename to src/entity/src/gateway/postgres/models.rs index f3a2f39..a7cfe94 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/src/gateway/postgres/models.rs @@ -4,13 +4,13 @@ use std::convert::Into; use serde::{Serialize, Deserialize}; use libpso::character::settings; use libpso::util::vec_to_array; -use crate::entity::account::*; -use crate::entity::character::*; -use crate::entity::item::*; -use crate::entity::room::*; -use crate::ship::map::MapArea; -use crate::ship::room::{Episode, Difficulty}; -use crate::ship::monster::MonsterType; +use crate::account::*; +use crate::character::*; +use crate::item::*; +use crate::room::*; +use maps::area::MapArea; +use maps::room::{Episode, Difficulty}; +use maps::monster::MonsterType; #[derive(Debug, sqlx::FromRow)] pub struct PgUserAccount { @@ -253,7 +253,7 @@ impl From for CharacterEntity { raw_data: vec_to_array(other.config) }, info_board: CharacterInfoboard { - board: libpso::utf8_to_utf16_array!(other.infoboard, 172), + board: libpso::util::utf8_to_utf16_array(other.infoboard), }, guildcard: CharacterGuildCard { description: other.guildcard, diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/src/gateway/postgres/postgres.rs similarity index 99% rename from src/entity/gateway/postgres/postgres.rs rename to src/entity/src/gateway/postgres/postgres.rs index c31217f..f1219ba 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/src/gateway/postgres/postgres.rs @@ -1,16 +1,16 @@ // this lint is currently bugged and suggests incorrect code https://github.com/rust-lang/rust-clippy/issues/9123 #![allow(clippy::explicit_auto_deref)] -use std::convert::{From, TryFrom, Into}; +use std::convert::{From, Into}; use futures::future::{Future, BoxFuture}; use futures::stream::{StreamExt, FuturesOrdered}; use async_std::sync::{Arc, Mutex}; use libpso::character::guildcard; -use crate::entity::account::*; -use crate::entity::character::*; -use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; -use crate::entity::item::*; -use crate::entity::room::*; +use crate::account::*; +use crate::character::*; +use crate::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; +use crate::item::*; +use crate::room::*; use super::models::*; use sqlx::postgres::PgPoolOptions; @@ -19,7 +19,7 @@ use sqlx::Connection; mod embedded { use refinery::embed_migrations; - embed_migrations!("src/entity/gateway/postgres/migrations"); + embed_migrations!("src/gateway/postgres/migrations"); } diff --git a/src/entity/item/armor.rs b/src/entity/src/item/armor.rs similarity index 99% rename from src/entity/item/armor.rs rename to src/entity/src/item/armor.rs index 45e9ed4..bd0cc48 100644 --- a/src/entity/item/armor.rs +++ b/src/entity/src/item/armor.rs @@ -1,5 +1,5 @@ use serde::{Serialize, Deserialize}; -use crate::entity::item::ItemEntityId; +use crate::item::ItemEntityId; #[derive(Debug, Copy, Clone)] pub enum ItemParseError { diff --git a/src/entity/item/esweapon.rs b/src/entity/src/item/esweapon.rs similarity index 100% rename from src/entity/item/esweapon.rs rename to src/entity/src/item/esweapon.rs diff --git a/src/entity/item/mag.rs b/src/entity/src/item/mag.rs similarity index 99% rename from src/entity/item/mag.rs rename to src/entity/src/item/mag.rs index b865c62..9469a2c 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/src/item/mag.rs @@ -1,9 +1,9 @@ -use thiserror::Error; use std::collections::HashMap; +use thiserror::Error; use serde::{Serialize, Deserialize}; -use crate::entity::item::tool::ToolType; -use crate::entity::character::{CharacterClass, SectionID}; -use crate::entity::item::ItemEntityId; +use crate::item::tool::ToolType; +use crate::character::{CharacterClass, SectionID}; +use crate::item::ItemEntityId; use std::io::Read; use std::cmp::Ordering::{Less, Greater, Equal}; diff --git a/src/entity/item/mod.rs b/src/entity/src/item/mod.rs similarity index 84% rename from src/entity/item/mod.rs rename to src/entity/src/item/mod.rs index 7023f7c..d418579 100644 --- a/src/entity/item/mod.rs +++ b/src/entity/src/item/mod.rs @@ -9,11 +9,11 @@ pub mod mag; pub mod esweapon; use serde::{Serialize, Deserialize}; -use crate::entity::character::CharacterEntityId; -use crate::entity::room::RoomEntityId; -use crate::ship::map::MapArea; -use crate::ship::monster::MonsterType; -use crate::ship::drops::ItemDropType; +use crate::character::CharacterEntityId; +use crate::room::RoomEntityId; +use maps::area::MapArea; +use maps::monster::MonsterType; +//use crate::ship::drops::ItemDropType; #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)] pub struct ItemEntityId(pub u32); @@ -156,26 +156,6 @@ impl ItemDetail { } } - pub fn parse_item_from_bytes(data: [u8; 16]) -> Option { - let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon) - .or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor)) - .or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield)) - .or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit)) - .or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag)) - .or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool)) - .or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?; - - match item_type { - ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)), - ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)), - ItemType::Shield(_s) => Some(ItemDropType::Shield(shield::Shield::from_bytes(data).ok()?)), - ItemType::Unit(_u) => Some(ItemDropType::Unit(unit::Unit::from_bytes(data).ok()?)), - ItemType::Mag(_m) => Some(ItemDropType::Mag(mag::Mag::from_bytes(data).ok()?)), - ItemType::Tool(_t) => Some(ItemDropType::Tool(tool::Tool::from_bytes(data).ok()?)), - _ => None, - } - } - pub fn as_client_bytes(&self) -> [u8; 16] { match self { ItemDetail::Weapon(w) => w.as_bytes(), diff --git a/src/entity/item/shield.rs b/src/entity/src/item/shield.rs similarity index 100% rename from src/entity/item/shield.rs rename to src/entity/src/item/shield.rs diff --git a/src/entity/item/tech.rs b/src/entity/src/item/tech.rs similarity index 100% rename from src/entity/item/tech.rs rename to src/entity/src/item/tech.rs diff --git a/src/entity/item/tool.rs b/src/entity/src/item/tool.rs similarity index 100% rename from src/entity/item/tool.rs rename to src/entity/src/item/tool.rs diff --git a/src/entity/item/unit.rs b/src/entity/src/item/unit.rs similarity index 100% rename from src/entity/item/unit.rs rename to src/entity/src/item/unit.rs diff --git a/src/entity/item/weapon.rs b/src/entity/src/item/weapon.rs similarity index 99% rename from src/entity/item/weapon.rs rename to src/entity/src/item/weapon.rs index 29a9357..a5753d6 100644 --- a/src/entity/item/weapon.rs +++ b/src/entity/src/item/weapon.rs @@ -1,4 +1,4 @@ -use crate::entity::item::ItemEntityId; +use crate::item::ItemEntityId; use serde::{Serialize, Deserialize}; #[derive(Debug, Copy, Clone)] diff --git a/src/entity/mod.rs b/src/entity/src/lib.rs similarity index 100% rename from src/entity/mod.rs rename to src/entity/src/lib.rs diff --git a/src/entity/room.rs b/src/entity/src/room.rs similarity index 93% rename from src/entity/room.rs rename to src/entity/src/room.rs index a5eeea4..30d3b6b 100644 --- a/src/entity/room.rs +++ b/src/entity/src/room.rs @@ -1,8 +1,8 @@ use serde::{Serialize, Deserialize}; -use crate::entity::character::{CharacterEntityId, SectionID}; -use crate::ship::room::{Episode, Difficulty}; +use crate::character::{CharacterEntityId, SectionID}; +use maps::room::{Episode, Difficulty}; #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)] diff --git a/src/entity/src/team.rs b/src/entity/src/team.rs new file mode 100644 index 0000000..2a5bfac --- /dev/null +++ b/src/entity/src/team.rs @@ -0,0 +1,31 @@ +use serde::{Serialize, Deserialize}; + +use super::account::UserAccountId; + +// [2022-10-23 00:11:18][elseware::common::mainloop::client][WARN] error RecvServerPacket::from_bytes: WrongPacketForServerType(490, [40, 0, 234, 1, 0, 0, 0, 0, 9, 0, 74, 0, 97, 0, 115, 0, 100, 0, 102, 0, 0, 0, 0, 0, 192, 52, 67, 3, 60, 159, 129, 0, 32, 64, 233, 10, 196, 156, 152, 0]) +// [2022-10-23 00:20:14][elseware::common::mainloop::client][WARN] error RecvServerPacket::from_bytes: WrongPacketForServerType(490, [40, 0, 234, 1, 0, 0, 0, 0, 9, 0, 74, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 0, 0, 152, 0]) + + +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)] +pub struct TeamEntityId(pub u32); + +pub struct NewTeamEntity { + pub created_by: UserAccountId, + pub name: String, +} + + +#[derive(Debug, Clone)] +pub struct TeamEntity { + pub id: TeamEntityId, + pub owner: UserAccountId, + pub name: String, + + pub team_flag: [u8; 2048], +} + + + + + + diff --git a/src/items/Cargo.toml b/src/items/Cargo.toml new file mode 100644 index 0000000..84ce90c --- /dev/null +++ b/src/items/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "items" +version = "0.1.0" +edition = "2021" + +[dependencies] +entity = { workspace = true } +maps = { workspace = true } +shops = { workspace = true } +location = { workspace = true } +drops = { workspace = true } + +libpso = { workspace = true } + +enum-utils = { workspace = true } +derive_more = { workspace = true } +serde = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } +async-recursion = { workspace = true } +async-std = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } \ No newline at end of file diff --git a/src/ship/items/actions.rs b/src/items/src/actions.rs similarity index 96% rename from src/ship/items/actions.rs rename to src/items/src/actions.rs index 0c06691..0b55d6d 100644 --- a/src/ship/items/actions.rs +++ b/src/items/src/actions.rs @@ -1,6 +1,6 @@ // TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency -use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemNote}; +use crate::ClientItemId; +use entity::item::{Meseta, ItemNote}; use async_std::sync::Arc; use std::future::Future; use futures::future::BoxFuture; @@ -8,30 +8,33 @@ use std::pin::Pin; use std::iter::IntoIterator; use anyhow::Context; -use libpso::packet::{ship::Message, messages::GameMessage}; -use crate::entity::character::{CharacterEntity, CharacterEntityId}; -use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; -use crate::entity::item::{ItemDetail, NewItemEntity, TradeId, ItemModifier}; -use crate::entity::item::tool::Tool; -use crate::entity::room::RoomEntityId; -use crate::ship::map::MapArea; -use crate::ship::ship::SendShipPacket; -use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; -use crate::ship::items::bank::{BankItem, BankItemDetail}; -use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; -use crate::ship::items::floor::{FloorItem, FloorItemDetail}; -use crate::ship::items::apply_item::{apply_item, ApplyItemAction}; -use crate::ship::shops::ShopItem; -use crate::ship::drops::{ItemDrop, ItemDropType}; -use crate::ship::packet::builder; -use crate::ship::location::AreaClient; -use crate::ship::monster::MonsterType; +use entity::character::{CharacterEntity, CharacterEntityId}; +use entity::gateway::{EntityGateway, EntityGatewayTransaction}; +use entity::item::{ItemDetail, NewItemEntity, TradeId, ItemModifier}; +use entity::item::tool::Tool; +use entity::room::RoomEntityId; +use maps::area::MapArea; +use crate::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; +use crate::bank::{BankItem, BankItemDetail}; +use crate::inventory::{InventoryItem, InventoryItemDetail}; +use crate::floor::{FloorItem, FloorItemDetail}; +use crate::apply_item::{apply_item, ApplyItemAction}; +use shops::ShopItem; +use drops::{ItemDrop, ItemDropType}; +use location::AreaClient; +use maps::monster::MonsterType; pub enum TriggerCreateItem { Yes, No } +#[derive(Clone)] +pub enum CreateItem { + Individual(AreaClient, ClientItemId, IndividualItemDetail), + Stacked(AreaClient, ClientItemId, Tool, usize), +} + pub(super) fn take_item_from_floor<'a, EG, TR>( character_id: CharacterEntityId, item_id: ClientItemId @@ -1144,7 +1147,7 @@ pub(super) fn apply_item_action_packets<'a, EG, TR>( character_id: CharacterEntityId, area_client: AreaClient, ) -> impl Fn((ItemStateProxy, TR), ApplyItemAction) - -> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec), anyhow::Error>> + -> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec), anyhow::Error>> where EG: EntityGateway, TR: EntityGatewayTransaction + 'a, @@ -1161,7 +1164,7 @@ where let (inventory_item_detail, create_item) = if item_detail.is_stackable() { let tool = item_detail.as_tool().ok_or_else(|| ItemStateError::NotATool(ClientItemId(0xFFFFFFFF)))?; - let create_item = builder::message::create_stacked_item(area_client, item_id, &tool, 1).map_err(|_err| ItemStateError::Dummy)?; + let create_item = CreateItem::Stacked(area_client, item_id, tool, 1); let item_detail = StackedItemDetail { entity_ids: vec![new_item.id], tool @@ -1173,7 +1176,7 @@ where entity_id: new_item.id, item: item_detail, }; - let create_item = builder::message::create_individual_item(area_client, item_id, &item_detail).map_err(|_err| ItemStateError::Dummy)?; + let create_item = CreateItem::Individual(area_client, item_id, item_detail.clone()); (InventoryItemDetail::Individual(item_detail), create_item) }; @@ -1187,7 +1190,8 @@ where transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; item_state.set_inventory(inventory).await; - vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))] + //vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))] + vec![create_item] } else { Vec::new() diff --git a/src/ship/items/apply_item.rs b/src/items/src/apply_item.rs similarity index 97% rename from src/ship/items/apply_item.rs rename to src/items/src/apply_item.rs index a003b44..0f74627 100644 --- a/src/ship/items/apply_item.rs +++ b/src/items/src/apply_item.rs @@ -4,15 +4,15 @@ use thiserror::Error; use anyhow::Context; use rand::SeedableRng; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::{CharacterEntity, TechLevel}; -use crate::entity::item::mag::{MagCell, MagCellError}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::tech::TechniqueDisk; -use crate::entity::item::{ItemDetail, ItemEntityId}; -use crate::entity::item::weapon::WeaponModifier; -use crate::ship::items::state::ItemStateProxy; -use crate::ship::items::inventory::InventoryItemDetail; +use entity::gateway::{EntityGateway, GatewayError}; +use entity::character::{CharacterEntity, TechLevel}; +use entity::item::mag::{MagCell, MagCellError}; +use entity::item::tool::{Tool, ToolType}; +use entity::item::tech::TechniqueDisk; +use entity::item::{ItemDetail, ItemEntityId}; +use entity::item::weapon::WeaponModifier; +use crate::state::ItemStateProxy; +use crate::inventory::InventoryItemDetail; #[derive(Error, Debug)] diff --git a/src/ship/items/bank.rs b/src/items/src/bank.rs similarity index 93% rename from src/ship/items/bank.rs rename to src/items/src/bank.rs index 73f0e10..e68700a 100644 --- a/src/ship/items/bank.rs +++ b/src/items/src/bank.rs @@ -1,15 +1,15 @@ use std::cmp::Ordering; use libpso::character::character; -use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity}; +use crate::ClientItemId; +use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity}; use std::future::Future; use async_std::sync::{Arc, Mutex}; -use crate::entity::character::CharacterEntityId; -use crate::entity::item::BankIdentifier; -use crate::ship::items::state::ItemStateError; -use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; -use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; +use entity::character::CharacterEntityId; +use entity::item::BankIdentifier; +use crate::state::ItemStateError; +use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; +use crate::inventory::{InventoryItem, InventoryItemDetail}; #[derive(thiserror::Error, Debug)] @@ -325,15 +325,7 @@ impl std::cmp::Eq for BankItemDetail {} impl std::cmp::PartialOrd for BankItemDetail { fn partial_cmp(&self, other: &BankItemDetail) -> Option { - let mut self_bytes = [0u8; 4]; - let mut other_bytes = [0u8; 4]; - self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); - other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]); - - let self_value = u32::from_be_bytes(self_bytes); - let other_value = u32::from_be_bytes(other_bytes); - - self_value.partial_cmp(&other_value) + Some(self.cmp(other)) } } @@ -344,8 +336,8 @@ impl std::cmp::Ord for BankItemDetail { self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]); - let self_value = u32::from_le_bytes(self_bytes); - let other_value = u32::from_le_bytes(other_bytes); + let self_value = u32::from_be_bytes(self_bytes); + let other_value = u32::from_be_bytes(other_bytes); self_value.cmp(&other_value) } @@ -362,7 +354,7 @@ impl std::cmp::Eq for BankItem {} impl std::cmp::PartialOrd for BankItem { fn partial_cmp(&self, other: &BankItem) -> Option { - self.item.partial_cmp(&other.item) + Some(self.cmp(other)) } } diff --git a/src/ship/items/floor.rs b/src/items/src/floor.rs similarity index 88% rename from src/ship/items/floor.rs rename to src/items/src/floor.rs index c71b7fd..29b79fa 100644 --- a/src/ship/items/floor.rs +++ b/src/items/src/floor.rs @@ -1,14 +1,14 @@ -use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemEntityId, ItemDetail}; +use crate::ClientItemId; +use entity::item::{Meseta, ItemEntityId, ItemDetail}; use std::future::Future; -use crate::ship::map::MapArea; -use crate::entity::character::CharacterEntityId; -use crate::entity::item::mag::Mag; +use maps::area::MapArea; +use entity::character::CharacterEntityId; +use entity::item::mag::Mag; -use crate::ship::items::state::ItemStateError; -use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail}; -use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; +use crate::state::ItemStateError; +use crate::state::{IndividualItemDetail, StackedItemDetail}; +use crate::inventory::{InventoryItem, InventoryItemDetail}; pub enum FloorType { Local, @@ -96,13 +96,13 @@ pub struct FloorState { impl FloorState { pub fn take_item(&mut self, item_id: &ClientItemId) -> Option { let item = self.local.0 - .drain_filter(|item| { + .extract_if(|item| { item.item_id == *item_id }) .next(); item.or_else(|| { self.shared.0 - .drain_filter(|item| { + .extract_if(|item| { item.item_id == *item_id }) .next() diff --git a/src/ship/items/inventory.rs b/src/items/src/inventory.rs similarity index 97% rename from src/ship/items/inventory.rs rename to src/items/src/inventory.rs index da131d8..d8c0da9 100644 --- a/src/ship/items/inventory.rs +++ b/src/items/src/inventory.rs @@ -1,18 +1,18 @@ use std::cmp::Ordering; use libpso::character::character; -use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity}; +use crate::ClientItemId; +use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity}; use std::future::Future; use async_std::sync::{Arc, Mutex}; -use crate::entity::character::CharacterEntityId; -use crate::entity::item::tool::ToolType; -use crate::entity::item::mag::Mag; -use crate::entity::item::weapon::Weapon; -use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem}; -use crate::ship::items::state::ItemStateError; -use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; -use crate::ship::items::floor::{FloorItem, FloorItemDetail}; +use entity::character::CharacterEntityId; +use entity::item::tool::ToolType; +use entity::item::mag::Mag; +use entity::item::weapon::Weapon; +use shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem}; +use crate::state::ItemStateError; +use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; +use crate::floor::{FloorItem, FloorItemDetail}; #[derive(Clone, Debug)] pub enum InventoryItemDetail { diff --git a/src/ship/items/itemstateaction.rs b/src/items/src/itemstateaction.rs similarity index 100% rename from src/ship/items/itemstateaction.rs rename to src/items/src/itemstateaction.rs diff --git a/src/ship/items/mod.rs b/src/items/src/lib.rs similarity index 87% rename from src/ship/items/mod.rs rename to src/items/src/lib.rs index 549ee51..7f4251f 100644 --- a/src/ship/items/mod.rs +++ b/src/items/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(extract_if)] + pub mod state; pub mod actions; pub mod apply_item; @@ -6,6 +8,7 @@ pub mod inventory; pub mod floor; pub mod bank; pub mod tasks; +pub mod trade; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)] pub struct ClientItemId(pub u32); diff --git a/src/ship/items/state.rs b/src/items/src/state.rs similarity index 95% rename from src/ship/items/state.rs rename to src/items/src/state.rs index 906762a..aa27143 100644 --- a/src/ship/items/state.rs +++ b/src/items/src/state.rs @@ -4,18 +4,18 @@ use async_std::sync::{Arc, RwLock, Mutex}; use futures::stream::{FuturesOrdered, StreamExt}; use anyhow::Context; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::{CharacterEntity, CharacterEntityId}; -use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankIdentifier}; -use crate::entity::item::tool::Tool; -use crate::entity::item::weapon::Weapon; -use crate::entity::item::mag::Mag; -use crate::ship::drops::ItemDrop; -use crate::ship::items::ClientItemId; -use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState}; -use crate::ship::items::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType}; -use crate::ship::items::bank::{Bank, BankState, BankItem, BankItemDetail, BankError}; -use crate::ship::location::{AreaClient, RoomId}; +use entity::gateway::{EntityGateway, GatewayError}; +use entity::character::{CharacterEntity, CharacterEntityId}; +use entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankIdentifier}; +use entity::item::tool::Tool; +use entity::item::weapon::Weapon; +use entity::item::mag::Mag; +use drops::ItemDrop; +use crate::ClientItemId; +use crate::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState}; +use crate::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType}; +use crate::bank::{Bank, BankState, BankItem, BankItemDetail, BankError}; +use location::{AreaClient, RoomId}; #[derive(thiserror::Error, Debug)] pub enum ItemStateError { @@ -50,7 +50,7 @@ pub enum ItemStateError { #[error("stacked item")] StackedItemError(Vec), #[error("apply item {0}")] - ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError), + ApplyItemError(#[from] crate::apply_item::ApplyItemError), #[error("item is not a mag {0}")] NotAMag(ClientItemId), #[error("item is not mag food {0}")] diff --git a/src/ship/items/tasks.rs b/src/items/src/tasks.rs similarity index 95% rename from src/ship/items/tasks.rs rename to src/items/src/tasks.rs index 0c3f948..cf313fc 100644 --- a/src/ship/items/tasks.rs +++ b/src/items/src/tasks.rs @@ -1,24 +1,23 @@ use futures::future::BoxFuture; -use crate::ship::items::ClientItemId; -use crate::entity::item::Meseta; - -use crate::ship::ship::SendShipPacket; -use crate::ship::map::MapArea; -use crate::entity::character::{CharacterEntity, CharacterEntityId}; -use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; -use crate::entity::item::ItemModifier; -use crate::entity::room::RoomEntityId; -use crate::ship::items::state::{ItemState, ItemStateProxy, IndividualItemDetail}; -use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction}; -use crate::ship::items::inventory::InventoryItem; -use crate::ship::items::floor::FloorItem; -use crate::ship::shops::ShopItem; -use crate::ship::trade::TradeItem; -use crate::ship::location::AreaClient; -use crate::ship::drops::ItemDrop; -use crate::ship::monster::MonsterType; - -use crate::ship::items::actions; +use crate::ClientItemId; +use entity::item::Meseta; + +use maps::area::MapArea; +use entity::character::{CharacterEntity, CharacterEntityId}; +use entity::gateway::{EntityGateway, EntityGatewayTransaction}; +use entity::item::ItemModifier; +use entity::room::RoomEntityId; +use crate::state::{ItemState, ItemStateProxy, IndividualItemDetail}; +use crate::itemstateaction::{ItemStateAction, ItemAction}; +use crate::inventory::InventoryItem; +use crate::floor::FloorItem; +use shops::ShopItem; +use crate::trade::TradeItem; +use location::AreaClient; +use drops::ItemDrop; +use maps::monster::MonsterType; + +use crate::actions; pub fn pick_up_item<'a, EG>( item_state: &'a mut ItemState, @@ -278,7 +277,7 @@ pub fn use_item<'a, EG> ( area_client: AreaClient, item_id: &'a ClientItemId, amount: u32, -) -> BoxFuture<'a, Result, anyhow::Error>> +) -> BoxFuture<'a, Result, anyhow::Error>> where EG: EntityGateway + 'static, { @@ -372,6 +371,8 @@ where Ok((transaction, result)) }) } + +#[allow(clippy::type_complexity)] pub fn trade_items<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, diff --git a/src/items/src/trade.rs b/src/items/src/trade.rs new file mode 100644 index 0000000..19e49bc --- /dev/null +++ b/src/items/src/trade.rs @@ -0,0 +1,38 @@ +use crate::ClientItemId; + +#[derive(Debug, Clone)] +pub enum TradeItem { + Individual(ClientItemId), + Stacked(ClientItemId, usize), +} + +impl TradeItem { + pub fn stacked(&self) -> Option<(ClientItemId, usize)> { + match self { + TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)), + _ => None + } + } + + pub fn stacked_mut(&mut self) -> Option<(ClientItemId, &mut usize)> { + match self { + TradeItem::Stacked(item_id, ref mut amount) => Some((*item_id, amount)), + _ => None + } + } + + pub fn item_id(&self) -> ClientItemId { + match self { + TradeItem::Individual(item_id) => *item_id, + TradeItem::Stacked(item_id, _) => *item_id, + } + } + + pub fn amount(&self) -> usize { + match self { + TradeItem::Individual(_) => 1, + TradeItem::Stacked(_, amount) => *amount, + } + } +} + diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 2c3d9c0..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![allow(clippy::type_complexity)] -#![allow(incomplete_features)] -#![feature(inline_const)] -#![feature(drain_filter)] -#![feature(try_blocks)] -#![feature(once_cell)] -#![feature(test)] -#![feature(error_generic_member_access)] -#![feature(provide_any)] - -extern crate test; - -pub mod common; -pub mod entity; -pub mod patch; -pub mod login; -pub mod ship; diff --git a/src/location/Cargo.toml b/src/location/Cargo.toml new file mode 100644 index 0000000..f6768c0 --- /dev/null +++ b/src/location/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "location" +version = "0.1.0" +edition = "2021" + +[dependencies] +networking = { workspace = true } + +async-std = { workspace = true } +derive_more = { workspace = true } +futures= { workspace = true } +thiserror = { workspace = true } \ No newline at end of file diff --git a/src/ship/location.rs b/src/location/src/lib.rs similarity index 99% rename from src/ship/location.rs rename to src/location/src/lib.rs index 5dc805e..3dd0b2b 100644 --- a/src/ship/location.rs +++ b/src/location/src/lib.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::time::SystemTime; use thiserror::Error; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use async_std::sync::{Arc, RwLock}; use futures::{stream, StreamExt}; diff --git a/src/login/mod.rs b/src/login/mod.rs deleted file mode 100644 index a5b3370..0000000 --- a/src/login/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[allow(clippy::module_inception)] -pub mod login; -pub mod character; diff --git a/src/login/models.rs b/src/login/models.rs deleted file mode 100644 index c5fb059..0000000 --- a/src/login/models.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::time::SystemTime; -use std::io::Write; -//use diesel::sql_types::Timestamp; -use diesel::{Insertable, Queryable, Identifiable, Associations, AsExpression, FromSqlRow}; -//use bcrypt::{DEFAULT_COST, hash}; -use diesel::pg::Pg; -use diesel::sql_types; -use diesel::deserialize::{self, FromSql}; -use diesel::serialize::{self, ToSql, Output, IsNull}; -use diesel::backend::Backend; - -use libpso::character::settings; - -use elseware::schema::*; - -//const ELSEWHERE_COST: u32 = bcrypt::DEFAULT_COST; -const ELSEWHERE_COST: u32 = 5; - -#[derive(Debug, AsExpression, FromSqlRow)] -#[sql_type="sql_types::Binary"] -pub struct EUserSettings(pub settings::UserSettings); - -impl std::ops::Deref for EUserSettings { - type Target = settings::UserSettings; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Queryable, Identifiable, Debug)] -pub struct UserAccount { - pub id: i32, - pub username: String, - pub password: String, - pub guildcard: Option, - pub team_id: Option, - pub banned: bool, - pub muted_until: SystemTime, - pub created_at: SystemTime, -} - -#[derive(Insertable)] -#[table_name="user_accounts"] -pub struct NewUser { - username: String, - password: String, -} - -impl NewUser { - pub fn new(username: String, password: String) -> NewUser { - let crypt_password = bcrypt::hash(password, ELSEWHERE_COST).expect("could not hash password?"); - NewUser { - username: username, - password: crypt_password, - } - } -} - -#[derive(Queryable, Identifiable, Associations)] -#[belongs_to(UserAccount, foreign_key="user_id")] -#[table_name="user_settings"] -pub struct UserSettings { - pub id: i32, - pub user_id: i32, - //settings: Vec, - pub settings: EUserSettings, -} - -#[derive(Insertable, Debug)] -#[table_name="user_settings"] -pub struct NewUserSettings { - pub user_id: i32, - pub settings: EUserSettings, -} - -impl ToSql for EUserSettings { - fn to_sql(&self, out: &mut Output) -> serialize::Result { - out.write_all(&self.0.as_bytes()[..]) - .map(|_| IsNull::No) - .map_err(|e| Box::new(e) as Box) - } -} - -impl FromSql for EUserSettings { - fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result { - let bytes_vec: Vec = as FromSql>::from_sql(bytes)?; - let mut static_bytes = [0u8; 0x1160]; - static_bytes[..0x1160].clone_from_slice(&bytes_vec); - Ok(EUserSettings(settings::UserSettings::from_bytes(static_bytes))) - } -} diff --git a/src/login_server/Cargo.toml b/src/login_server/Cargo.toml new file mode 100644 index 0000000..8ce2441 --- /dev/null +++ b/src/login_server/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "login_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +entity = { workspace = true } +networking = { workspace = true } +pktbuilder = { workspace = true } +stats = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +async-trait = { workspace = true } +anyhow = { workspace = true } +bcrypt = { workspace = true } +crc = { workspace = true } +thiserror = { workspace = true } +chrono = { workspace = true } +rand= { workspace = true } diff --git a/src/login/character.rs b/src/login_server/src/character.rs similarity index 94% rename from src/login/character.rs rename to src/login_server/src/character.rs index f23beea..3bce346 100644 --- a/src/login/character.rs +++ b/src/login_server/src/character.rs @@ -12,30 +12,31 @@ use libpso::packet::login::*; use libpso::packet::ship::{MenuDetail, SmallLeftDialog}; use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; -use crate::entity::item; use libpso::character::character; +use entity::item; -use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; -use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; -use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship}; -use crate::common::leveltable::LEVEL_TABLE; -use libpso::{utf8_to_array, utf8_to_utf16_array}; - -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM}; -use crate::entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankIdentifier, EquippedEntity, Meseta}; -use crate::entity::item::weapon::Weapon; -use crate::entity::item::armor::Armor; -use crate::entity::item::tech::Technique; -use crate::entity::item::tool::Tool; -use crate::entity::item::mag::Mag; -use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel}; - -use crate::login::login::{get_login_status}; -use crate::common::interserver::AuthToken; +use networking::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; +use networking::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; +use networking::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship}; +use stats::leveltable::LEVEL_TABLE; +use libpso::util::{utf8_to_array, utf8_to_utf16_array}; + +use entity::gateway::{EntityGateway, GatewayError}; +use entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM}; +use entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankIdentifier, EquippedEntity, Meseta}; +use entity::item::weapon::Weapon; +use entity::item::armor::Armor; +use entity::item::tech::Technique; +use entity::item::tool::Tool; +use entity::item::mag::Mag; +use entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel}; + +use crate::login::get_login_status; +use networking::interserver::AuthToken; + +use pktbuilder::ship::SHIP_MENU_ID; pub const CHARACTER_PORT: u16 = 12001; -pub const SHIP_MENU_ID: u32 = 1; #[derive(thiserror::Error, Debug)] pub enum CharacterError { @@ -149,7 +150,7 @@ fn generate_param_data(path: &str) -> (ParamDataHeader, Vec) { size: len as u32, checksum: crc.sum32(), offset: buffer.len() as u32, - filename: utf8_to_array!(param.file_name().unwrap().to_str().unwrap(), 0x40), + filename: utf8_to_array(param.file_name().unwrap().to_str().unwrap()), }); buffer.append(&mut filebuf); @@ -176,7 +177,7 @@ impl ClientState { user: None, characters: None, guildcard_data_buffer: None, - session: Session::new(), + session: Session::default(), } } } @@ -341,15 +342,15 @@ impl CharacterServerState { if let Some(connected_client) = self.connected_clients.read().await.get(&user.id) { if let Some(expires) = connected_client.expires { if expires > chrono::Utc::now() { - return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::new()))]); + return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::default()))]); } } else { - return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::new()))]); + return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::default()))]); } } - let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); + let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::default()); response.guildcard = user.guildcard; response.team_id = user.team_id.map_or(0, |ti| ti); @@ -366,7 +367,7 @@ impl CharacterServerState { Ok(vec![SendCharacterPacket::LoginResponse(response)]) }, Err(err) => { - Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(err, Session::new()))]) + Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(err, Session::default()))]) } } } @@ -378,7 +379,7 @@ impl CharacterServerState { menu: SHIP_MENU_ID, item: i.0 as u32, flags: 0, - name: utf8_to_utf16_array!(s.name, 0x11) + name: utf8_to_utf16_array(&s.name) } }).collect())) ]) @@ -484,7 +485,7 @@ impl CharacterServerState { async fn set_flag(&mut self, id: ClientId, setflag: &SetFlag) -> Result, anyhow::Error> { let mut client = self.clients.write().await; let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; - let mut user = client.user.as_mut().unwrap(); + let user = client.user.as_mut().unwrap(); user.flags = setflag.flags; self.entity_gateway.save_user(user).await.unwrap(); Ok(None.into_iter()) @@ -515,7 +516,7 @@ impl CharacterServerState { async fn character_preview(&mut self, id: ClientId, preview: &CharacterPreview) -> Result, anyhow::Error> { let mut client = self.clients.write().await; let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; - let mut user = client.user.as_mut().unwrap(); + let user = client.user.as_mut().unwrap(); if user.flags == USERFLAG_NEWCHAR { new_character(&mut self.entity_gateway, user, preview).await? } @@ -823,7 +824,7 @@ impl<'a> SelectScreenCharacterBuilder<'a> { hair_b: character.appearance.hair_b, prop_x: character.appearance.prop_x, prop_y: character.appearance.prop_y, - name: utf8_to_utf16_array!(character.name, 16), + name: utf8_to_utf16_array(&character.name), play_time: character.playtime, ..character::SelectScreenCharacter::default() } @@ -834,9 +835,21 @@ impl<'a> SelectScreenCharacterBuilder<'a> { #[cfg(test)] mod test { use super::*; - use crate::entity::account::*; + use entity::account::*; use libpso::character::{settings, character}; - use crate::entity::gateway::{InMemoryGateway, GatewayError}; + use entity::gateway::{InMemoryGateway, EntityGatewayTransaction, GatewayError}; + + #[derive(Clone)] + struct CharTestDb; + + impl EntityGateway for CharTestDb { + type Transaction<'t> = CharTestDb where Self: 't; + } + + impl EntityGatewayTransaction for CharTestDb { + type ParentGateway = CharTestDb; + } + #[async_std::test] async fn test_option_send() { @@ -846,7 +859,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'a> = () where Self: 'a; + type Transaction<'a> = CharTestDb where Self: 'a; async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result { Ok(UserSettingsEntity { id: UserSettingsId(0), @@ -889,7 +902,7 @@ mod test { #[derive(Clone)] struct TestData; impl EntityGateway for TestData { - type Transaction<'a> = () where Self: 'a; + type Transaction<'a> = CharTestDb where Self: 'a; } let mut server = CharacterServerState::new(TestData {}, AuthToken("".into())); let send = server.handle(ClientId(1), RecvCharacterPacket::Checksum(Checksum {checksum: 1234, diff --git a/src/login_server/src/lib.rs b/src/login_server/src/lib.rs new file mode 100644 index 0000000..0006241 --- /dev/null +++ b/src/login_server/src/lib.rs @@ -0,0 +1,2 @@ +pub mod login; +pub mod character; diff --git a/src/login/login.rs b/src/login_server/src/login.rs similarity index 93% rename from src/login/login.rs rename to src/login_server/src/login.rs index b4fcad6..70bb5a4 100644 --- a/src/login/login.rs +++ b/src/login_server/src/login.rs @@ -11,11 +11,11 @@ use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; use libpso::util::array_to_utf8; -use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; -use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; +use networking::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; +use networking::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; -use crate::entity::gateway::EntityGateway; -use crate::entity::account::{UserAccountEntity}; +use entity::gateway::EntityGateway; +use entity::account::{UserAccountEntity}; pub const LOGIN_PORT: u16 = 12000; pub const COMMUNICATION_PORT: u16 = 12123; @@ -83,21 +83,13 @@ pub async fn get_login_status(entity_gateway: &mut impl EntityGateway, pkt: &Log pub fn check_if_already_online(user: UserAccountEntity) -> Result { Ok(user) - /* - if user.is_currently_online() { - Err(AccountStatus::PayUp) -} - else { - Ok(user) -} - */ } #[derive(Clone)] pub struct LoginServerState { character_server_ip: net::Ipv4Addr, entity_gateway: EG, - clients: HashMap, + clients: HashMap, // TODO: this should be arc/mutex'd? } impl LoginServerState { @@ -119,7 +111,7 @@ impl LoginServerState { let response = SendLoginPacket::LoginResponse(LoginResponse::by_status(AccountStatus::Ok, pkt.session)); let ip = u32::from_ne_bytes(self.character_server_ip.octets()); Ok(vec![response, - SendLoginPacket::RedirectClient(RedirectClient::new(ip, crate::login::character::CHARACTER_PORT))]) + SendLoginPacket::RedirectClient(RedirectClient::new(ip, crate::character::CHARACTER_PORT))]) }, Err(err) => { Ok(vec![SendLoginPacket::LoginResponse(LoginResponse::by_status(err, pkt.session))]) @@ -178,8 +170,8 @@ impl ServerState for LoginServerState { #[cfg(test)] mod test { use super::*; - use crate::entity::account::{UserAccountId}; - use crate::entity::gateway::{EntityGatewayTransaction, GatewayError}; + use entity::account::{UserAccountId}; + use entity::gateway::{EntityGatewayTransaction, GatewayError}; const LOGIN_PACKET: RecvLoginPacket = RecvLoginPacket::Login(Login { tag: 65536, @@ -204,13 +196,16 @@ mod test { character_slot: 0, } }); - - impl EntityGateway for () { - type Transaction<'t> = () where Self: 't; + + #[derive(Clone)] + struct LoginTestDb; + + impl EntityGateway for LoginTestDb { + type Transaction<'t> = LoginTestDb where Self: 't; } - impl EntityGatewayTransaction for () { - type ParentGateway = (); + impl EntityGatewayTransaction for LoginTestDb { + type ParentGateway = LoginTestDb; } #[async_std::test] @@ -221,7 +216,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'t> = () where Self: 't; + type Transaction<'t> = LoginTestDb where Self: 't; async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { @@ -280,7 +275,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'t> = () where Self: 't; + type Transaction<'t> = LoginTestDb where Self: 't; async fn get_user_by_name(&mut self, _name: String) -> Result { Err(GatewayError::Error) } @@ -315,7 +310,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'t> = () where Self: 't; + type Transaction<'t> = LoginTestDb where Self: 't; async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { @@ -365,7 +360,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'t> = () where Self: 't; + type Transaction<'t> = LoginTestDb where Self: 't; async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { diff --git a/src/maps/Cargo.toml b/src/maps/Cargo.toml new file mode 100644 index 0000000..db84b6a --- /dev/null +++ b/src/maps/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "maps" +version = "0.1.0" +edition = "2021" + +[dependencies] +byteorder = { workspace = true } +serde = { workspace = true } +thiserror = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } +toml = { workspace = true } +enum-utils = { workspace = true } +derive_more = { workspace = true } diff --git a/src/ship/map/area.rs b/src/maps/src/area.rs similarity index 99% rename from src/ship/map/area.rs rename to src/maps/src/area.rs index 02361c3..bb64737 100644 --- a/src/ship/map/area.rs +++ b/src/maps/src/area.rs @@ -2,7 +2,7 @@ use serde::{Serialize, Deserialize}; use std::collections::HashMap; use thiserror::Error; -use crate::ship::room::Episode; +use crate::room::Episode; use std::fmt; #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/src/ship/map/enemy.rs b/src/maps/src/enemy.rs similarity index 94% rename from src/ship/map/enemy.rs rename to src/maps/src/enemy.rs index 4989041..54ac36d 100644 --- a/src/ship/map/enemy.rs +++ b/src/maps/src/enemy.rs @@ -1,19 +1,18 @@ // TOOD: `pub(super) for most of these?` use std::io::{Read}; use std::collections::HashMap; +use std::fs::File; +use std::path::PathBuf; use byteorder::{LittleEndian, ReadBytesExt}; use thiserror::Error; - -use crate::ship::ship::ShipEvent; -use crate::ship::monster::MonsterType; -use crate::ship::room::Episode; - -use crate::ship::map::*; - use rand::{Rng, SeedableRng}; use serde::{Serialize, Deserialize}; -use crate::ship::drops::{load_rare_monster_file}; + +use crate::Holiday; +use crate::area::{MapArea, MapAreaError}; +use crate::room::Episode; +use crate::monster::MonsterType; #[derive(Debug, Copy, Clone)] pub struct RawMapEnemy { @@ -69,6 +68,17 @@ impl RawMapEnemy { } +pub fn load_rare_monster_file(episode: Episode) -> T { + // TODO: where does the rare monster toml file actually live + let mut path = PathBuf::from("data/battle_param/"); + path.push(episode.to_string().to_lowercase() + "_rare_monster.toml"); + + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + toml::from_str::(s.as_str()).unwrap() +} + #[derive(Error, Debug)] #[error("")] pub enum MapEnemyError { @@ -76,6 +86,7 @@ pub enum MapEnemyError { MapAreaError(#[from] MapAreaError), } + // making this `pub type` doesn't allow `impl`s to be defined? #[derive(Clone, Debug, Serialize, Deserialize)] pub struct RareMonsterAppearTable { @@ -103,7 +114,7 @@ impl RareMonsterAppearTable { rand_chacha::ChaChaRng::from_entropy().gen::() < *self.appear_rate.get(monster).unwrap_or(&0.0f32) } - pub fn apply(&self, enemy: MapEnemy, event: ShipEvent) -> MapEnemy { + pub fn apply(&self, enemy: MapEnemy, event: Holiday) -> MapEnemy { if enemy.can_be_rare() && self.roll_is_rare(&enemy.monster) { enemy.into_rare(event) } @@ -345,12 +356,12 @@ impl MapEnemy { guaranteed rare monsters don't count towards the limit */ #[must_use] - pub fn into_rare(self, event: ShipEvent) -> MapEnemy { + pub fn into_rare(self, event: Holiday) -> MapEnemy { match (self.monster, self.map_area.to_episode(), event) { (MonsterType::RagRappy, Episode::One, _) => {MapEnemy {monster: MonsterType::AlRappy, shiny:true, ..self}}, - (MonsterType::RagRappy, Episode::Two, ShipEvent::Easter) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}}, - (MonsterType::RagRappy, Episode::Two, ShipEvent::Halloween) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}}, - (MonsterType::RagRappy, Episode::Two, ShipEvent::Christmas) => {MapEnemy {monster: MonsterType::StRappy, shiny:true, ..self}}, + (MonsterType::RagRappy, Episode::Two, Holiday::Easter) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}}, + (MonsterType::RagRappy, Episode::Two, Holiday::Halloween) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}}, + (MonsterType::RagRappy, Episode::Two, Holiday::Christmas) => {MapEnemy {monster: MonsterType::StRappy, shiny:true, ..self}}, (MonsterType::RagRappy, Episode::Two, _) => {MapEnemy {monster: MonsterType::LoveRappy, shiny:true, ..self}}, (MonsterType::Hildebear, _, _) => {MapEnemy {monster: MonsterType::Hildeblue, shiny:true, ..self}}, (MonsterType::PoisonLily, _, _) => {MapEnemy {monster: MonsterType::NarLily, shiny:true, ..self}}, diff --git a/src/maps/src/lib.rs b/src/maps/src/lib.rs new file mode 100644 index 0000000..2da528c --- /dev/null +++ b/src/maps/src/lib.rs @@ -0,0 +1,59 @@ +pub mod area; +pub mod enemy; +pub mod object; +pub mod variant; +pub mod maps; +pub mod monster; +pub mod room; + +#[derive(Clone, Copy)] +pub enum Holiday { + None, + Christmas, + Valentines, + Easter, + Halloween, + Sonic, + NewYear, + Summer, + White, + Wedding, + Fall, + Spring, + Summer2, + Spring2, +} + + +impl From for u32 { + fn from(other: Holiday) -> u32 { + u16::from(other) as u32 + } +} + +impl From for u16 { + fn from(other: Holiday) -> u16 { + u8::from(other) as u16 + } +} + +impl From for u8 { + fn from(other: Holiday) -> u8 { + match other { + Holiday::None => 0, + Holiday::Christmas => 1, + Holiday::Valentines => 3, + Holiday::Easter => 4, + Holiday::Halloween => 5, + Holiday::Sonic => 6, + Holiday::NewYear => 7, + Holiday::Summer => 8, + Holiday::White => 9, + Holiday::Wedding => 10, + Holiday::Fall => 11, + Holiday::Spring => 12, + Holiday::Summer2 => 13, + Holiday::Spring2 => 14, + } + } +} diff --git a/src/ship/map/maps.rs b/src/maps/src/maps.rs similarity index 96% rename from src/ship/map/maps.rs rename to src/maps/src/maps.rs index 05c7e29..2ed7961 100644 --- a/src/ship/map/maps.rs +++ b/src/maps/src/maps.rs @@ -6,14 +6,15 @@ use std::fs::File; use thiserror::Error; -use crate::ship::ship::ShipEvent; -use crate::ship::monster::MonsterType; -use crate::ship::room::{Episode, RoomMode, PlayerMode}; - -// TODO: don't use * -use crate::ship::map::*; - +//use crate::ship::ship::ShipEvent; +use crate::area::MapArea; +use crate::Holiday; +use crate::enemy::{MapEnemy, RawMapEnemy, RareMonsterAppearTable}; +use crate::monster::MonsterType; +use crate::variant::{MapVariant, MapVariantMode}; +use crate::object::{MapObject, RawMapObject}; +use crate::room::{Episode, RoomMode, PlayerMode}; pub fn objects_from_stream(cursor: &mut impl Read, episode: &Episode, map_area: &MapArea) -> Vec> { let mut object_data = Vec::new(); @@ -325,7 +326,7 @@ impl Maps { enemies: Vec>, objects: Vec>, rare_monster_table: &RareMonsterAppearTable, - event: ShipEvent) + event: Holiday) { self.enemy_data = enemies .into_iter() @@ -358,7 +359,7 @@ impl Maps { } } -pub fn generate_free_roam_maps(room_mode: RoomMode, event: ShipEvent) -> Maps { +pub fn generate_free_roam_maps(room_mode: RoomMode, event: Holiday) -> Maps { let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); let map_variants = default_map_variants(room_mode.episode(), room_mode.player_mode()); Maps { @@ -375,3 +376,12 @@ pub fn generate_free_roam_maps(room_mode: RoomMode, event: ShipEvent) -> Maps { map_variants, } } + + +pub fn null_free_roam_maps(_room_mode: RoomMode, _event: Holiday) -> Maps { + Maps { + enemy_data: Default::default(), + object_data: Default::default(), + map_variants: Default::default(), + } +} diff --git a/src/ship/monster.rs b/src/maps/src/monster.rs similarity index 98% rename from src/ship/monster.rs rename to src/maps/src/monster.rs index 1bdb5b7..a72288d 100644 --- a/src/ship/monster.rs +++ b/src/maps/src/monster.rs @@ -4,7 +4,7 @@ use std::fs::File; use std::io::Read; use std::path::PathBuf; use serde::{Serialize, Deserialize}; -use crate::ship::room::{Difficulty, Episode, RoomMode}; +use crate::room::{Difficulty, Episode, RoomMode}; #[derive(Debug)] @@ -149,7 +149,7 @@ pub enum MonsterType { } -#[derive(serde::Deserialize, Debug)] +#[derive(Deserialize, Debug)] pub struct MonsterStats { pub atp: u16, pub mst: u16, diff --git a/src/ship/map/object.rs b/src/maps/src/object.rs similarity index 98% rename from src/ship/map/object.rs rename to src/maps/src/object.rs index 81bce6a..0f73442 100644 --- a/src/ship/map/object.rs +++ b/src/maps/src/object.rs @@ -1,13 +1,11 @@ // TOOD: `pub(super) for most of these?` -use std::io::{Read}; +use std::io::Read; use byteorder::{LittleEndian, ReadBytesExt}; -use crate::ship::room::Episode; - -// TODO: don't use * -use crate::ship::map::*; +use crate::room::Episode; +use crate::area::MapArea; #[derive(Debug, Copy, Clone)] diff --git a/src/maps/src/room.rs b/src/maps/src/room.rs new file mode 100644 index 0000000..8370e7c --- /dev/null +++ b/src/maps/src/room.rs @@ -0,0 +1,150 @@ +#[derive(Debug, Copy, Clone, derive_more::Display)] +pub enum Episode { + #[display(fmt="ep1")] + One, + #[display(fmt="ep2")] + Two, + #[display(fmt="ep4")] + Four, +} + +impl TryFrom for Episode { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 1 => Ok(Episode::One), + 2 => Ok(Episode::Two), + 3 => Ok(Episode::Four), + _ => Err(()) + } + } +} + +impl From for u8 { + fn from(other: Episode) -> u8 { + match other { + Episode::One => 1, + Episode::Two => 2, + Episode::Four => 3, + } + } +} + +impl Episode { + pub fn from_quest(value: u8) -> Option { + match value { + 0 => Some(Episode::One), + 1 => Some(Episode::Two), + 2 => Some(Episode::Four), + _ => None, + } + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] +pub enum Difficulty { + Normal, + Hard, + VeryHard, + Ultimate, +} + +impl TryFrom for Difficulty { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Difficulty::Normal), + 1 => Ok(Difficulty::Hard), + 2 => Ok(Difficulty::VeryHard), + 3 => Ok(Difficulty::Ultimate), + _ => Err(()) + } + } +} + +impl From for u8 { + fn from(other: Difficulty) -> u8 { + match other { + Difficulty::Normal => 0, + Difficulty::Hard => 1, + Difficulty::VeryHard => 2, + Difficulty::Ultimate => 3, + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum PlayerMode { + Single, + Multi, +} + +impl PlayerMode { + pub fn value(&self) -> u8 { + match self { + PlayerMode::Single => 1, + PlayerMode::Multi => 0, + } + } +} + +#[derive(Debug, Copy, Clone, derive_more::Display)] +pub enum RoomMode { + #[display(fmt="single")] + Single { + episode: Episode, + difficulty: Difficulty, + }, + #[display(fmt="multi")] + Multi { + episode: Episode, + difficulty: Difficulty, + }, + #[display(fmt="challenge")] + Challenge { + episode: Episode, + }, + #[display(fmt="battle")] + Battle { + episode: Episode, + difficulty: Difficulty, + } +} + + +impl RoomMode { + pub fn difficulty(&self) -> Difficulty { + match self { + RoomMode::Single {difficulty, ..} => *difficulty, + RoomMode::Multi {difficulty, ..} => *difficulty, + RoomMode::Battle {difficulty, ..} => *difficulty, + RoomMode::Challenge {..} => Difficulty::Normal, + } + } + + pub fn episode(&self) -> Episode { + match self { + RoomMode::Single {episode, ..} => *episode, + RoomMode::Multi {episode, ..} => *episode, + RoomMode::Battle {episode, ..} => *episode, + RoomMode::Challenge {episode, ..} => *episode, + } + } + + pub fn battle(&self) -> bool { + matches!(self, RoomMode::Battle {..}) + } + + pub fn challenge(&self) -> bool { + matches!(self, RoomMode::Challenge {..}) + } + + pub fn player_mode(&self) -> PlayerMode { + match self { + RoomMode::Single {..} => PlayerMode::Single, + _ => PlayerMode::Multi, + } + } +} diff --git a/src/ship/map/variant.rs b/src/maps/src/variant.rs similarity index 99% rename from src/ship/map/variant.rs rename to src/maps/src/variant.rs index 0fa7c65..78fa4bf 100644 --- a/src/ship/map/variant.rs +++ b/src/maps/src/variant.rs @@ -3,7 +3,8 @@ use rand::Rng; // TODO: don't use * -use crate::ship::map::*; +//use crate::map::*; +use crate::area::MapArea; #[derive(Debug, PartialEq, Eq)] pub enum MapVariantMode { diff --git a/src/networking/Cargo.toml b/src/networking/Cargo.toml new file mode 100644 index 0000000..1ecadc9 --- /dev/null +++ b/src/networking/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "networking" +version = "0.1.0" +edition = "2021" + + +[dependencies] +entity = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +log = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +derive_more = { workspace = true } \ No newline at end of file diff --git a/src/common/cipherkeys.rs b/src/networking/src/cipherkeys.rs similarity index 100% rename from src/common/cipherkeys.rs rename to src/networking/src/cipherkeys.rs diff --git a/src/common/interserver.rs b/src/networking/src/interserver.rs similarity index 94% rename from src/common/interserver.rs rename to src/networking/src/interserver.rs index 1f6e0ff..be49a9f 100644 --- a/src/common/interserver.rs +++ b/src/networking/src/interserver.rs @@ -2,8 +2,8 @@ use std::net::Ipv4Addr; use async_std::channel; use serde::{Serialize, Deserialize}; use serde::de::DeserializeOwned; -use crate::entity::account::UserAccountId; -use crate::entity::character::CharacterEntityId; +use entity::account::UserAccountId; +use entity::character::CharacterEntityId; #[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ServerId(pub usize); diff --git a/src/networking/src/lib.rs b/src/networking/src/lib.rs new file mode 100644 index 0000000..d62efe2 --- /dev/null +++ b/src/networking/src/lib.rs @@ -0,0 +1,4 @@ +pub mod cipherkeys; +pub mod serverstate; +pub mod mainloop; +pub mod interserver; diff --git a/src/common/mainloop/client.rs b/src/networking/src/mainloop/client.rs similarity index 97% rename from src/common/mainloop/client.rs rename to src/networking/src/mainloop/client.rs index d7af211..619a1a6 100644 --- a/src/common/mainloop/client.rs +++ b/src/networking/src/mainloop/client.rs @@ -9,8 +9,8 @@ use log::{trace, info, warn, error}; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; use libpso::PacketParseError; -use crate::common::serverstate::ClientId; -use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; +use crate::serverstate::ClientId; +use crate::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; #[derive(Debug)] @@ -72,7 +72,7 @@ impl PacketReceiver { let mut dec_buf = { //let mut cipher = self.cipher.lock().await; let block_chunk_len = self.recv_buffer.len() / self.cipher.block_size() * self.cipher.block_size(); - let buf = self.recv_buffer.drain(..block_chunk_len).collect(); + let buf = self.recv_buffer.drain(..block_chunk_len).collect::>(); self.cipher.decrypt(&buf)? }; self.incoming_data.append(&mut dec_buf); @@ -255,7 +255,7 @@ where let (mut socket, addr) = listener.accept().await.unwrap(); id += 1; - let client_id = crate::common::serverstate::ClientId(id); + let client_id = crate::serverstate::ClientId(id); info!("new client {:?} {:?} {:?}", client_id, socket, addr); let (client_tx, client_rx) = async_std::channel::unbounded(); diff --git a/src/common/mainloop/interserver.rs b/src/networking/src/mainloop/interserver.rs similarity index 93% rename from src/common/mainloop/interserver.rs rename to src/networking/src/mainloop/interserver.rs index dbe940d..5e5194b 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/networking/src/mainloop/interserver.rs @@ -8,13 +8,11 @@ use std::collections::HashMap; use serde::Serialize; use serde::de::DeserializeOwned; -use crate::common::interserver::{ServerId, InterserverActor}; +use crate::interserver::{ServerId, InterserverActor}; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; -use crate::common::serverstate::{ServerState, SendServerPacket, RecvServerPacket}; -use crate::login::character::CharacterServerState; -//use crate::ship::ship::ShipServerState; -use crate::entity::gateway::entitygateway::EntityGateway; +use crate::serverstate::{ServerState, SendServerPacket, RecvServerPacket}; +use entity::gateway::entitygateway::EntityGateway; use async_std::channel; use std::fmt::Debug; @@ -149,7 +147,7 @@ where info!("[interserver listen] new server: {:?} {:?}", socket, addr); id += 1; - let server_id = crate::common::interserver::ServerId(id); + let server_id = crate::interserver::ServerId(id); let (client_tx, client_rx) = async_std::channel::unbounded(); state.set_sender(server_id, client_tx.clone()).await; @@ -196,7 +194,7 @@ where } }; id += 1; - let server_id = crate::common::interserver::ServerId(id); + let server_id = crate::interserver::ServerId(id); info!("[interserver connect] found loginserv: {:?} {:?}", server_id, socket); let (client_tx, client_rx) = async_std::channel::unbounded(); @@ -220,12 +218,8 @@ where let mut buf = [0u8; 1]; loop { let peek = socket.peek(&mut buf).await; - match peek { - Ok(len) if len == 0 => { - break - }, - _ => { - } + if let Ok(0) = peek { + break } } } diff --git a/src/common/mainloop/mod.rs b/src/networking/src/mainloop/mod.rs similarity index 100% rename from src/common/mainloop/mod.rs rename to src/networking/src/mainloop/mod.rs diff --git a/src/common/serverstate.rs b/src/networking/src/serverstate.rs similarity index 100% rename from src/common/serverstate.rs rename to src/networking/src/serverstate.rs diff --git a/src/patch/mod.rs b/src/patch/mod.rs deleted file mode 100644 index 323a777..0000000 --- a/src/patch/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[allow(clippy::module_inception)] -pub mod patch; diff --git a/src/patch_server/Cargo.toml b/src/patch_server/Cargo.toml new file mode 100644 index 0000000..f528b04 --- /dev/null +++ b/src/patch_server/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "patch_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +networking = { workspace = true } + +libpso = { workspace = true } + +async-trait = { workspace = true } +rand = { workspace = true } +crc = { workspace = true } +ron = { workspace = true } +serde = { workspace = true } diff --git a/src/patch/patch.rs b/src/patch_server/src/lib.rs similarity index 98% rename from src/patch/patch.rs rename to src/patch_server/src/lib.rs index 26441f8..ecf51f9 100644 --- a/src/patch/patch.rs +++ b/src/patch_server/src/lib.rs @@ -11,8 +11,8 @@ use libpso::crypto::pc::PSOPCCipher; use ron::de::from_str; use serde::Deserialize; -use crate::common::mainloop::{NetworkError}; -use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId}; +use networking::mainloop::{NetworkError}; +use networking::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId}; #[derive(Debug)] pub enum PatchError { @@ -341,7 +341,7 @@ impl Iterator for SendFileIterator { if len == 0 { self.current_file = None; self.chunk_num = 0; - Some(SendPatchPacket::EndFileSend(EndFileSend::new())) + Some(SendPatchPacket::EndFileSend(EndFileSend::default())) } else { let mut crc = crc32::Digest::new(crc32::IEEE); diff --git a/src/pktbuilder/Cargo.toml b/src/pktbuilder/Cargo.toml new file mode 100644 index 0000000..9c070f9 --- /dev/null +++ b/src/pktbuilder/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "pktbuilder" +version = "0.1.0" +edition = "2021" + +[dependencies] +quests = { workspace = true } +stats = { workspace = true } +location = { workspace = true } +client = { workspace = true } +items = { workspace = true } +networking = { workspace = true } +maps = { workspace = true } +room = { workspace = true } +shops = { workspace = true } +entity = { workspace = true } + +libpso = { workspace = true } + +anyhow = { workspace = true } +futures = { workspace = true } +thiserror = { workspace = true } \ No newline at end of file diff --git a/src/ship/character.rs b/src/pktbuilder/src/character.rs similarity index 95% rename from src/ship/character.rs rename to src/pktbuilder/src/character.rs index 348f8ac..1052af6 100644 --- a/src/ship/character.rs +++ b/src/pktbuilder/src/character.rs @@ -1,10 +1,9 @@ use libpso::character::character; -use crate::common::leveltable::CharacterStats; -use crate::entity::character::CharacterEntity; -//use crate::ship::items::{CharacterInventory, CharacterBank}; -use crate::ship::items::bank::BankState; -use crate::ship::items::inventory::InventoryState; -use crate::entity::item::Meseta; +use stats::leveltable::CharacterStats; +use entity::character::CharacterEntity; +use items::bank::BankState; +use items::inventory::InventoryState; +use entity::item::Meseta; #[derive(Default)] @@ -54,7 +53,7 @@ impl<'a> CharacterBytesBuilder<'a> { let level = self.level.unwrap(); let meseta = self.meseta.unwrap(); character::Character { - name: libpso::utf8_to_utf16_array!(character.name, 16), + name: libpso::util::utf8_to_utf16_array(&character.name), hp: stats.hp, atp: stats.atp + character.materials.power as u16 * 2, mst: stats.mst + character.materials.mind as u16 * 2, diff --git a/src/ship/packet/builder/mod.rs b/src/pktbuilder/src/lib.rs similarity index 81% rename from src/ship/packet/builder/mod.rs rename to src/pktbuilder/src/lib.rs index f74015e..e735521 100644 --- a/src/ship/packet/builder/mod.rs +++ b/src/pktbuilder/src/lib.rs @@ -3,14 +3,15 @@ pub mod message; pub mod room; pub mod quest; pub mod ship; +pub mod character; use libpso::character::character::Inventory; use libpso::packet::ship::{PlayerHeader, PlayerInfo}; -use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::character::CharacterBytesBuilder; -use crate::ship::ship::ClientState; -use crate::ship::location::AreaClient; -use crate::ship::items::inventory::InventoryState; +use stats::leveltable::LEVEL_TABLE; +use crate::character::CharacterBytesBuilder; +use client::ClientState; +use location::AreaClient; +use items::inventory::InventoryState; pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader { PlayerHeader { @@ -18,7 +19,7 @@ pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) - guildcard: client.user.id.0, _unknown1: [0; 5], client_id: area_client.local_client.id() as u32, - name: libpso::utf8_to_utf16_array!(client.character.name, 16), + name: libpso::util::utf8_to_utf16_array(&client.character.name), _unknown2: 2, } } diff --git a/src/ship/packet/builder/lobby.rs b/src/pktbuilder/src/lobby.rs similarity index 91% rename from src/ship/packet/builder/lobby.rs rename to src/pktbuilder/src/lobby.rs index af033ca..34587c5 100644 --- a/src/ship/packet/builder/lobby.rs +++ b/src/pktbuilder/src/lobby.rs @@ -1,9 +1,10 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{Clients, ShipEvent}; -use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError}; -use crate::ship::packet::builder::{player_info}; -use crate::ship::items::state::ItemState; +use networking::serverstate::ClientId; +use maps::Holiday; +use client::Clients; +use location::{ClientLocation, LobbyId, ClientLocationError}; +use crate::player_info; +use items::state::ItemState; use futures::future::join_all; @@ -12,7 +13,7 @@ pub async fn join_lobby(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &ItemState, - event: ShipEvent) + event: Holiday) -> Result { let lobby_clients = client_location.get_clients_in_lobby(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; @@ -52,7 +53,7 @@ pub async fn add_to_lobby(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &ItemState, - event: ShipEvent) + event: Holiday) -> Result { let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; diff --git a/src/ship/packet/builder/message.rs b/src/pktbuilder/src/message.rs similarity index 72% rename from src/ship/packet/builder/message.rs rename to src/pktbuilder/src/message.rs index ac60484..cf843df 100644 --- a/src/ship/packet/builder/message.rs +++ b/src/pktbuilder/src/message.rs @@ -1,21 +1,21 @@ use libpso::packet::messages::*; use libpso::packet::ship::*; -use crate::entity::item; -use crate::common::leveltable::CharacterStats; -use crate::ship::ship::{ShipError}; -use crate::ship::items::ClientItemId; -use crate::ship::items::inventory::InventoryItem; -use crate::ship::items::state::IndividualItemDetail; -use crate::ship::items::bank::BankState; -use crate::ship::items::floor::FloorItem; -use crate::ship::location::AreaClient; +use entity::item; +use stats::leveltable::CharacterStats; +//use crate::ship::ship::{ShipError}; +use items::ClientItemId; +use items::inventory::InventoryItem; +use items::state::IndividualItemDetail; +use items::bank::BankState; +use items::floor::FloorItem; +use location::AreaClient; use std::convert::TryInto; -use crate::ship::shops::ShopItem; +use shops::ShopItem; -pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result { +pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> ItemDrop { let item_bytes = item_drop.as_client_bytes(); - Ok(ItemDrop { + ItemDrop { client, target, map_area: item_drop.map_area.area_value(), @@ -24,37 +24,37 @@ pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result Result { +pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &IndividualItemDetail) -> CreateItem { let bytes = item.as_client_bytes(); - Ok(CreateItem { + CreateItem { client: area_client.local_client.id(), target: 0, - item_data: bytes[0..12].try_into()?, + item_data: bytes[0..12].try_into().unwrap(), item_id: item_id.0, - item_data2: bytes[12..16].try_into()?, + item_data2: bytes[12..16].try_into().unwrap(), unknown: 0, - }) + } } // TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed -pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> Result { +pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> CreateItem { let bytes = tool.as_stacked_bytes(amount); - Ok(CreateItem { + CreateItem { client: area_client.local_client.id(), target: 0, - item_data: bytes[0..12].try_into()?, + item_data: bytes[0..12].try_into().unwrap(), item_id: item_id.0, - item_data2: bytes[12..16].try_into()?, + item_data2: bytes[12..16].try_into().unwrap(), unknown: 0, - }) + } } pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem { @@ -69,32 +69,32 @@ pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem { } } -pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> Result { +pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> CreateItem { let bytes = item.item.as_client_bytes(); - Ok(CreateItem { + CreateItem { client: area_client.local_client.id(), target: 0, - item_data: bytes[0..12].try_into()?, + item_data: bytes[0..12].try_into().unwrap(), item_id: item.item_id.0, - item_data2: bytes[12..16].try_into()?, + item_data2: bytes[12..16].try_into().unwrap(), unknown: 0, - }) + } } -pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem) -> Result { +pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem) -> CreateItem { let bytes = item.item.as_client_bytes(); - Ok(CreateItem { + CreateItem { client: area_client.local_client.id(), target: 0, - item_data: bytes[0..12].try_into()?, + item_data: bytes[0..12].try_into().unwrap(), item_id: item.item_id.0, - item_data2: bytes[12..16].try_into()?, + item_data2: bytes[12..16].try_into().unwrap(), unknown: 0, - }) + } } -pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Result { - Ok(RemoveItemFromFloor { +pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> RemoveItemFromFloor { + RemoveItemFromFloor { client: area_client.local_client.id(), target: 0, client_id: area_client.local_client.id(), @@ -102,12 +102,12 @@ pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Resu map_area: item.map_area.area_value(), unknown2: 0, item_id: item.item_id.0, - }) + } } -pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> Result { +pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> DropSplitStack { let item_bytes = item.as_client_bytes(); - Ok(DropSplitStack { + DropSplitStack { client: area_client.local_client.id(), target: 0, variety: 0, @@ -115,16 +115,16 @@ pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> Result Result { +pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> DropSplitStack { let item_bytes = item.as_client_bytes(); - Ok(DropSplitStack { + DropSplitStack { client: area_client.local_client.id(), target: 0, variety: 0, @@ -132,11 +132,11 @@ pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> Res map_area: item.map_area.area_value(), x: item.x, z: item.z, - item_bytes: item_bytes[0..12].try_into()?, + item_bytes: item_bytes[0..12].try_into().unwrap(), item_id: item.item_id.0, - item_bytes2: item_bytes[12..16].try_into()?, + item_bytes2: item_bytes[12..16].try_into().unwrap(), unknown2: 0, - }) + } } pub fn character_gained_exp(area_client: AreaClient, exp: u32) -> GiveCharacterExp { @@ -215,13 +215,13 @@ pub fn shop_list(shop_type: u8, items: &[I]) -> ShopList { } } -pub fn tek_preview(id: ClientItemId, weapon: &item::weapon::Weapon) -> Result { +pub fn tek_preview(id: ClientItemId, weapon: &item::weapon::Weapon) -> TekPreview { let bytes = weapon.as_bytes(); - Ok(TekPreview { + TekPreview { client: 0x79, target: 0, - item_bytes: bytes[0..12].try_into()?, + item_bytes: bytes[0..12].try_into().unwrap(), item_id: id.0, - item_bytes2: bytes[12..16].try_into()?, - }) + item_bytes2: bytes[12..16].try_into().unwrap(), + } } diff --git a/src/ship/packet/builder/quest.rs b/src/pktbuilder/src/quest.rs similarity index 71% rename from src/ship/packet/builder/quest.rs rename to src/pktbuilder/src/quest.rs index f162269..3676e8c 100644 --- a/src/ship/packet/builder/quest.rs +++ b/src/pktbuilder/src/quest.rs @@ -1,8 +1,9 @@ -use crate::ship::quests::{Quest, QuestList}; -use crate::ship::ship::{QUEST_CATEGORY_MENU_ID, QUEST_SELECT_MENU_ID}; +use quests::{Quest, QuestList}; use libpso::packet::ship::*; -use libpso::{utf8_to_array, utf8_to_utf16_array}; +use libpso::util::{utf8_to_array, utf8_to_utf16_array}; +pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2; +pub const QUEST_SELECT_MENU_ID: u32 = 0xA3; pub fn quest_category_list(quests: &QuestList) -> QuestCategoryList { let categories = quests.iter() @@ -11,8 +12,8 @@ pub fn quest_category_list(quests: &QuestList) -> QuestCategoryList { QuestCategory { menu_id: QUEST_CATEGORY_MENU_ID, option_id: i as u32, - name: utf8_to_utf16_array!(category.name, 32), - description: utf8_to_utf16_array!(category.description, 122), + name: utf8_to_utf16_array(&category.name), + description: utf8_to_utf16_array(&category.description), } }) .collect(); @@ -29,8 +30,8 @@ pub fn quest_list(category_id: u32, quests: &[Quest]) -> QuestOptionList { menu_id: QUEST_SELECT_MENU_ID, category_id: category_id as u16, quest_id: quest.id, - name: utf8_to_utf16_array!(quest.name, 32), - description: utf8_to_utf16_array!(quest.description, 122), + name: utf8_to_utf16_array(&quest.name), + description: utf8_to_utf16_array(&quest.description), } }) .collect(); @@ -42,7 +43,7 @@ pub fn quest_list(category_id: u32, quests: &[Quest]) -> QuestOptionList { pub fn quest_detail(quest: &Quest) -> QuestDetail { QuestDetail { - description: utf8_to_utf16_array!(quest.full_description, 288), + description: utf8_to_utf16_array(&quest.full_description), } } @@ -50,9 +51,9 @@ pub fn quest_header(quest_menu_select: &QuestMenuSelect, data_blob: &[u8], suffi let path = format!("{}-{}.{}", quest_menu_select.category, quest_menu_select.quest, suffix); QuestHeader { unknown1: [0; 0x24], - filename: utf8_to_array!(path, 16), + filename: utf8_to_array(&path), length: data_blob.len() as u32, - name: utf8_to_array!(path, 16), + name: utf8_to_array(&path), unknown2: [0; 8], } } diff --git a/src/ship/packet/builder/room.rs b/src/pktbuilder/src/room.rs similarity index 84% rename from src/ship/packet/builder/room.rs rename to src/pktbuilder/src/room.rs index 2b5c8e5..a7bbe75 100644 --- a/src/ship/packet/builder/room.rs +++ b/src/pktbuilder/src/room.rs @@ -1,11 +1,12 @@ -use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{ShipError, ClientState, Clients, ShipEvent}; -use crate::ship::location::{ClientLocation, RoomId, AreaClient, ClientLocationError}; -use crate::ship::room::RoomState; -use crate::ship::items::state::ItemState; -use crate::ship::packet::builder::{player_header, player_info}; use std::convert::TryInto; +use libpso::packet::ship::*; +use networking::serverstate::ClientId; +use maps::Holiday; +use client::{ClientState, Clients}; +use location::{ClientLocation, RoomId, AreaClient, ClientLocationError}; +use room::RoomState; +use items::state::ItemState; +use crate::{player_header, player_info}; use futures::stream::StreamExt; @@ -14,13 +15,14 @@ pub async fn join_room(id: ClientId, client_location: &ClientLocation, room_id: RoomId, room: &RoomState, - event: ShipEvent) + event: Holiday) -> Result { let all_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + #[allow(clippy::manual_try_fold)] // I don't think its even possible to make this work here let players = futures::stream::iter(all_clients.iter()) .enumerate() .fold::, _, _>(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| async move { - let header_area_client = client_location.get_local_client(id).await.map_err(|err| ShipError::ClientLocationError(err.into()))?; + let header_area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError {err.into() })?; clients.with(c.client, |client| Box::pin(async move { acc.map(|mut a| { a[i] = player_header(0x10000, client, &header_area_client); @@ -57,7 +59,7 @@ pub async fn add_to_room(_id: ClientId, area_client: &AreaClient, leader: &AreaClient, item_state: &ItemState, - event: ShipEvent) + event: Holiday) -> Result { let inventory = item_state.get_character_inventory(&client.character).await?; Ok(AddToRoom { diff --git a/src/ship/packet/builder/ship.rs b/src/pktbuilder/src/ship.rs similarity index 68% rename from src/ship/packet/builder/ship.rs rename to src/pktbuilder/src/ship.rs index 1411f2a..b5a9659 100644 --- a/src/ship/packet/builder/ship.rs +++ b/src/pktbuilder/src/ship.rs @@ -1,8 +1,9 @@ use libpso::packet::login::{ShipList, ShipListEntry}; -use libpso::utf8_to_utf16_array; +use libpso::util::utf8_to_utf16_array; -use crate::common::interserver::Ship; -use crate::login::character::SHIP_MENU_ID; +use networking::interserver::Ship; + +pub const SHIP_MENU_ID: u32 = 1; pub fn ship_list(ships: &[Ship]) -> ShipList { let ships = ships.iter() @@ -12,7 +13,7 @@ pub fn ship_list(ships: &[Ship]) -> ShipList { menu: SHIP_MENU_ID, item: i as u32, flags: 0, - name: utf8_to_utf16_array!(ship.name, 0x11) + name: utf8_to_utf16_array(&ship.name) } }) .collect(); diff --git a/src/pktbuilder/src/team.rs b/src/pktbuilder/src/team.rs new file mode 100644 index 0000000..9ebdfb9 --- /dev/null +++ b/src/pktbuilder/src/team.rs @@ -0,0 +1,107 @@ +use futures::stream::{FuturesOrdered, StreamExt}; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::entity::gateway::EntityGateway; +use crate::ship::client::{Clients, ClientState}; +use crate::ship::teams::Teams; +use crate::ship::location::ClientLocation; +use crate::ship::ship::ShipError; +use crate::entity::team::TeamEntity; + + +pub fn client_team_state_changed(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> ClientTeamStateChanged { + ClientTeamStateChanged { + unknown: 0, + guildcard: client.user.guildcard(), + team_id: team.id.0, + unknown2: [0;2], + privilege: 0x40, // TODO: improve + team_name: libpso::utf8_to_utf16_array!(team.name, 14), + unknown3: 0x00986C84, // TODO: what if we omit this? + } +} + +fn player_team_info(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> PlayerTeamInfo { + PlayerTeamInfo { + guildcard: client.user.guildcard(), + team_id: team.id.0, + info: 0, + info2: 0, + privilege: 0x40, // TODO: improve + team_name: libpso::utf8_to_utf16_array!(team.name, 14), + unknown: 0x00986C84, // TODO: what if we omit this? + guildcard_again: client.user.guildcard(), + client_id: client_id.0 as u32, + character_name: libpso::utf8_to_utf16_array!(client.character.name, 12), + unknown2: 0, + unknown3: 0, + team_flag: team.team_flag, + } +} + +pub fn team_info_individual(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> TeamInfo { + TeamInfo { + clients: vec![player_team_info(client_id, client, team)] + } +} + + +pub async fn player_team_info_list(id: ClientId, + client_location: &ClientLocation, + clients: &Clients, + teams: &Teams, +) -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ + Ok(futures::stream::iter(client_location.get_all_clients_by_client(id).await?.into_iter()) + .filter_map(|area_client| { + let clients = clients.clone(); + async move { + clients.with(area_client.client, |client| { + let mut teams = teams.clone(); + Box::pin(async move { + let team = teams.get_team(area_client.client).await.ok()??; + Some(player_team_info(area_client.client, client, &team)) + })}).await.ok()? + }}) + .collect::>() + .await) +} + +pub async fn team_info(id: ClientId, + client_location: &ClientLocation, + clients: &Clients, + teams: &Teams, +) -> Result +where + EG: EntityGateway + Clone + 'static, +{ + Ok(TeamInfo { + clients: player_team_info_list(id, client_location, clients, teams).await?, + }) +} + +pub async fn lobby_team_list(id: ClientId, + client_location: &ClientLocation, + clients: &Clients, + teams: &Teams, +) -> Result +where + EG: EntityGateway + Clone + 'static, +{ + Ok(TeamLobbyList { + clients: player_team_info_list(id, client_location, clients, teams).await?, + }) +} + +pub fn team_invitation_info(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> TeamInvitationInfo { + TeamInvitationInfo { + guildcard: client.user.guildcard(), + team_id: team.id.0, + unknown: [0; 2], + team_name: libpso::utf8_to_utf16_array!(team.name, 14), + unknown2: 0x00986C84, // TODO: what if we omit this? + team_flag: team.team_flag, + } +} diff --git a/src/ship/packet/builder/trade.rs b/src/pktbuilder/src/trade.rs similarity index 100% rename from src/ship/packet/builder/trade.rs rename to src/pktbuilder/src/trade.rs diff --git a/src/quests/Cargo.toml b/src/quests/Cargo.toml new file mode 100644 index 0000000..6cab926 --- /dev/null +++ b/src/quests/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "quests" +version = "0.1.0" +edition = "2021" + +[dependencies] +maps = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +ages-prs = { workspace = true } +log = { workspace = true } +byteorder = { workspace = true } +thiserror = { workspace = true } +anyhow = { workspace = true } +toml = { workspace = true } +serde = { workspace = true } diff --git a/src/ship/quests.rs b/src/quests/src/lib.rs similarity index 97% rename from src/ship/quests.rs rename to src/quests/src/lib.rs index 4f5eb26..91e5d4d 100644 --- a/src/ship/quests.rs +++ b/src/quests/src/lib.rs @@ -10,9 +10,12 @@ use serde::{Serialize, Deserialize}; use ages_prs::{LegacyPrsDecoder, LegacyPrsEncoder}; use byteorder::{LittleEndian, ReadBytesExt}; use libpso::util::array_to_utf16; -use crate::ship::map::{MapArea, MapAreaError, MapObject, MapEnemy, enemy_data_from_stream, objects_from_stream}; -use crate::ship::room::{Episode, RoomMode}; -use crate::ship::map::area::{MapAreaLookup, MapAreaLookupBuilder}; +use maps::area::{MapArea, MapAreaError}; +use maps::object::MapObject; +use maps::enemy::MapEnemy; +use maps::maps::{objects_from_stream, enemy_data_from_stream}; +use maps::room::{Episode, RoomMode}; +use maps::area::{MapAreaLookup, MapAreaLookupBuilder}; #[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -101,7 +104,7 @@ fn quest_episode(bin: &[u8]) -> Option { for bytes in bin.windows(3) { // set_episode if bytes[0] == 0xF8 && bytes[1] == 0xBC { - return Episode::from_quest(bytes[2]).ok() + return Episode::from_quest(bytes[2]) } } None diff --git a/src/room/Cargo.toml b/src/room/Cargo.toml new file mode 100644 index 0000000..d081284 --- /dev/null +++ b/src/room/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "room" +version = "0.1.0" +edition = "2021" + +[dependencies] +maps = { workspace = true } +entity = { workspace = true } +quests = { workspace = true } +location = { workspace = true } +drops = { workspace = true } + +rand = { workspace = true } +async-std = { workspace = true } +futures = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } diff --git a/src/ship/room.rs b/src/room/src/lib.rs similarity index 55% rename from src/ship/room.rs rename to src/room/src/lib.rs index b3a03c2..fca3669 100644 --- a/src/ship/room.rs +++ b/src/room/src/lib.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::convert::{From, Into, TryFrom}; +use std::convert::{From, Into}; use async_std::sync::{Arc, RwLock, RwLockReadGuard}; use futures::future::BoxFuture; use futures::stream::{FuturesOrdered, Stream}; @@ -7,19 +7,29 @@ use futures::stream::{FuturesOrdered, Stream}; use thiserror::Error; use rand::Rng; -use crate::ship::map::Maps; -use crate::ship::drops::DropTable; -use crate::entity::character::SectionID; -use crate::entity::room::{RoomEntityId, RoomEntityMode}; -use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats}; -use crate::ship::map::area::MapAreaLookup; -use crate::ship::quests; -use crate::ship::ship::{ShipError, ShipEvent}; -use crate::ship::location::{MAX_ROOMS, RoomId}; +use quests::{QuestList, QuestLoadError}; +use maps::maps::Maps; +use drops::DropTable; +use entity::character::SectionID; +use entity::room::{RoomEntityId, RoomEntityMode}; +use maps::monster::{load_monster_stats_table, MonsterType, MonsterStats}; +use maps::area::MapAreaLookup; +use maps::Holiday; +use location::{MAX_ROOMS, RoomId}; + +use maps::room::{Episode, Difficulty, RoomMode}; + +#[derive(Error, Debug)] +pub enum RoomError { + #[error("invalid room id {0}")] + Invalid(u32), +} + #[derive(Clone)] pub struct Rooms([Arc>>; MAX_ROOMS]); + impl Default for Rooms { fn default() -> Rooms { Rooms(core::array::from_fn(|_| Arc::new(RwLock::new(None)))) @@ -30,7 +40,7 @@ impl Rooms { pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), anyhow::Error> { *self.0 .get(room_id.0) - .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? + .ok_or(RoomError::Invalid(room_id.0 as u32))? .write() .await = Some(room); Ok(()) @@ -63,14 +73,14 @@ impl Rooms { { let room = self.0 .get(room_id.0) - .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? + .ok_or(RoomError::Invalid(room_id.0 as u32))? .read() .await; if let Some(room) = room.as_ref() { Ok(func(room).await) } else { - Err(ShipError::InvalidRoom(room_id.0 as u32).into()) + Err(RoomError::Invalid(room_id.0 as u32).into()) } } @@ -81,7 +91,7 @@ impl Rooms { { let mut room = self.0 .get(room_id.0) - .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? + .ok_or(RoomError::Invalid(room_id.0 as u32))? .write() .await; @@ -89,7 +99,7 @@ impl Rooms { Ok(func(room).await) } else { - Err(ShipError::InvalidRoom(room_id.0 as u32).into()) + Err(RoomError::Invalid(room_id.0 as u32).into()) } } @@ -123,156 +133,7 @@ pub enum RoomCreationError { CouldNotLoadQuests, } -#[derive(Debug, Copy, Clone, derive_more::Display)] -pub enum Episode { - #[display(fmt="ep1")] - One, - #[display(fmt="ep2")] - Two, - #[display(fmt="ep4")] - Four, -} - -#[derive(Debug, Copy, Clone)] -pub enum PlayerMode{ - Single, - Multi, -} - -impl PlayerMode { - pub fn value(&self) -> u8 { - match self { - PlayerMode::Single => 1, - PlayerMode::Multi => 0, - } - } -} - -impl TryFrom for Episode { - type Error = RoomCreationError; - - fn try_from(value: u8) -> Result { - match value { - 1 => Ok(Episode::One), - 2 => Ok(Episode::Two), - 3 => Ok(Episode::Four), - _ => Err(RoomCreationError::InvalidEpisode(value)) - } - } -} - -impl From for u8 { - fn from(other: Episode) -> u8 { - match other { - Episode::One => 1, - Episode::Two => 2, - Episode::Four => 3, - } - } -} - -impl Episode { - pub fn from_quest(value: u8) -> Result { - match value { - 0 => Ok(Episode::One), - 1 => Ok(Episode::Two), - 2 => Ok(Episode::Four), - _ => Err(RoomCreationError::InvalidEpisode(value)) - } - } -} -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] -pub enum Difficulty { - Normal, - Hard, - VeryHard, - Ultimate, -} - -impl TryFrom for Difficulty { - type Error = RoomCreationError; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Difficulty::Normal), - 1 => Ok(Difficulty::Hard), - 2 => Ok(Difficulty::VeryHard), - 3 => Ok(Difficulty::Ultimate), - _ => Err(RoomCreationError::InvalidDifficulty(value)) - } - } -} - -impl From for u8 { - fn from(other: Difficulty) -> u8 { - match other { - Difficulty::Normal => 0, - Difficulty::Hard => 1, - Difficulty::VeryHard => 2, - Difficulty::Ultimate => 3, - } - } -} - -#[derive(Debug, Copy, Clone, derive_more::Display)] -pub enum RoomMode { - #[display(fmt="single")] - Single { - episode: Episode, - difficulty: Difficulty, - }, - #[display(fmt="multi")] - Multi { - episode: Episode, - difficulty: Difficulty, - }, - #[display(fmt="challenge")] - Challenge { - episode: Episode, - }, - #[display(fmt="battle")] - Battle { - episode: Episode, - difficulty: Difficulty, - } -} - - -impl RoomMode { - pub fn difficulty(&self) -> Difficulty { - match self { - RoomMode::Single {difficulty, ..} => *difficulty, - RoomMode::Multi {difficulty, ..} => *difficulty, - RoomMode::Battle {difficulty, ..} => *difficulty, - RoomMode::Challenge {..} => Difficulty::Normal, - } - } - - pub fn episode(&self) -> Episode { - match self { - RoomMode::Single {episode, ..} => *episode, - RoomMode::Multi {episode, ..} => *episode, - RoomMode::Battle {episode, ..} => *episode, - RoomMode::Challenge {episode, ..} => *episode, - } - } - - pub fn battle(&self) -> bool { - matches!(self, RoomMode::Battle {..}) - } - - pub fn challenge(&self) -> bool { - matches!(self, RoomMode::Challenge {..}) - } - - pub fn player_mode(&self) -> PlayerMode { - match self { - RoomMode::Single {..} => PlayerMode::Single, - _ => PlayerMode::Multi, - } - } -} pub enum QuestCategoryType { Standard, Government, @@ -310,15 +171,15 @@ pub struct RoomState { pub name: String, pub password: [u16; 16], pub maps: Maps, - pub drop_table: Box, + pub drop_table: Box, pub section_id: SectionID, pub random_seed: u32, pub bursting: bool, pub monster_stats: Box>, pub map_areas: MapAreaLookup, pub quest_group: QuestCategoryType, - pub standard_quests: quests::QuestList, - pub government_quests: quests::QuestList, + pub standard_quests: QuestList, + pub government_quests: QuestList, // enemy info } @@ -353,14 +214,14 @@ impl RoomState { difficulty + 0x22 } - pub fn quests(&self) -> &quests::QuestList { + pub fn quests(&self) -> &QuestList { match self.quest_group { QuestCategoryType::Standard => &self.standard_quests, QuestCategoryType::Government => &self.government_quests, } } - #[allow(clippy::too_many_arguments)] + #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub fn new (room_id: RoomEntityId, mode: RoomEntityMode, episode: Episode, @@ -368,9 +229,11 @@ impl RoomState { section_id: SectionID, name: String, password: [u16; 16], - event: ShipEvent, - map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, + event: Holiday, + map_builder: Arc Maps + Send + Sync>>, + drop_table_builder: Arc Box + Send + Sync>>, + standard_quest_builder: Arc Result + Send + Sync>>, + government_quest_builder: Arc Result + Send + Sync>>, ) -> Result { let mode = match mode { RoomEntityMode::Single => RoomMode::Single { @@ -399,12 +262,12 @@ impl RoomState { password, maps: map_builder(mode, event), section_id, - drop_table: Box::new(drop_table_builder(episode, difficulty, section_id)), + drop_table: drop_table_builder(episode, difficulty, section_id), bursting: false, map_areas: MapAreaLookup::new(&episode), quest_group: QuestCategoryType::Standard, - standard_quests: quests::load_standard_quests(mode)?, - government_quests: quests::load_government_quests(mode)?, + standard_quests: standard_quest_builder(mode)?, + government_quests: government_quest_builder(mode)?, }) } diff --git a/src/ship/drops/drop_table.rs b/src/ship/drops/drop_table.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs deleted file mode 100644 index e9251c4..0000000 --- a/src/ship/items/manager.rs +++ /dev/null @@ -1,1380 +0,0 @@ -use crate::ship::items::ClientItemId; -use std::collections::HashMap; -use std::cmp::Ordering; -use std::cell::RefCell; -use thiserror::Error; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel}; -use crate::entity::item::{ItemDetail, ItemNote, BankName}; -use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, BankItemEntity}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::weapon; -use crate::ship::map::MapArea; -use crate::ship::ship::ItemDropLocation; -use crate::ship::trade::TradeItem; -use crate::ship::drops::{ItemDrop, ItemDropType}; -use crate::ship::location::{AreaClient, RoomId}; -use crate::ship::shops::ShopItem; -use crate::ship::packet::handler::trade::{TradeError, OTHER_MESETA_ITEM_ID}; - -use crate::ship::items::bank::*; -use crate::ship::items::floor::*; -use crate::ship::items::inventory::*; -use crate::ship::items::transaction::{ItemTransaction, ItemAction, TransactionError, TransactionCommitError}; - -#[derive(PartialEq, Eq)] -pub enum FloorType { - Local, - Shared, -} - -pub enum TriggerCreateItem { - Yes, - No -} - -#[derive(Error, Debug)] -#[error("itemmanager")] -pub enum ItemManagerError { - #[error("gateway")] - EntityGatewayError, - #[error("no such item id {0}")] - NoSuchItemId(ClientItemId), - NoCharacter(CharacterEntityId), - NoRoom(RoomId), - CouldNotAddToInventory(ClientItemId), - //ItemBelongsToOtherPlayer, - #[error("shrug")] - Idunnoman, - CouldNotSplitItem(ClientItemId), - #[error("could not drop meseta")] - CouldNotDropMeseta, - InvalidBankName(BankName), - #[error("not enough tools")] - NotEnoughTools(Tool, usize, usize), // have, expected - InventoryItemConsumeError(#[from] InventoryItemConsumeError), - #[error("bank full")] - BankFull, - WrongItemType(ClientItemId), - UseItemError(#[from] use_tool::UseItemError), - #[error("could not buy item")] - CouldNotBuyItem, - #[error("could not add bought item to inventory")] - CouldNotAddBoughtItemToInventory, - ItemIdNotInInventory(ClientItemId), - #[error("cannot get mut item")] - CannotGetMutItem, - #[error("cannot get individual item")] - CannotGetIndividualItem, - InvalidSlot(u8, u8), // slots available, slot attempted - #[error("no armor equipped")] - NoArmorEquipped, - GatewayError(#[from] GatewayError), - #[error("stacked item")] - StackedItemError(Vec), - #[error("item not sellable")] - ItemNotSellable(InventoryItem), - #[error("wallet full")] - WalletFull, - #[error("invalid sale")] - InvalidSale, - ItemTransactionAction(Box), - #[error("invalid trade")] - InvalidTrade, -} - -impl std::convert::From> for ItemManagerError -where - E: std::fmt::Debug + std::marker::Send + std::marker::Sync + std::error::Error + 'static, -{ - fn from(other: TransactionError) -> ItemManagerError { - match other { - TransactionError::Action(err) => { - ItemManagerError::ItemTransactionAction(Box::new(err)) - }, - TransactionError::Commit(err) => { - match err { - TransactionCommitError::Gateway(gw) => { - ItemManagerError::GatewayError(gw) - }, - TransactionCommitError::ItemManager(im) => { - im - } - } - } - } - } -} - - -pub struct ItemManager { - pub(super) id_counter: u32, - - pub(self) character_inventory: HashMap, - pub(self) character_meseta: HashMap, - pub(self) bank_meseta: HashMap, - //character_bank: HashMap>, - pub(self) character_bank: HashMap, - pub(self) character_floor: HashMap, - - pub(self) character_room: HashMap, - pub(self) room_floor: HashMap, - pub(self) room_item_id_counter: RefCell ClientItemId + Send>>>, -} - -impl Default for ItemManager { - fn default() -> ItemManager { - ItemManager { - id_counter: 0, - character_inventory: HashMap::new(), - character_meseta: HashMap::new(), - bank_meseta: HashMap::new(), - character_bank: HashMap::new(), - character_floor: HashMap::new(), - character_room: HashMap::new(), - room_floor: HashMap::new(), - room_item_id_counter: RefCell::new(HashMap::new()), - } - } -} - -impl ItemManager { - pub fn next_global_item_id(&mut self) -> ClientItemId { - self.id_counter += 1; - ClientItemId(self.id_counter) - } - - pub async fn load_character(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), anyhow::Error> { - let inventory = entity_gateway.get_character_inventory(&character.id).await?; - let bank = entity_gateway.get_character_bank(&character.id, &BankName("".into())).await?; - let equipped = entity_gateway.get_character_equips(&character.id).await?; - - let inventory_items = inventory.items.into_iter() - .map(|item| -> Result { - Ok(match item { - InventoryItemEntity::Individual(item) => { - InventoryItem::Individual(IndividualInventoryItem { - entity_id: item.id, - item_id: self.next_global_item_id(), - item: item.item, - }) - }, - InventoryItemEntity::Stacked(items) => { - InventoryItem::Stacked(StackedInventoryItem { - entity_ids: items.iter().map(|i| i.id).collect(), - item_id: self.next_global_item_id(), - tool: items.get(0) - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - .item - .clone() - .as_tool() - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - }) - }, - }) - }) - .collect::, _>>()?; - let character_inventory = CharacterInventory::new(inventory_items, &equipped); - - let bank_items = bank.items.into_iter() - .map(|item| -> Result { - Ok(match item { - BankItemEntity::Individual(item) => { - BankItem::Individual(IndividualBankItem { - entity_id: item.id, - item_id: self.next_global_item_id(), - item: item.item, - }) - }, - BankItemEntity::Stacked(items) => { - BankItem::Stacked(StackedBankItem { - entity_ids: items.iter().map(|i| i.id).collect(), - item_id: self.next_global_item_id(), - tool: items.get(0) - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - .item - .clone() - .as_tool() - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - }) - }, - }) - }) - .collect::, _>>()?; - let character_bank = CharacterBank::new(bank_items); - - let character_meseta = entity_gateway.get_character_meseta(&character.id).await?; - let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?; - - self.character_inventory.insert(character.id, character_inventory); - self.character_bank.insert(character.id, character_bank); - self.character_meseta.insert(character.id, character_meseta); - self.bank_meseta.insert(character.id, bank_meseta); - Ok(()) - } - - pub fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { - let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000; - let inventory = self.character_inventory.get_mut(&character.id).unwrap(); - inventory.initialize_item_ids(base_inventory_id); - let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000; - let default_bank = self.character_bank.get_mut(&character.id); - if let Some(default_bank ) = default_bank { - default_bank.initialize_item_ids(base_bank_id); - } - self.character_room.insert(character.id, room_id); - self.character_floor.insert(character.id, RoomFloorItems::default()); - self.room_floor.entry(room_id).or_insert_with(RoomFloorItems::default); - - let mut inc = 0x00810000; - self.room_item_id_counter.borrow_mut().entry(room_id).or_insert_with(|| Box::new(move || { - inc += 1; - ClientItemId(inc) - })); - } - - pub fn get_character_inventory(&self, character: &CharacterEntity) -> Result<&CharacterInventory, anyhow::Error> { - Ok(self.character_inventory.get(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?) - } - - pub fn get_character_inventory_mut<'a>(&'a mut self, character: &CharacterEntity) -> Result<&'a mut CharacterInventory, anyhow::Error> { - Ok(self.character_inventory.get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?) - } - - pub fn get_character_bank(&self, character: &CharacterEntity) -> Result<&CharacterBank, anyhow::Error> { - self.character_bank - .get(&character.id) - .ok_or_else(|| ItemManagerError::NoCharacter(character.id).into()) - } - - pub fn get_character_meseta(&self, character_id: &CharacterEntityId) -> Result<&Meseta, ItemManagerError> { - self.character_meseta.get(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_character_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<&'a mut Meseta, ItemManagerError> { - self.character_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_bank_meseta(&self, character_id: &CharacterEntityId) -> Result<&Meseta, ItemManagerError> { - self.bank_meseta.get(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_bank_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<&'a mut Meseta, ItemManagerError> { - self.bank_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_character_and_bank_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<(&'a mut Meseta, &'a mut Meseta), ItemManagerError> { - Ok(( - self.character_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id))?, - self.bank_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id))? - )) - } - - pub fn remove_character_from_room(&mut self, character: &CharacterEntity) { - self.character_inventory.remove(&character.id); - self.character_floor.remove(&character.id); - if let Some(room) = self.character_room.remove(&character.id).as_ref() { - if self.character_room.iter().any(|(_, r)| r == room) { - self.room_floor.remove(room); - } - } - } - - pub fn get_floor_item_by_id(&self, character: &CharacterEntity, item_id: ClientItemId) -> Result<(&FloorItem, FloorType), anyhow::Error> { - let local_floor = self.character_floor.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get(room).ok_or(ItemManagerError::NoCharacter(character.id))?; - - local_floor.get_item_by_id(item_id).map(|item| (item, FloorType::Local)) - .or_else(|| { - shared_floor.get_item_by_id(item_id).map(|item| (item, FloorType::Shared)) - }) - .ok_or_else(|| ItemManagerError::NoSuchItemId(item_id).into()) - } - - pub async fn character_picks_up_item(&mut self, entity_gateway: &mut EG, character: &mut CharacterEntity, item_id: ClientItemId) - -> Result { - let it = ItemTransaction::new(self, (character, item_id)) - .act(|it, (character, item_id)| -> Result<_, ItemManagerError> { - let local_floor = it.manager.character_floor.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let inventory = it.manager.character_inventory.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room_id = it.manager.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = it.manager.room_floor.get(room_id).ok_or(ItemManagerError::NoRoom(*room_id))?; - - let floor_item = match local_floor.get_item_by_id(*item_id) { - Some(floor_item) => { - it.action(Box::new(RemoveFromLocalFloor { - character_id: character.id, - item_id: *item_id - })); - floor_item - }, - None => { - match shared_floor.get_item_by_id(*item_id) { - Some(floor_item) => { - it.action(Box::new(RemoveFromSharedFloor { - room_id: *room_id, - item_id: *item_id - })); - floor_item - }, - None => { - return Err(ItemManagerError::NoSuchItemId(*item_id)) - } - } - } - }; - - let create_trigger = match floor_item { - FloorItem::Individual(individual_floor_item) => { - if inventory.space_for_individual_item() { - it.action(Box::new(AddIndividualFloorItemToInventory { - character: (**character).clone(), - item: individual_floor_item.clone() - })) - } - else { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - } - TriggerCreateItem::Yes - }, - FloorItem::Stacked(stacked_floor_item) => { - match inventory.space_for_stacked_item(&stacked_floor_item.tool, stacked_floor_item.entity_ids.len()) { - SpaceForStack::Yes(YesThereIsSpace::NewStack) => { - it.action(Box::new(AddStackedFloorItemToInventory { - character_id: character.id, - item: stacked_floor_item.clone() - })); - TriggerCreateItem::Yes - }, - SpaceForStack::Yes(YesThereIsSpace::ExistingStack) => { - it.action(Box::new(AddStackedFloorItemToInventory { - character_id: character.id, - item: stacked_floor_item.clone() - })); - TriggerCreateItem::No - }, - SpaceForStack::No(_) => { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - }, - } - }, - FloorItem::Meseta(meseta_floor_item) => { - let character_meseta = it.manager.character_meseta.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - if character_meseta.0 >= 999999 { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - } - it.action(Box::new(AddMesetaFloorItemToInventory { - character_id: character.id, - item: meseta_floor_item.clone() - })); - - TriggerCreateItem::No - }, - }; - Ok(create_trigger) - }); - it.commit(self, entity_gateway) - .await - .map_err(|err| err.into()) - } - - pub async fn enemy_drop_item_on_local_floor<'a, EG: EntityGateway>(&'a mut self, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_drop: ItemDrop) -> Result<&'a FloorItem, anyhow::Error> { - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - enum ItemOrMeseta { - Individual(ItemDetail), - Stacked(Tool), - Meseta(Meseta) - } - - let item = match item_drop.item { - ItemDropType::Weapon(w) => ItemOrMeseta::Individual(ItemDetail::Weapon(w)), - ItemDropType::Armor(w) => ItemOrMeseta::Individual(ItemDetail::Armor(w)), - ItemDropType::Shield(w) => ItemOrMeseta::Individual(ItemDetail::Shield(w)), - ItemDropType::Unit(w) => ItemOrMeseta::Individual(ItemDetail::Unit(w)), - ItemDropType::TechniqueDisk(w) => ItemOrMeseta::Individual(ItemDetail::TechniqueDisk(w)), - ItemDropType::Mag(w) => ItemOrMeseta::Individual(ItemDetail::Mag(w)), - //ItemDropType::IndividualTool(t) => ItemOrMeseta::Individual(ItemDetail::Tool(t)), - //ItemDropType::StackedTool(t, _) => ItemOrMeseta::Stacked(t), - ItemDropType::Tool(t) if t.tool.is_stackable() => ItemOrMeseta::Stacked(t), - ItemDropType::Tool(t) if !t.tool.is_stackable() => ItemOrMeseta::Individual(ItemDetail::Tool(t)), - ItemDropType::Meseta(m) => ItemOrMeseta::Meseta(Meseta(m)), - _ => unreachable!() // rust isnt smart enough to see that the conditional on tool catches everything - }; - - let item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let floor_item = match item { - ItemOrMeseta::Individual(item_detail) => { - let entity = entity_gateway.create_item(NewItemEntity { - item: item_detail.clone(), - }).await?; - entity_gateway.add_item_note(&entity.id, ItemNote::EnemyDrop { - character_id: character.id, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }).await?; - FloorItem::Individual(IndividualFloorItem { - entity_id: entity.id, - item_id, - item: item_detail, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - ItemOrMeseta::Stacked(tool) => { - let entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&entity.id, ItemNote::EnemyDrop { - character_id: character.id, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }).await?; - FloorItem::Stacked(StackedFloorItem { - entity_ids: vec![entity.id], - item_id, - tool, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - ItemOrMeseta::Meseta(meseta) => { - FloorItem::Meseta(MesetaFloorItem { - item_id, - meseta, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - }; - - self.character_floor.entry(character.id).or_insert_with(RoomFloorItems::default).add_item(floor_item); - // TODO: make these real errors - 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(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - //inventory_item: InventoryItem, - item_id: ClientItemId, - item_drop_location: (MapArea, f32, f32, f32)) - -> Result<(), anyhow::Error> { - 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 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))?; - - match dropped_inventory_item { - InventoryItem::Individual(individual_inventory_item) => { - let individual_floor_item = shared_floor.drop_individual_inventory_item(individual_inventory_item, item_drop_location); - entity_gateway.add_item_note( - &individual_floor_item.entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: item_drop_location.0, - x: item_drop_location.1, - y: item_drop_location.2, - z: item_drop_location.3, - } - ).await?; - }, - InventoryItem::Stacked(stacked_inventory_item) => { - let stacked_floor_item = shared_floor.drop_stacked_inventory_item(stacked_inventory_item, item_drop_location); - for entity_id in &stacked_floor_item.entity_ids { - entity_gateway.add_item_note( - entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: item_drop_location.0, - x: item_drop_location.1, - y: item_drop_location.2, - z: item_drop_location.3, - } - ).await?; - } - }, - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn player_drops_meseta_on_shared_floor(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - drop_location: ItemDropLocation, - amount: u32) - -> Result { - 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 character_meseta = self.character_meseta.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - if character_meseta.0 < amount { - return Err(ItemManagerError::CouldNotDropMeseta.into()) - } - character_meseta.0 -= amount; - entity_gateway.set_character_meseta(&character.id, *character_meseta).await?; - - let item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let floor_item = FloorItem::Meseta(MesetaFloorItem { - item_id, - meseta: Meseta(amount), - map_area: drop_location.map_area, - x: drop_location.x, - y: 0.0, - z: drop_location.z, - }); - - shared_floor.add_item(floor_item.clone()); - Ok(floor_item) - } - - pub async fn player_drops_partial_stack_on_shared_floor<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - //inventory_item: InventoryItem, - item_id: ClientItemId, - drop_location: ItemDropLocation, - amount: usize) - -> Result<&'a StackedFloorItem, anyhow::Error> { - 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 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 new_item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let stacked_floor_item = shared_floor.drop_partial_stacked_inventory_item(item_to_split, amount, new_item_id, (drop_location.map_area, drop_location.x, 0.0, drop_location.z)) - .ok_or(ItemManagerError::CouldNotSplitItem(item_id))?; - - for entity_id in &stacked_floor_item.entity_ids { - entity_gateway.add_item_note( - entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: drop_location.map_area, - x: drop_location.x, - y: 0.0, - z: drop_location.z, - } - ).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(stacked_floor_item) - } - - pub async fn player_consumes_tool(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let used_item = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let consumed_item = used_item.consume(amount)?; - - if let ItemDetail::TechniqueDisk(tech_disk) = consumed_item.item() { - // TODO: validate tech level in packet is in bounds [1..30] - character.techs.set_tech(tech_disk.tech, TechLevel(tech_disk.level as u8)); - entity_gateway.save_character(character).await?; - }; - - for entity_id in consumed_item.entity_ids() { - entity_gateway.add_item_note(&entity_id, - ItemNote::Consumed).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(consumed_item) - } - - pub async fn player_deposits_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let bank = self.character_bank - .get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_to_deposit = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let _bank_item = bank.deposit_item(item_to_deposit, amount).ok_or(ItemManagerError::Idunnoman)?; - - 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?; - Ok(()) - } - - pub async fn player_withdraws_item<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<&'a InventoryItem, anyhow::Error> { - - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let bank = self.character_bank - .get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_to_withdraw = bank.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let inventory_item_slot = { - let inventory_item = inventory.withdraw_item(item_to_withdraw, amount).ok_or(ItemManagerError::Idunnoman)?; - inventory_item.1 - }; - - 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?; - inventory.slot(inventory_item_slot).ok_or_else(|| ItemManagerError::Idunnoman.into()) - } - - pub async fn player_feeds_mag_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - mag_id: ClientItemId, - tool_id: ClientItemId) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let consumed_tool = { - let item_to_feed = inventory.get_item_handle_by_id(tool_id).ok_or(ItemManagerError::NoSuchItemId(tool_id))?; - item_to_feed.consume(1)? - }; - let mut mag_handle = inventory.get_item_handle_by_id(mag_id).ok_or(ItemManagerError::NoSuchItemId(mag_id))?; - - let individual_item = mag_handle.item_mut() - .ok_or(ItemManagerError::NoSuchItemId(mag_id))? - .individual_mut() - .ok_or(ItemManagerError::WrongItemType(mag_id))?; - let mag = individual_item - .mag_mut() - .ok_or(ItemManagerError::WrongItemType(mag_id))?; - - let consumed_tool_type = match &consumed_tool { - ConsumedItem::Stacked(stacked_consumed_item) => stacked_consumed_item.tool.tool, - _ => return Err(ItemManagerError::WrongItemType(tool_id).into()) - }; - mag.feed(consumed_tool_type); - - for entity_id in consumed_tool.entity_ids() { - entity_gateway.feed_mag(&individual_item.entity_id, &entity_id).await?; - entity_gateway.add_item_note(&entity_id, ItemNote::FedToMag { - mag: individual_item.entity_id, - }).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn use_item(&mut self, - used_item: ConsumedItem, - entity_gateway: &mut EG, - character: &mut CharacterEntity) -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - match &used_item.item() { - ItemDetail::Weapon(_w) => { - // something like when items are used to combine/transform them? - //_ => {} - }, - ItemDetail::Tool(t) => { - match t.tool { - ToolType::PowerMaterial => { - use_tool::power_material(entity_gateway, character).await; - }, - ToolType::MindMaterial => { - use_tool::mind_material(entity_gateway, character).await; - }, - ToolType::EvadeMaterial => { - use_tool::evade_material(entity_gateway, character).await; - }, - ToolType::DefMaterial => { - use_tool::def_material(entity_gateway, character).await; - }, - ToolType::LuckMaterial => { - use_tool::luck_material(entity_gateway, character).await; - }, - ToolType::HpMaterial => { - use_tool::hp_material(entity_gateway, character).await; - }, - ToolType::TpMaterial => { - use_tool::tp_material(entity_gateway, character).await; - }, - ToolType::CellOfMag502 => { - use_tool::cell_of_mag_502(entity_gateway, &used_item, inventory).await?; - }, - ToolType::CellOfMag213 => { - use_tool::cell_of_mag_213(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PartsOfRobochao => { - use_tool::parts_of_robochao(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfOpaOpa => { - use_tool::heart_of_opaopa(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfPian => { - use_tool::heart_of_pian(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfChao=> { - use_tool::heart_of_chao(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfAngel => { - use_tool::heart_of_angel(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfHamburger => { - use_tool::kit_of_hamburger(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PanthersSpirit => { - use_tool::panthers_spirit(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfMark3 => { - use_tool::kit_of_mark3(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfMasterSystem=> { - use_tool::kit_of_master_system(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfGenesis => { - use_tool::kit_of_genesis(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfSegaSaturn => { - use_tool::kit_of_sega_saturn(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfDreamcast => { - use_tool::kit_of_dreamcast(entity_gateway, &used_item, inventory).await?; - }, - ToolType::Tablet => { - use_tool::tablet(entity_gateway, &used_item, inventory).await?; - }, - ToolType::DragonScale => { - use_tool::dragon_scale(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeavenStrikerCoat => { - use_tool::heaven_striker_coat(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PioneerParts => { - use_tool::pioneer_parts(entity_gateway, &used_item, inventory).await?; - }, - ToolType::AmitiesMemo => { - use_tool::amities_memo(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfMorolian => { - use_tool::heart_of_morolian(entity_gateway, &used_item, inventory).await?; - }, - ToolType::RappysBeak => { - use_tool::rappys_beak(entity_gateway, &used_item, inventory).await?; - }, - ToolType::YahoosEngine => { - use_tool::yahoos_engine(entity_gateway, &used_item, inventory).await?; - }, - ToolType::DPhotonCore => { - use_tool::d_photon_core(entity_gateway, &used_item, inventory).await?; - }, - ToolType::LibertaKit => { - use_tool::liberta_kit(entity_gateway, &used_item, inventory).await?; - }, - _ => {} - } - } - _ => {} - } - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn player_buys_item<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - shop_item: &'a (dyn ShopItem + Send + Sync), - item_id: ClientItemId, - amount: usize) - -> Result<&'a InventoryItem, anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_detail = shop_item.as_item(); - let inventory_item = match item_detail { - ItemDetail::Tool(tool) => { - if tool.is_stackable() { - let mut item_entities = Vec::new(); - for _ in 0..amount { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - item_entities.push(item_entity); - } - let floor_item = StackedFloorItem { - entity_ids: item_entities.into_iter().map(|i| i.id).collect(), - item_id, - tool, - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_stacked_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - } - else { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - - let floor_item = IndividualFloorItem { - entity_id: item_entity.id, - item_id, - item: ItemDetail::Tool(tool), - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - } - }, - item_detail => { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: item_detail.clone(), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - let floor_item = IndividualFloorItem { - entity_id: item_entity.id, - item_id, - item: item_detail, - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - }, - }; - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(inventory_item) - } - - pub async fn player_sells_item(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<(), anyhow::Error> { - let character_meseta = self.get_character_meseta(&character.id)?.0; - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let sold_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - if let Some(item_sold) = sold_item_handle.item() { - let unit_price = item_sold.get_sell_price()?; { - let total_sale = unit_price * amount as u32; - if character_meseta + total_sale <= 999999 { - match item_sold { - InventoryItem::Individual(i) => { - entity_gateway.add_item_note(&i.entity_id, ItemNote::SoldToShop).await?; - inventory.remove_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - }, - InventoryItem::Stacked(s) => { - match amount.cmp(&s.count()) { - Ordering::Less | Ordering::Equal => { - sold_item_handle.consume(amount)?; - }, - Ordering::Greater => return Err(ItemManagerError::InvalidSale.into()), - }; - }, - } - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - let character_meseta = self.get_character_meseta_mut(&character.id)?; - character_meseta.0 += total_sale; - entity_gateway.set_character_meseta(&character.id, *character_meseta).await?; - } - else { - return Err(ItemManagerError::WalletFull.into()) - } - } - } else { - return Err(ItemManagerError::ItemIdNotInInventory(item_id).into()) - } - Ok(()) - } - - // TODO: check if slot exists before putting units into it - pub async fn player_equips_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - equip_slot: u8) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - inventory.equip(&item_id, equip_slot); - entity_gateway.set_character_equips(&character.id, &inventory.as_equipped_entity()).await?; - Ok(()) - } - - pub async fn player_unequips_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - inventory.unequip(&item_id); - entity_gateway.set_character_equips(&character.id, &inventory.as_equipped_entity()).await?; - Ok(()) - } - - pub async fn player_sorts_items(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_ids: [u32; 30]) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let sorted_inventory_items: Vec = item_ids.iter() - .filter(|&client_item_id| *client_item_id < 0xFFFFFFFF) - .map(|&client_item_id| inventory.get_item_by_id(ClientItemId(client_item_id))) - .filter(|&x| x.is_some()) - .map(|x| x.cloned().unwrap()) - .collect(); - - inventory.set_items(sorted_inventory_items); - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn replace_item_with_tekked(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - tek: weapon::WeaponModifier) - -> Result { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item = inventory.remove_by_id(item_id) - .ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let individual = item - .individual() - .ok_or(ItemManagerError::WrongItemType(item_id))?; - - let entity_id = individual.entity_id; - let mut weapon = *individual - .weapon() - .ok_or(ItemManagerError::WrongItemType(item_id))?; - - weapon.apply_modifier(&tek); - entity_gateway.add_weapon_modifier(&entity_id, tek).await?; - - inventory.add_item(InventoryItem::Individual(IndividualInventoryItem { - entity_id, - item_id, - item: ItemDetail::Weapon(weapon), - })); - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - - Ok(weapon) - } - - pub async fn trade_items(&mut self, - entity_gateway: &mut EG, - room_id: RoomId, - p1: (&AreaClient, &CharacterEntity, &Vec, usize), - p2: (&AreaClient, &CharacterEntity, &Vec, usize)) - -> Result, anyhow::Error> { - let it = ItemTransaction::new(self, (p1, p2, room_id)) - .act(|it, (p1, p2, room_id)| -> Result<_, anyhow::Error> { - let p1_inventory = it.manager.get_character_inventory(p1.1)?; - let p2_inventory = it.manager.get_character_inventory(p2.1)?; - - [(p2_inventory, p1_inventory, p2.2, p1.2), (p1_inventory, p2_inventory, p1.2, p2.2)].iter() - .map(|(src_inventory, dest_inventory, trade_recv, trade_send)| { - let item_slots_lost_to_trade = trade_send - .iter() - .fold(0, |acc, item| { - match item { - TradeItem::Individual(..) => { - acc + 1 - }, - TradeItem::Stacked(item_id, amount) => { - let stacked_inventory_item = try { - src_inventory - .get_item_by_id(*item_id)? - .stacked() - }; - if let Some(Some(item)) = stacked_inventory_item { - if item.count() == *amount { - acc + 1 - } - else { - acc - } - } - else { - acc - } - } - } - }); - trade_recv - .iter() - .try_fold(dest_inventory.count(), |acc, item| { - match item { - TradeItem::Individual(..) => { - if acc >= (30 + item_slots_lost_to_trade) { - Err(TradeError::NoInventorySpace) - } - else { - Ok(acc + 1) - } - }, - TradeItem::Stacked(item_id, amount) => { - let stacked_inventory_item = src_inventory - .get_item_by_id(*item_id) - .ok_or(TradeError::InvalidItemId(*item_id))? - .stacked() - .ok_or(TradeError::InvalidItemId(*item_id))?; - match dest_inventory.space_for_stacked_item(&stacked_inventory_item.tool, *amount) { - SpaceForStack::Yes(YesThereIsSpace::ExistingStack) => { - Ok(acc) - }, - SpaceForStack::Yes(YesThereIsSpace::NewStack) => { - Ok(acc + 1) - }, - SpaceForStack::No(NoThereIsNotSpace::FullStack) => { - Err(TradeError::NoStackSpace) - }, - SpaceForStack::No(NoThereIsNotSpace::FullInventory) => { - if acc >= (30 + item_slots_lost_to_trade) { - Err(TradeError::NoInventorySpace) - } - else { - Ok(acc + 1) - } - }, - } - } - } - }) - }) - .collect::, _>>()?; - - let trade_items = [(p1, p2, p1_inventory), (p2, p1, p2_inventory)] - .map(|(src_client, dest_client, src_inventory)| { - src_client.2.iter() - .map(|item| -> Option<(Option, Box>)> { - match item { - TradeItem::Individual(item_id) => { - let item = src_inventory.get_item_by_id(*item_id)?.individual()?; - let new_item_id = it.manager.room_item_id_counter.borrow_mut().get_mut(room_id)?(); - Some(( - Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: *item_id, - new_item_id, - item_detail: ItemToTradeDetail::Individual(item.item.clone()) - }), - Box::new(TradeIndividualItem { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - current_item_id: *item_id, - new_item_id, - }), - )) - }, - TradeItem::Stacked(item_id, amount) => { - let item = src_inventory.get_item_by_id(*item_id)?.stacked()?; - if item.count() < *amount { - None - } - else { - let new_item_id = it.manager.room_item_id_counter.borrow_mut().get_mut(room_id)?(); - Some(( - Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: *item_id, - new_item_id, - item_detail: ItemToTradeDetail::Stacked(item.tool, *amount) - }), - Box::new(TradeStackedItem { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - //item_ids: item.entity_ids.iter().cloned().take(*amount).collect(), - current_item_id: *item_id, - new_item_id, - amount: *amount, - }), - )) - } - } - } - }) - .chain( - if src_client.3 > 0 { - Box::new(std::iter::once(Some( - (Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: OTHER_MESETA_ITEM_ID, - new_item_id: OTHER_MESETA_ITEM_ID, - item_detail: ItemToTradeDetail::Meseta(src_client.3) - }), - Box::new(TradeMeseta { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - amount: src_client.3, - }) as Box>)))) as Box> - } - else { - Box::new(std::iter::empty()) as Box> - }) - .collect::>>() - }); - - - if let [Some(p1_trades), Some(p2_trades)] = trade_items { - let (p1_item_trades, p1_item_actions): (Vec<_>, Vec<_>) = p1_trades.into_iter().unzip(); - let (p2_item_trades, p2_item_actions): (Vec<_>, Vec<_>) = p2_trades.into_iter().unzip(); - - let item_trades = p1_item_trades.into_iter().flatten().chain(p2_item_trades.into_iter().flatten()); - let item_actions = p1_item_actions.into_iter().chain(p2_item_actions.into_iter()); - - for action in item_actions { - it.action(action); - } - - Ok(item_trades.collect()) - } - else { - Err(ItemManagerError::InvalidTrade.into()) - } - - }); - it.commit(self, entity_gateway) - .await - .map_err(|err| err.into()) - } -} - -#[derive(Debug)] -pub enum ItemToTradeDetail { - Individual(ItemDetail), - Stacked(Tool, usize), - Meseta(usize), -} - -#[derive(Debug)] -pub struct ItemToTrade { - pub add_to: AreaClient, - pub remove_from: AreaClient, - pub current_item_id: ClientItemId, - pub new_item_id: ClientItemId, - pub item_detail: ItemToTradeDetail, -} - - -#[derive(Debug)] -struct RemoveFromLocalFloor { - character_id: CharacterEntityId, - item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for RemoveFromLocalFloor { - async fn commit(&self, item_manager: &mut ItemManager, _entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let local_floor = item_manager.character_floor.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - local_floor.remove_item(&self.item_id); - Ok(()) - } -} - - -#[derive(Debug)] -struct RemoveFromSharedFloor { - room_id: RoomId, - item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for RemoveFromSharedFloor { - async fn commit(&self, item_manager: &mut ItemManager, _entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let shared_floor = item_manager.room_floor.get_mut(&self.room_id).ok_or(ItemManagerError::NoRoom(self.room_id))?; - shared_floor.remove_item(&self.item_id); - Ok(()) - } -} - - -#[derive(Debug)] -struct AddIndividualFloorItemToInventory{ - character: CharacterEntity, - item: IndividualFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddIndividualFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let inventory = item_manager.character_inventory.get_mut(&self.character.id).ok_or(ItemManagerError::NoCharacter(self.character.id))?; - let inv_item = inventory.add_individual_floor_item(&self.item); - - entity_gateway.add_item_note( - &self.item.entity_id, - ItemNote::Pickup { - character_id: self.character.id, - } - ).await?; - - if inv_item.mag().is_some() { - entity_gateway.change_mag_owner(&self.item.entity_id, &self.character).await?; - } - - entity_gateway.set_character_inventory(&self.character.id, &inventory.as_inventory_entity(&self.character.id)).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct AddStackedFloorItemToInventory{ - character_id: CharacterEntityId, - item: StackedFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddStackedFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let inventory = item_manager.character_inventory.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - inventory.add_stacked_floor_item(&self.item); - - entity_gateway.set_character_inventory(&self.character_id, &inventory.as_inventory_entity(&self.character_id)).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct AddMesetaFloorItemToInventory{ - character_id: CharacterEntityId, - item: MesetaFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddMesetaFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let character_meseta = item_manager.character_meseta.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - character_meseta.0 = std::cmp::min(character_meseta.0 + self.item.meseta.0, 999999); - entity_gateway.set_character_meseta(&self.character_id, *character_meseta).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct TradeIndividualItem { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - current_item_id: ClientItemId, - new_item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for TradeIndividualItem { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let src_inventory = item_manager.character_inventory.get_mut(&self.src_character_id).ok_or(ItemManagerError::NoCharacter(self.src_character_id))?; - let inventory_item = src_inventory.take_item_by_id(self.current_item_id).ok_or(ItemManagerError::NoSuchItemId(self.current_item_id))?; - entity_gateway.set_character_inventory(&self.src_character_id, &src_inventory.as_inventory_entity(&self.src_character_id)).await?; - - let dest_inventory = item_manager.character_inventory.get_mut(&self.dest_character_id).ok_or(ItemManagerError::NoCharacter(self.dest_character_id))?; - dest_inventory.add_item_with_new_item_id(inventory_item, self.new_item_id); - entity_gateway.set_character_inventory(&self.dest_character_id, &dest_inventory.as_inventory_entity(&self.dest_character_id)).await?; - - Ok(()) - } -} - -#[derive(Debug)] -struct TradeStackedItem { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - current_item_id: ClientItemId, - new_item_id: ClientItemId, - amount: usize, -} - -#[async_trait::async_trait] -impl ItemAction for TradeStackedItem { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let src_inventory = item_manager.character_inventory.get_mut(&self.src_character_id).ok_or(ItemManagerError::NoCharacter(self.src_character_id))?; - let inventory_item = src_inventory.take_stacked_item_by_id(self.current_item_id, self.amount).ok_or(ItemManagerError::NoSuchItemId(self.current_item_id))?; - entity_gateway.set_character_inventory(&self.src_character_id, &src_inventory.as_inventory_entity(&self.src_character_id)).await?; - - let dest_inventory = item_manager.character_inventory.get_mut(&self.dest_character_id).ok_or(ItemManagerError::NoCharacter(self.dest_character_id))?; - dest_inventory.add_item_with_new_item_id(InventoryItem::Stacked(inventory_item), self.new_item_id); - entity_gateway.set_character_inventory(&self.dest_character_id, &dest_inventory.as_inventory_entity(&self.dest_character_id)).await?; - - Ok(()) - } -} - -#[derive(Debug)] -struct TradeMeseta { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - amount: usize, -} - -#[async_trait::async_trait] -impl ItemAction for TradeMeseta { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - { - let src_meseta = item_manager.get_character_meseta_mut(&self.src_character_id)?; - src_meseta.0 -= self.amount as u32; - entity_gateway.set_character_meseta(&self.src_character_id, *src_meseta).await?; - } - { - let dest_meseta = item_manager.get_character_meseta_mut(&self.dest_character_id)?; - dest_meseta.0 += self.amount as u32; - entity_gateway.set_character_meseta(&self.dest_character_id, *dest_meseta).await?; - } - Ok(()) - } -} diff --git a/src/ship/map/mod.rs b/src/ship/map/mod.rs deleted file mode 100644 index 693fd46..0000000 --- a/src/ship/map/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod area; -pub mod enemy; -pub mod object; -pub mod variant; -pub mod maps; - -// TODO: don't just forward everything to the module scope -pub use area::*; -pub use enemy::*; -pub use object::*; -pub use variant::*; -pub use maps::*; diff --git a/src/ship/mod.rs b/src/ship/mod.rs deleted file mode 100644 index c58edb6..0000000 --- a/src/ship/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[allow(clippy::module_inception)] -pub mod ship; -pub mod location; -pub mod character; -pub mod client; -pub mod room; -pub mod items; -pub mod item_stats; -pub mod map; -pub mod monster; -pub mod drops; -pub mod packet; -pub mod quests; -pub mod shops; -pub mod trade; -pub mod chatcommand; diff --git a/src/ship/packet/handler/mod.rs b/src/ship/packet/handler/mod.rs deleted file mode 100644 index c921d28..0000000 --- a/src/ship/packet/handler/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod auth; -pub mod communication; -pub mod direct_message; -pub mod lobby; -pub mod message; -pub mod room; -pub mod settings; -pub mod quest; -pub mod ship; -pub mod trade; diff --git a/src/ship/packet/mod.rs b/src/ship/packet/mod.rs deleted file mode 100644 index 5b46ce1..0000000 --- a/src/ship/packet/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod builder; -pub mod handler; diff --git a/src/ship/shops/mod.rs b/src/ship/shops/mod.rs deleted file mode 100644 index 573b667..0000000 --- a/src/ship/shops/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -mod weapon; -mod tool; -mod armor; - -use crate::entity::item::ItemDetail; - -pub trait ShopItem { - fn price(&self) -> usize; - fn as_bytes(&self) -> [u8; 12]; - fn as_item(&self) -> ItemDetail; -} - -pub enum ShopType { - Weapon, - Tool, - Armor -} - -pub use weapon::{WeaponShop, WeaponShopItem}; -pub use tool::{ToolShop, ToolShopItem}; -pub use armor::{ArmorShop, ArmorShopItem}; diff --git a/src/ship_server/Cargo.toml b/src/ship_server/Cargo.toml new file mode 100644 index 0000000..604dda8 --- /dev/null +++ b/src/ship_server/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "ship_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +networking = { workspace = true } +trade = { workspace = true } +maps = { workspace = true } +location = { workspace = true } +room = { workspace = true } +shops = { workspace = true } +client = { workspace = true } +pktbuilder = { workspace = true } +items = { workspace = true } +entity = { workspace = true } +drops = { workspace = true } +quests = { workspace = true } +stats = { workspace = true } + +login_server = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +async-trait = { workspace = true } +log = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } +rand = { workspace = true } +serde = { workspace = true } +futures = { workspace = true } diff --git a/src/ship/packet/handler/auth.rs b/src/ship_server/src/auth.rs similarity index 85% rename from src/ship/packet/handler/auth.rs rename to src/ship_server/src/auth.rs index 698de75..2c60f67 100644 --- a/src/ship/packet/handler/auth.rs +++ b/src/ship_server/src/auth.rs @@ -1,11 +1,12 @@ use libpso::packet::login::{Login, LoginResponse, AccountStatus, Session}; use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; -use crate::login::login::get_login_status; -use crate::entity::gateway::EntityGateway; -use crate::ship::items::state::ItemState; -use crate::common::interserver::ShipMessage; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, ShipError}; +use client::{Clients, ClientState}; +use login_server::login::get_login_status; +use entity::gateway::EntityGateway; +use items::state::ItemState; +use networking::interserver::ShipMessage; #[allow(clippy::too_many_arguments)] pub async fn validate_login(id: ClientId, @@ -22,7 +23,7 @@ where { Ok(match get_login_status(entity_gateway, &pkt).await { Ok(user) => { - let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); + let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::default()); response.guildcard = user.id.0; response.team_id = user.team_id.map_or(31, |ti| ti); let characters = entity_gateway.get_characters_by_user(&user).await?; @@ -43,7 +44,7 @@ where vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(ship_name, num_blocks))] }, Err(err) => { - vec![SendShipPacket::LoginResponse(LoginResponse::by_status(err, Session::new()))] + vec![SendShipPacket::LoginResponse(LoginResponse::by_status(err, Session::default()))] } }) } diff --git a/src/ship/chatcommand.rs b/src/ship_server/src/chatcommand.rs similarity index 90% rename from src/ship/chatcommand.rs rename to src/ship_server/src/chatcommand.rs index 97d5054..a2d3ff1 100644 --- a/src/ship/chatcommand.rs +++ b/src/ship_server/src/chatcommand.rs @@ -1,11 +1,11 @@ use libpso::packet::ship::PlayerChat; -use crate::entity::gateway::EntityGateway; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{ShipServerState, SendShipPacket}; -use crate::ship::client::Clients; -use crate::ship::items::state::ItemState; -use crate::entity::item::{BankName, BankIdentifier}; -use crate::ship::packet::builder::message::bank_item_list; +use entity::gateway::EntityGateway; +use networking::serverstate::ClientId; +use crate::{ShipServerState, SendShipPacket}; +use client::Clients; +use items::state::ItemState; +use entity::item::{BankName, BankIdentifier}; +use pktbuilder::message::bank_item_list; async fn default_bank<'a, EG>(id: ClientId, entity_gateway: &mut EG, diff --git a/src/ship/packet/handler/communication.rs b/src/ship_server/src/communication.rs similarity index 89% rename from src/ship/packet/handler/communication.rs rename to src/ship_server/src/communication.rs index c0ac3e5..69f8016 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship_server/src/communication.rs @@ -1,8 +1,8 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, Clients}; -use crate::ship::location::{ClientLocation}; -use crate::entity::gateway::EntityGateway; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, Clients}; +use location::ClientLocation; +use entity::gateway::EntityGateway; use futures::future::join_all; @@ -32,7 +32,7 @@ pub async fn request_infoboard(id: ClientId, .map(|client| async { clients.with(client.client, |client| Box::pin(async move { InfoboardResponse { - name: libpso::utf8_to_utf16_array!(client.character.name, 16), + name: libpso::util::utf8_to_utf16_array(&client.character.name), message: client.character.info_board.as_bytes(), } })).await diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship_server/src/direct_message.rs similarity index 90% rename from src/ship/packet/handler/direct_message.rs rename to src/ship_server/src/direct_message.rs index 3c914e8..74e68e2 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship_server/src/direct_message.rs @@ -1,24 +1,25 @@ use log::warn; +use async_std::sync::Arc; use rand::Rng; use rand::seq::SliceRandom; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::leveltable::LEVEL_TABLE; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemShops}; -use crate::ship::location::ClientLocation; -use crate::ship::drops::ItemDrop; -use crate::ship::room::Rooms; -use crate::ship::items::ClientItemId; -use crate::entity::gateway::EntityGateway; -use crate::entity::item; -use libpso::utf8_to_utf16_array; -use crate::ship::packet::builder; -use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem}; -use crate::ship::items::state::{ItemState, ItemStateError}; -use crate::ship::items::floor::{FloorType, FloorItemDetail}; -use crate::ship::items::actions::TriggerCreateItem; -use crate::ship::items::tasks::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, box_drops_item, take_meseta, apply_modifier}; +use stats::leveltable::LEVEL_TABLE; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, ShipError, Clients}; +use location::ClientLocation; +use drops::ItemDrop; +use room::Rooms; +use items::ClientItemId; +use entity::gateway::EntityGateway; +use entity::item; +use libpso::util::utf8_to_utf16_array; +use pktbuilder as builder; +use shops::{ItemShops, ShopItem, ToolShopItem, ArmorShopItem}; +use items::state::{ItemState, ItemStateError}; +use items::floor::{FloorType, FloorItemDetail}; +use items::actions::TriggerCreateItem; +use items::tasks::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, box_drops_item, take_meseta, apply_modifier}; const BANK_ACTION_DEPOSIT: u8 = 0; const BANK_ACTION_WITHDRAW: u8 = 1; @@ -63,9 +64,9 @@ pub async fn guildcard_send(id: ClientId, client: guildcard_send.client, target: guildcard_send.target, guildcard: client.user.id.0, - name: utf8_to_utf16_array!(client.character.name, 0x18), + name: utf8_to_utf16_array(&client.character.name), team: [0; 0x10], // TODO: teams not yet implemented - desc: utf8_to_utf16_array!(client.character.guildcard.description, 0x58), + desc: utf8_to_utf16_array(&client.character.guildcard.description), one: 1, language: 0, // TODO: add language flag to character section_id: client.character.section_id.into(), @@ -122,7 +123,7 @@ where })).await?; let floor_item = enemy_drops_item(item_state, entity_gateway, character_id, room_entity_id, monster.monster, 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))))); } @@ -149,10 +150,10 @@ where let mut item_state = item_state.clone(); Box::pin(async move { let (item, floor_type) = item_state.get_floor_item(&client.character.id, &ClientItemId(pickup_item.item_id)).await?; - 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.item { - FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, individual_floor_item)?), - FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())?), + FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, individual_floor_item)), + FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())), FloorItemDetail::Meseta(_) => None, }; @@ -234,7 +235,7 @@ where })).await?; let floor_item = box_drops_item(item_state, entity_gateway, character_id, room_entity_id, item_drop).await?; //let floor_item = enemy_drops_item(item_state, &mut entity_gateway, client.character.id, item_drop).await?; - 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))))) } @@ -293,7 +294,7 @@ where } else { let item_added_to_inventory = withdraw_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; - let item_created = builder::message::create_withdrawn_inventory_item2(area_client, &item_added_to_inventory)?; + let item_created = builder::message::create_withdrawn_inventory_item2(area_client, &item_added_to_inventory); vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(item_created)))] } }, @@ -320,45 +321,30 @@ pub async fn shop_request(id: ClientId, client_location: &ClientLocation, clients: &Clients, rooms: &Rooms, - shops: &ItemShops) + shops: &Arc>) -> Result, anyhow::Error> { - //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let room_id = client_location.get_room(id).await?; - /* - let room = rooms.get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_ref() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - */ let difficulty = rooms.with(room_id, |room| Box::pin(async move { room.mode.difficulty() })).await?; let shop_list = clients.with_mut(id, |client| { - let mut shops = shops.clone(); + let shops = shops.clone(); Box::pin(async move { let level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) as usize; match shop_request.shop_type { SHOP_OPTION_WEAPON => { - client.weapon_shop = shops.weapon_shop.get_mut(&(difficulty, client.character.section_id)) - .ok_or(ShipError::ShopError)? - .lock() + client.weapon_shop = shops.generate_weapon_list(difficulty, client.character.section_id, level) .await - .generate_weapon_list(level); + .ok_or(ShipError::ShopError)?; Ok(builder::message::shop_list(shop_request.shop_type, &client.weapon_shop)) }, SHOP_OPTION_TOOL => { - client.tool_shop = shops.tool_shop - .lock() - .await - .generate_tool_list(level); + client.tool_shop = shops.generate_tool_list(level).await; Ok(builder::message::shop_list(shop_request.shop_type, &client.tool_shop)) }, SHOP_OPTION_ARMOR => { - client.armor_shop = shops.armor_shop - .lock() - .await - .generate_armor_list(level); + client.armor_shop = shops.generate_armor_list(level).await; Ok(builder::message::shop_list(shop_request.shop_type, &client.armor_shop)) }, _ => { @@ -440,7 +426,7 @@ where _ => {} } } - Ok::<_, anyhow::Error>(builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)?) + Ok::<_, anyhow::Error>(builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)) })}).await??; let other_clients_in_area = client_location.get_client_neighbors(id).await?; @@ -503,7 +489,7 @@ where }); take_meseta(&mut item_state, &mut entity_gateway, &client.character.id, item::Meseta(100)).await?; - Ok::<_, anyhow::Error>(builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)?) + Ok::<_, anyhow::Error>(builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)) })}).await??; @@ -539,7 +525,7 @@ where }; let weapon = apply_modifier(&mut item_state, &mut entity_gateway, &client.character, item_id, item::ItemModifier::WeaponModifier(modifier)).await?; - let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon)?; + let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon); Ok(neighbors.into_iter() .map(move |c| { diff --git a/src/ship/ship.rs b/src/ship_server/src/lib.rs similarity index 71% rename from src/ship/ship.rs rename to src/ship_server/src/lib.rs index cd40965..f6d0ed1 100644 --- a/src/ship/ship.rs +++ b/src/ship_server/src/lib.rs @@ -1,9 +1,20 @@ -#![allow(dead_code, unused_must_use)] +#![allow(clippy::type_complexity)] +mod auth; +mod communication; +mod direct_message; +mod lobby; +mod message; +mod room; +mod settings; +mod quest; +mod ship; +pub mod trade; +mod chatcommand; + use std::net::Ipv4Addr; -use std::collections::HashMap; use async_std::channel; -use async_std::sync::{Arc, Mutex, RwLock}; +use async_std::sync::{Arc, RwLock}; use rand::Rng; use thiserror::Error; @@ -14,80 +25,29 @@ use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; use libpso::packet::ship::{BLOCK_MENU_ID, ROOM_MENU_ID}; -use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; -use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; -use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage}; -use crate::login::character::SHIP_MENU_ID; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::SectionID; -use crate::entity::room::RoomNote; -use crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; -use crate::ship::drops::DropTable; -use crate::ship::items; -use crate::ship::room; -use crate::ship::map::{Maps, MapsError, MapAreaError, generate_free_roam_maps}; -use crate::ship::packet::handler; -use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop}; -use crate::ship::trade::TradeState; -use crate::ship::chatcommand; - -// TODO: remove once stuff settles down -pub use crate::ship::client::*; +use networking::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; +use networking::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; +use networking::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage}; +use pktbuilder::ship::SHIP_MENU_ID; +use entity::gateway::{EntityGateway, GatewayError}; +use entity::character::SectionID; +use entity::room::RoomNote; +use location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; +use drops::{DropTable, StandardDropTable}; +use ::room::{Rooms, RoomCreationError}; +use maps::room::{RoomMode, Episode, Difficulty}; +use quests::{load_standard_quests, load_government_quests}; +use quests::{QuestList, QuestLoadError}; +use maps::Holiday; +use maps::area::MapAreaError; +use maps::maps::{Maps, MapsError, generate_free_roam_maps}; +use shops::{ItemShops, StandardItemShops}; +use ::trade::{TradeState, TradeStateError}; +use pktbuilder::quest::{QUEST_CATEGORY_MENU_ID, QUEST_SELECT_MENU_ID}; + +pub use client::{Clients, ClientState}; pub const SHIP_PORT: u16 = 23423; -pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2; -pub const QUEST_SELECT_MENU_ID: u32 = 0xA3; - -#[derive(Clone, Copy)] -pub enum ShipEvent { - None, - Christmas, - Valentines, - Easter, - Halloween, - Sonic, - NewYear, - Summer, - White, - Wedding, - Fall, - Spring, - Summer2, - Spring2, -} - -impl From for u32 { - fn from(other: ShipEvent) -> u32 { - u16::from(other) as u32 - } -} - -impl From for u16 { - fn from(other: ShipEvent) -> u16 { - u8::from(other) as u16 - } -} - -impl From for u8 { - fn from(other: ShipEvent) -> u8 { - match other { - ShipEvent::None => 0, - ShipEvent::Christmas => 1, - ShipEvent::Valentines => 3, - ShipEvent::Easter => 4, - ShipEvent::Halloween => 5, - ShipEvent::Sonic => 6, - ShipEvent::NewYear => 7, - ShipEvent::Summer => 8, - ShipEvent::White => 9, - ShipEvent::Wedding => 10, - ShipEvent::Fall => 11, - ShipEvent::Spring => 12, - ShipEvent::Summer2 => 13, - ShipEvent::Spring2 => 14, - } - } -} #[derive(Error, Debug)] @@ -139,7 +99,7 @@ pub enum ShipError { #[error("gateway error {0}")] GatewayError(#[from] GatewayError), #[error("unknown monster {0}")] - UnknownMonster(crate::ship::monster::MonsterType), + UnknownMonster(maps::monster::MonsterType), #[error("invalid ship {0}")] InvalidShip(usize), #[error("invalid block {0}")] @@ -147,13 +107,13 @@ pub enum ShipError { #[error("invalid item {0}")] InvalidItem(items::ClientItemId), #[error("trade error {0}")] - TradeError(#[from] crate::ship::packet::handler::trade::TradeError), + TradeError(#[from] trade::TradeError), #[error("trade state error {0}")] - TradeStateError(#[from] crate::ship::trade::TradeStateError), + TradeStateError(#[from] TradeStateError), #[error("message error {0}")] - MessageError(#[from] crate::ship::packet::handler::direct_message::MessageError), + MessageError(#[from] crate::direct_message::MessageError), #[error("room creation error {0}")] - RoomCreationError(#[from] room::RoomCreationError), + RoomCreationError(#[from] RoomCreationError), #[error("channel send error {0}")] SendError(#[from] async_std::channel::SendError), } @@ -167,6 +127,7 @@ impl> From for ShipError { */ + #[derive(Debug)] pub enum RecvShipPacket { Login(Login), @@ -293,6 +254,7 @@ pub enum SendShipPacket { TradeSuccessful(TradeSuccessful), LobbyEvent(LobbyEvent), LargeDialog(LargeDialog), + RightText(RightText), } impl SendServerPacket for SendShipPacket { @@ -337,34 +299,7 @@ impl SendServerPacket for SendShipPacket { SendShipPacket::TradeSuccessful(pkt) => pkt.as_bytes(), SendShipPacket::LobbyEvent(pkt) => pkt.as_bytes(), SendShipPacket::LargeDialog(pkt) => pkt.as_bytes(), - } - } -} - -#[derive(Clone)] -pub struct ItemShops { - pub weapon_shop: HashMap<(room::Difficulty, SectionID), Arc>>>, - pub tool_shop: Arc>>, - pub armor_shop: Arc>>, -} - -impl Default for ItemShops { - fn default() -> ItemShops { - 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, - SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill]; - - let mut weapon_shop = HashMap::new(); - for d in difficulty.iter() { - for id in section_id.iter() { - weapon_shop.insert((*d, *id), Arc::new(Mutex::new(WeaponShop::new(*d, *id)))); - } - } - - ItemShops { - weapon_shop, - tool_shop: Arc::new(Mutex::new(ToolShop::default())), - armor_shop: Arc::new(Mutex::new(ArmorShop::default())), + SendShipPacket::RightText(pkt) => pkt.as_bytes(), } } } @@ -376,9 +311,12 @@ pub struct ShipServerStateBuilder { ip: Option, port: Option, auth_token: Option, - event: Option, - map_builder: Option Maps + Send + Sync>>, - drop_table_builder: Option DropTable + Send + Sync>>, + event: Option, + shops: Option>, + map_builder: Option Maps + Send + Sync>>, + drop_table_builder: Option Box + Send + Sync>>, + standard_quest_builder: Option Result + Send + Sync>>, + government_quest_builder: Option Result + Send + Sync>>, num_blocks: usize, } @@ -391,8 +329,11 @@ impl Default for ShipServerStateBuilder port: None, auth_token: None, event: None, + shops: None, map_builder: None, drop_table_builder: None, + standard_quest_builder: None, + government_quest_builder: None, num_blocks: 2, } } @@ -430,23 +371,41 @@ impl ShipServerStateBuilder { } #[must_use] - pub fn event(mut self, event: ShipEvent) -> ShipServerStateBuilder { + pub fn event(mut self, event: Holiday) -> ShipServerStateBuilder { self.event = Some(event); self } #[must_use] - pub fn map_builder(mut self, map_builder: Box Maps + Send + Sync>) -> ShipServerStateBuilder { + pub fn map_builder(mut self, map_builder: Box Maps + Send + Sync>) -> ShipServerStateBuilder { self.map_builder = Some(map_builder); self } #[must_use] - pub fn drop_table_builder(mut self, drop_table_builder: Box DropTable + Send + Sync>) -> ShipServerStateBuilder { + pub fn drop_table_builder(mut self, drop_table_builder: Box Box + Send + Sync>) -> ShipServerStateBuilder { self.drop_table_builder = Some(drop_table_builder); self } + #[must_use] + pub fn standard_quest_builder(mut self, standard_quest_builder: Box Result + Send + Sync>) -> ShipServerStateBuilder { + self.standard_quest_builder = Some(standard_quest_builder); + self + } + + #[must_use] + pub fn government_quest_builder(mut self, government_quest_builder: Box Result + Send + Sync>) -> ShipServerStateBuilder { + self.government_quest_builder = Some(government_quest_builder); + self + } + + #[must_use] + pub fn item_shops(mut self, item_shops: impl ItemShops + Send + Sync + 'static) -> ShipServerStateBuilder { + self.shops = Some(Box::new(item_shops)); + self + } + #[must_use] pub fn blocks(mut self, num_blocks: usize) -> ShipServerStateBuilder { self.num_blocks = num_blocks; @@ -462,11 +421,13 @@ impl ShipServerStateBuilder { item_state: items::state::ItemState::default(), ip: self.ip.unwrap_or_else(|| Ipv4Addr::new(127,0,0,1)), port: self.port.unwrap_or(SHIP_PORT), - shops: ItemShops::default(), + shops: Arc::new(self.shops.unwrap_or_else(|| Box::::default())), blocks: Blocks(blocks), - event: self.event.unwrap_or(ShipEvent::None), - map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(generate_free_roam_maps))), - drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(DropTable::new))), + event: self.event.unwrap_or(Holiday::None), + map_builder: Arc::new(self.map_builder.unwrap_or_else(|| Box::new(generate_free_roam_maps))), + drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or_else(|| Box::new(StandardDropTable::new))), + standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or_else(|| Box::new(load_standard_quests))), + government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or_else(|| Box::new(load_government_quests))), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), ship_list: Arc::new(RwLock::new(Vec::new())), @@ -480,7 +441,7 @@ impl ShipServerStateBuilder { #[derive(Clone, Default)] pub struct Block { client_location: ClientLocation, - pub rooms: room::Rooms, + pub rooms: Rooms, } #[derive(Clone)] @@ -503,9 +464,9 @@ pub struct ShipServerState { pub clients: Clients, name: String, pub(crate) item_state: items::state::ItemState, - shops: ItemShops, + shops: Arc>, pub blocks: Blocks, - event: ShipEvent, + event: Holiday, ip: Ipv4Addr, port: u16, @@ -514,8 +475,10 @@ pub struct ShipServerState { ship_list: Arc>>, shipgate_sender: Option>, trades: TradeState, - map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, + map_builder: Arc Maps + Send + Sync>>, + drop_table_builder: Arc Box + Send + Sync>>, + standard_quest_builder: Arc Result + Send + Sync>>, + government_quest_builder: Arc Result + Send + Sync>>, } impl ShipServerState { @@ -527,58 +490,58 @@ impl ShipServerState { Ok(match msg.msg { GameMessage::RequestExp(request_exp) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms).await? + message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms).await? }, GameMessage::PlayerDropItem(player_drop_item) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? + message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::DropCoordinates(drop_coordinates) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &self.clients, &block.rooms).await? + message::drop_coordinates(id, drop_coordinates, &block.client_location, &self.clients, &block.rooms).await? }, GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) | GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) | GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) | GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::update_player_position(id, msg, &self.clients, &block.client_location, &block.rooms).await? + message::update_player_position(id, msg, &self.clients, &block.client_location, &block.rooms).await? }, GameMessage::ChargeAttack(charge_attack) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUseItem(player_use_item) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerFeedMag(player_feed_mag) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerEquipItem(player_equip_item) => { - handler::message::player_equips_item(id, player_equip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + message::player_equips_item(id, player_equip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUnequipItem(player_unequip_item) => { - handler::message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::SortItems(sort_items) => { - handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerSoldItem(player_sold_item) => { - handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::FloorItemLimitItemDeletion(floor_item_limit_delete) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::floor_item_limit_deletion(id, floor_item_limit_delete, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? + message::floor_item_limit_deletion(id, floor_item_limit_delete, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, _ => { let cmsg = msg.clone(); @@ -597,37 +560,37 @@ impl ShipServerState { let block = self.blocks.get_from_client(id, &self.clients).await?; Ok(match msg.msg { GameMessage::GuildcardSend(guildcard_send) => { - handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await? + direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await? }, GameMessage::RequestItem(request_item) => { - handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? + direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::PickupItem(pickup_item) => { - handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::BoxDropRequest(box_drop_request) => { - handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? + direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::BankRequest(_bank_request) => { - handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_state).await? + direct_message::send_bank_list(id, &self.clients, &mut self.item_state).await? }, GameMessage::BankInteraction(bank_interaction) => { - handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::ShopRequest(shop_request) => { - handler::direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &self.shops).await? + direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &self.shops).await? }, GameMessage::BuyItem(buy_item) => { - handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::TekRequest(tek_request) => { - handler::direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::TekAccept(tek_accept) => { - handler::direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::TradeRequest(trade_request) => { - handler::trade::trade_request(id, trade_request, target, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? + trade::trade_request(id, trade_request, target, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, _ => { let cmsg = msg.clone(); @@ -673,7 +636,7 @@ impl ServerState for ShipServerState { Ok(match pkt { RecvShipPacket::Login(login) => { - handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) + auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) .await? .into_iter() .map(move |pkt| (id, pkt)) @@ -682,7 +645,7 @@ impl ServerState for ShipServerState { RecvShipPacket::QuestDetailRequest(questdetailrequest) => { let block = self.blocks.get_from_client(id, &self.clients).await?; match questdetailrequest.menu { - QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &block.rooms).await?, + QUEST_SELECT_MENU_ID => quest::quest_detail(id, questdetailrequest, &block.client_location, &block.rooms).await?, _ => unreachable!(), } }, @@ -690,27 +653,27 @@ impl ServerState for ShipServerState { let block = self.blocks.get_from_client(id, &self.clients).await?; match menuselect.menu { SHIP_MENU_ID => { - let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().flatten(); - let select_ship = handler::ship::selected_ship(id, menuselect, &self.ship_list).await?; + let leave_lobby = lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().flatten(); + let select_ship = ship::selected_ship(id, menuselect, &self.ship_list).await?; leave_lobby.chain(select_ship).collect() } BLOCK_MENU_ID => { - let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().flatten(); - let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); + let leave_lobby = lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().flatten(); + let select_block = lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); leave_lobby.chain(select_block).collect() } - ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await?, - QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &block.rooms).await?, + ROOM_MENU_ID => room::join_room(id, menuselect, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await?, + QUEST_CATEGORY_MENU_ID => quest::select_quest_category(id, menuselect, &block.client_location, &block.rooms).await?, _ => unreachable!(), } }, RecvShipPacket::QuestMenuSelect(questmenuselect) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::player_chose_quest(id, questmenuselect, &self.clients, &block.client_location, &block.rooms, self.event).await? + quest::player_chose_quest(id, questmenuselect, &self.clients, &block.client_location, &block.rooms, self.event).await? }, RecvShipPacket::MenuDetail(menudetail) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients).await? + lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients).await? }, RecvShipPacket::RoomPasswordReq(room_password_req) => { let block = self.blocks.get_from_client(id, &self.clients).await?; @@ -724,7 +687,7 @@ impl ServerState for ShipServerState { menu: room_password_req.menu, item: room_password_req.item, }; - handler::room::join_room(id, menuselect, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await? + room::join_room(id, menuselect, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await? } else { vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))] @@ -732,7 +695,7 @@ impl ServerState for ShipServerState { }, RecvShipPacket::CharData(chardata) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state, self.event).await? + lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state, self.event).await? }, RecvShipPacket::Message(msg) => { self.message(id, msg).await? @@ -750,39 +713,40 @@ impl ServerState for ShipServerState { }, None => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::communication::player_chat(id, msg, &block.client_location, &self.clients).await? + communication::player_chat(id, msg, &block.client_location, &self.clients).await? } } }, RecvShipPacket::CreateRoom(create_room) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::create_room(id, create_room, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, - &block.rooms, self.map_builder.clone(), self.drop_table_builder.clone(), self.event).await? + room::create_room(id, create_room, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, + &block.rooms, self.map_builder.clone(), self.drop_table_builder.clone(), + self.standard_quest_builder.clone(), self.government_quest_builder.clone(), self.event).await? }, RecvShipPacket::RoomNameRequest(_req) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::room_name_request(id, &block.client_location, &block.rooms).await? + room::room_name_request(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::UpdateTechMenu(pkt) => { - handler::settings::update_tech_menu(id, pkt, &self.clients, &mut self.entity_gateway).await? + settings::update_tech_menu(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::UpdateConfig(pkt) => { - handler::settings::update_config(id, pkt, &self.clients, &mut self.entity_gateway).await? + settings::update_config(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::ViewInfoboardRequest(_pkt) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::communication::request_infoboard(id, &block.client_location, &self.clients).await? + communication::request_infoboard(id, &block.client_location, &self.clients).await? }, RecvShipPacket::WriteInfoboard(pkt) => { - handler::communication::write_infoboard(id, pkt, &self.clients, &mut self.entity_gateway).await? + communication::write_infoboard(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::RoomListRequest(_req) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::request_room_list(id, &block.client_location, &block.rooms).await + room::request_room_list(id, &block.client_location, &block.rooms).await }, RecvShipPacket::Like62ButCooler(cool62) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::cool_62(id, cool62, &block.client_location).await? + room::cool_62(id, cool62, &block.client_location).await? }, RecvShipPacket::ClientCharacterData(_) => { // TOOD: validate this in some way? @@ -790,57 +754,57 @@ impl ServerState for ShipServerState { }, RecvShipPacket::DoneBursting(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::done_bursting(id, &block.client_location, &block.rooms).await? + room::done_bursting(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::DoneBursting2(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::done_bursting(id, &block.client_location, &block.rooms).await? + room::done_bursting(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::LobbySelect(pkt) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, &mut self.entity_gateway, self.event).await? + lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, &mut self.entity_gateway, self.event).await? }, RecvShipPacket::RequestQuestList(rql) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::send_quest_category_list(id, rql, &block.client_location, &block.rooms).await? + quest::send_quest_category_list(id, rql, &block.client_location, &block.rooms).await? }, RecvShipPacket::QuestFileRequest(quest_file_request) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await? + quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::QuestChunkAck(quest_chunk_ack) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &block.rooms).await? + quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &block.rooms).await? }, RecvShipPacket::DoneLoadingQuest(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::done_loading_quest(id, &self.clients, &block.client_location).await? + quest::done_loading_quest(id, &self.clients, &block.client_location).await? }, RecvShipPacket::FullCharacterData(_full_character_data) => { Vec::new() }, RecvShipPacket::SaveOptions(save_options) => { - handler::settings::save_options(id, save_options, &self.clients, &mut self.entity_gateway).await? + settings::save_options(id, save_options, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::RequestShipList(_) => { - handler::ship::ship_list(id, &self.ship_list).await + ship::ship_list(id, &self.ship_list).await }, RecvShipPacket::RequestShipBlockList(_) => { - handler::ship::block_list(id, &self.name, self.blocks.0.len()) + ship::block_list(id, &self.name, self.blocks.0.len()) }, RecvShipPacket::ItemsToTrade(items_to_trade) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::trade::items_to_trade(id, items_to_trade, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? + trade::items_to_trade(id, items_to_trade, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::TradeConfirmed(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? + trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::KeyboardConfig(keyboard_config) => { - handler::settings::keyboard_config(id, keyboard_config, &self.clients, &mut self.entity_gateway).await? + settings::keyboard_config(id, keyboard_config, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::GamepadConfig(gamepad_config) => { - handler::settings::gamepad_config(id, gamepad_config, &self.clients, &mut self.entity_gateway).await? + settings::gamepad_config(id, gamepad_config, &self.clients, &mut self.entity_gateway).await? }, }) } @@ -861,7 +825,7 @@ impl ServerState for ShipServerState { entity_gateway.add_room_note(room.room_id, RoomNote::PlayerJoin { character_id, }).await - })}).await; + })}).await??; if neighbors.is_empty() { block.rooms.remove(room).await; } @@ -876,9 +840,9 @@ impl ServerState for ShipServerState { if let Some(mut client) = self.clients.remove(&id).await { client.user.at_ship = false; - self.entity_gateway.save_user(&client.user).await; + self.entity_gateway.save_user(&client.user).await?; if let Some(shipgate_sender) = self.shipgate_sender.as_ref() { - shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await; + shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await?; } self.item_state.remove_character_from_room(&client.character).await } diff --git a/src/ship/packet/handler/lobby.rs b/src/ship_server/src/lobby.rs similarity index 86% rename from src/ship/packet/handler/lobby.rs rename to src/ship_server/src/lobby.rs index d5506c4..d29d8d4 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship_server/src/lobby.rs @@ -1,15 +1,16 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; -use crate::ship::room::Rooms; -use crate::ship::character::{FullCharacterBytesBuilder}; -use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; -use crate::ship::packet; -use crate::ship::items::state::ItemState; -use crate::entity::gateway::EntityGateway; -use crate::entity::room::RoomNote; -use crate::ship::map::MapArea; +use networking::serverstate::ClientId; +use stats::leveltable::LEVEL_TABLE; +use crate::{SendShipPacket, ShipError}; +use maps::Holiday; +use client::Clients; +use room::Rooms; +use pktbuilder::character::FullCharacterBytesBuilder; +use location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; +use items::state::ItemState; +use entity::gateway::EntityGateway; +use entity::room::RoomNote; +use maps::area::MapArea; use futures::future::join_all; // this function needs a better home @@ -47,7 +48,7 @@ pub async fn block_selected(id: ClientId, character: fc, }))), (id, SendShipPacket::CharDataRequest(CharDataRequest {})), - (id, SendShipPacket::LobbyList(LobbyList::new())), + (id, SendShipPacket::LobbyList(LobbyList::default())), ]) })}).await? } @@ -57,11 +58,11 @@ pub async fn send_player_to_lobby(id: ClientId, client_location: &mut ClientLocation, clients: &Clients, item_state: &ItemState, - event: ShipEvent) + event: Holiday) -> Result, anyhow::Error> { let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).await.map_err(|_| ShipError::TooManyClients)?; - let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; - let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; + let join_lobby = pktbuilder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; + let addto = pktbuilder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; let neighbors = client_location.get_client_neighbors(id).await.unwrap(); Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] .into_iter() @@ -77,7 +78,7 @@ pub async fn change_lobby(id: ClientId, item_state: &mut ItemState, rooms: &Rooms, entity_gateway: &mut EG, - event: ShipEvent) + event: Holiday) -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, @@ -111,7 +112,7 @@ where })}).await??; }, } - let leave_lobby = packet::builder::lobby::remove_from_lobby(id, client_location).await?; + let leave_lobby = pktbuilder::lobby::remove_from_lobby(id, client_location).await?; let old_neighbors = client_location.get_client_neighbors(id).await.unwrap(); let mut lobby = LobbyId(requested_lobby as usize); if client_location.add_client_to_lobby(id, lobby).await.is_err() { @@ -131,8 +132,8 @@ where Box::pin(async move { item_state.load_character(&mut entity_gateway, &client.character).await })}).await??; - let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; - let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; + let join_lobby = pktbuilder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; + let addto = pktbuilder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; let neighbors = client_location.get_client_neighbors(id).await?; Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] .into_iter() diff --git a/src/ship/packet/handler/message.rs b/src/ship_server/src/message.rs similarity index 95% rename from src/ship/packet/handler/message.rs rename to src/ship_server/src/message.rs index f380d14..31a6541 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship_server/src/message.rs @@ -1,16 +1,17 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::entity::gateway::EntityGateway; -use crate::entity::item::Meseta; -use crate::common::serverstate::ClientId; -use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemDropLocation}; -use crate::ship::room::Rooms; -use crate::ship::location::{ClientLocation, ClientLocationError}; -use crate::ship::items::ClientItemId; -use crate::ship::packet::builder; -use crate::ship::items::state::ItemState; -use crate::ship::items::tasks::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item, take_meseta, floor_item_limit_reached}; +use entity::gateway::EntityGateway; +use entity::item::Meseta; +use networking::serverstate::ClientId; +use stats::leveltable::LEVEL_TABLE; +use crate::{SendShipPacket, ShipError}; +use client::{Clients, ItemDropLocation}; +use ::room::Rooms; +use location::{ClientLocation, ClientLocationError}; +use items::ClientItemId; +use pktbuilder as builder; +use items::state::ItemState; +use items::tasks::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item, take_meseta, floor_item_limit_reached}; pub async fn request_exp(id: ClientId, request_exp: RequestExp, @@ -162,7 +163,7 @@ where drop_meseta(&mut item_state, &mut entity_gateway, &client.character, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await })}).await??; - let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?; + let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta); let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount); let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; @@ -198,7 +199,7 @@ where no_longer_has_item.amount) .await })}).await??; - let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item)?; + let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item); let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(clients_in_area.into_iter() @@ -348,6 +349,15 @@ where })}).await?? .into_iter() .flat_map(move |pkt| { + let pkt = match pkt { + items::actions::CreateItem::Individual(area_client, item_id, item_detail) => { + builder::message::create_individual_item(area_client, item_id, &item_detail) + }, + items::actions::CreateItem::Stacked(area_client, item_id, tool, amount) => { + builder::message::create_stacked_item(area_client, item_id, &tool, amount) + } + }; + let pkt = SendShipPacket::Message(Message::new(GameMessage::CreateItem(pkt))); let player_use_tool = player_use_tool.clone(); neighbors.clone().map(move |client| { vec![(client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUseItem(player_use_tool.clone())))), (client.client, pkt.clone())] diff --git a/src/ship/packet/handler/quest.rs b/src/ship_server/src/quest.rs similarity index 96% rename from src/ship/packet/handler/quest.rs rename to src/ship_server/src/quest.rs index 1c8c31e..b40c718 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship_server/src/quest.rs @@ -1,12 +1,14 @@ use std::io::{Cursor, Read, Seek, SeekFrom}; use futures::stream::{FuturesOrdered, StreamExt}; use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; -use crate::ship::room::Rooms; -use crate::ship::map::enemy::RareMonsterAppearTable; -use crate::ship::location::{ClientLocation}; -use crate::ship::packet::builder::quest; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, ShipError}; +use client::Clients; +use maps::Holiday; +use room::Rooms; +use maps::enemy::RareMonsterAppearTable; +use location::{ClientLocation}; +use pktbuilder::quest; use libpso::util::array_to_utf8; enum QuestFileType { @@ -97,7 +99,7 @@ pub async fn player_chose_quest(id: ClientId, clients: &Clients, client_location: &ClientLocation, rooms: &Rooms, - event: ShipEvent) + event: Holiday) -> Result, anyhow::Error> { let room_id = client_location.get_room(id).await?; diff --git a/src/ship/packet/handler/room.rs b/src/ship_server/src/room.rs similarity index 88% rename from src/ship/packet/handler/room.rs rename to src/ship_server/src/room.rs index 9198c63..73bdb39 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship_server/src/room.rs @@ -1,22 +1,26 @@ -use std::convert::{TryFrom, Into}; +use std::convert::Into; use futures::stream::StreamExt; use async_std::sync::Arc; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::serverstate::ClientId; -use crate::common::leveltable::LEVEL_TABLE; -use crate::entity::gateway::EntityGateway; -use crate::entity::character::SectionID; -use crate::entity::room::{NewRoomEntity, RoomEntityMode, RoomNote}; -use crate::ship::drops::DropTable; -use crate::ship::ship::{SendShipPacket, Clients, ShipEvent}; -use crate::ship::room::{Rooms, Episode, Difficulty, RoomState, RoomMode}; -use crate::ship::map::Maps; -use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; -use crate::ship::packet::builder; -use crate::ship::items::state::ItemState; +use networking::serverstate::ClientId; +use stats::leveltable::LEVEL_TABLE; +use entity::gateway::EntityGateway; +use entity::character::SectionID; +use entity::room::{NewRoomEntity, RoomEntityMode, RoomNote}; +use drops::DropTable; +use crate::SendShipPacket; +use client::Clients; +use room::{Rooms, RoomState, RoomCreationError}; +use maps::Holiday; +use maps::room::{Episode, Difficulty, RoomMode}; +use maps::maps::Maps; +use location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; +use pktbuilder as builder; +use items::state::ItemState; +use quests::{QuestList, QuestLoadError}; #[allow(clippy::too_many_arguments)] pub async fn create_room(id: ClientId, @@ -26,9 +30,11 @@ pub async fn create_room(id: ClientId, clients: &Clients, item_state: &mut ItemState, rooms: &Rooms, - map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, - event: ShipEvent) + map_builder: Arc Maps + Send + Sync>>, + drop_table_builder: Arc Box + Send + Sync>>, + standard_quest_builder: Arc Result + Send + Sync>>, + government_quest_builder: Arc Result + Send + Sync>>, + event: Holiday) -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, @@ -36,7 +42,8 @@ where let level = clients.with(id, |client| Box::pin(async move { LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) })).await?; - let difficulty = Difficulty::try_from(create_room.difficulty)?; + let difficulty = create_room.difficulty.try_into() + .map_err(|()| RoomCreationError::InvalidDifficulty(create_room.difficulty))?; match difficulty { Difficulty::Ultimate if level < 80 => { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto create Ultimate rooms.".into())))]) @@ -64,8 +71,9 @@ where (0, 0, 1) => RoomEntityMode::Single, _ => RoomEntityMode::Multi, }; - let episode = create_room.episode.try_into()?; - let difficulty = create_room.difficulty.try_into()?; + let episode = create_room.episode.try_into() + .map_err(|()| RoomCreationError::InvalidEpisode(create_room.episode))?; + //let difficulty = create_room.difficulty.try_into()?; let room = clients.with(id, |client| { let mut item_state = item_state.clone(); @@ -86,7 +94,7 @@ where let mut room = RoomState::new(room_entity.id, mode, episode, difficulty, client.character.section_id, name, create_room.password, event, - map_builder, drop_table_builder)?; + map_builder, drop_table_builder, standard_quest_builder, government_quest_builder)?; room.bursting = true; Ok::<_, anyhow::Error>(room) })}).await??; @@ -132,7 +140,7 @@ pub async fn join_room(id: ClientId, clients: &Clients, item_state: &mut ItemState, rooms: &Rooms, - event: ShipEvent) + event: Holiday) -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, @@ -252,7 +260,7 @@ pub async fn request_room_list(id: ClientId, .filter_map(|(i, r)| async move { r.as_ref().map(|room| { let difficulty = room.get_difficulty_for_room_list(); - let name = libpso::utf8_to_utf16_array!(room.name, 16); + let name = libpso::util::utf8_to_utf16_array(&room.name); let episode = room.get_episode_for_room_list(); let flags = room.get_flags_for_room_list(); async move { @@ -272,7 +280,7 @@ pub async fn request_room_list(id: ClientId, item_id: ROOM_MENU_ID, difficulty: 0x00, players: 0x00, - name: libpso::utf8_to_utf16_array!("Room list menu", 16), + name: libpso::util::utf8_to_utf16_array("Room list menu"), episode: 0, flags: 0, }; diff --git a/src/ship/packet/handler/settings.rs b/src/ship_server/src/settings.rs similarity index 96% rename from src/ship/packet/handler/settings.rs rename to src/ship_server/src/settings.rs index de7bfaa..b21491b 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship_server/src/settings.rs @@ -1,7 +1,7 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, Clients}; -use crate::entity::gateway::EntityGateway; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, Clients}; +use entity::gateway::EntityGateway; pub async fn update_config(id: ClientId, update_config: UpdateConfig, diff --git a/src/ship/packet/handler/ship.rs b/src/ship_server/src/ship.rs similarity index 87% rename from src/ship/packet/handler/ship.rs rename to src/ship_server/src/ship.rs index a63ebdf..a006004 100644 --- a/src/ship/packet/handler/ship.rs +++ b/src/ship_server/src/ship.rs @@ -1,10 +1,10 @@ use async_std::sync::{Arc, RwLock}; use libpso::packet::ship::*; use libpso::packet::login::RedirectClient; -use crate::common::serverstate::ClientId; -use crate::common::interserver::Ship; -use crate::ship::ship::{SendShipPacket, ShipError}; -use crate::ship::packet::builder; +use networking::serverstate::ClientId; +use networking::interserver::Ship; +use crate::{SendShipPacket, ShipError}; +use pktbuilder as builder; pub async fn ship_list(id: ClientId, ship_list: &Arc>>) -> Vec<(ClientId, SendShipPacket)> { let ship_list = ship_list diff --git a/src/ship/packet/handler/trade.rs b/src/ship_server/src/trade.rs similarity index 97% rename from src/ship/packet/handler/trade.rs rename to src/ship_server/src/trade.rs index c1cb2d0..b57b218 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship_server/src/trade.rs @@ -1,19 +1,19 @@ use std::convert::TryInto; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients}; -use crate::ship::location::{ClientLocation}; -use crate::ship::items::ClientItemId; -use crate::ship::items::state::{ItemState, ItemStateError}; -use crate::ship::items::inventory::InventoryItemDetail; -use crate::ship::trade::{TradeItem, TradeState, TradeStatus}; -use crate::entity::gateway::EntityGateway; -use crate::ship::packet::builder; -use crate::ship::items::tasks::trade_items; -use crate::ship::location::{AreaClient, RoomId}; -use crate::entity::item::Meseta; -use crate::ship::trade::ClientTradeState; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, ShipError, Clients}; +use location::{ClientLocation}; +use items::ClientItemId; +use items::state::{ItemState, ItemStateError}; +use items::inventory::InventoryItemDetail; +use items::trade::TradeItem; +use entity::gateway::EntityGateway; +use pktbuilder as builder; +use items::tasks::trade_items; +use location::{AreaClient, RoomId}; +use entity::item::Meseta; +use trade::{ClientTradeState, TradeState, TradeStatus}; pub const MESETA_ITEM_ID: ClientItemId = ClientItemId(0xFFFFFF01); pub const OTHER_MESETA_ITEM_ID: ClientItemId = ClientItemId(0xFFFFFFFF); @@ -450,8 +450,8 @@ where enum TradeReady/*<'a>*/ { OnePlayer, BothPlayers(RoomId, - (AreaClient, crate::ship::trade::ClientTradeState), - (AreaClient, crate::ship::trade::ClientTradeState)), + (AreaClient, ClientTradeState), + (AreaClient, ClientTradeState)), //(AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState), //(AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState)), } @@ -527,10 +527,10 @@ where .map(|(client, item)| { match item.item { InventoryItemDetail::Individual(individual_item) => { - GameMessage::CreateItem(builder::message::create_individual_item(client, item.item_id, &individual_item).unwrap()) + GameMessage::CreateItem(builder::message::create_individual_item(client, item.item_id, &individual_item)) }, InventoryItemDetail::Stacked(stacked_item) => { - GameMessage::CreateItem(builder::message::create_stacked_item(client, item.item_id, &stacked_item.tool, stacked_item.count()).unwrap()) + GameMessage::CreateItem(builder::message::create_stacked_item(client, item.item_id, &stacked_item.tool, stacked_item.count())) } } }); diff --git a/src/shops/Cargo.toml b/src/shops/Cargo.toml new file mode 100644 index 0000000..25e3055 --- /dev/null +++ b/src/shops/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "shops" +version = "0.1.0" +edition = "2021" + +[dependencies] +maps = { workspace = true } +stats = { workspace = true } +entity = { workspace = true } + +async-std = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } +toml = { workspace = true } +serde = { workspace = true } \ No newline at end of file diff --git a/src/ship/shops/armor.rs b/src/shops/src/armor.rs similarity index 95% rename from src/ship/shops/armor.rs rename to src/shops/src/armor.rs index d1d8b47..f424877 100644 --- a/src/ship/shops/armor.rs +++ b/src/shops/src/armor.rs @@ -5,12 +5,12 @@ use std::convert::TryInto; use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::ItemDetail; -use crate::entity::item::armor::{Armor, ArmorType}; -use crate::entity::item::shield::{Shield, ShieldType}; -use crate::entity::item::unit::{Unit, UnitType}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; +use entity::item::ItemDetail; +use entity::item::armor::{Armor, ArmorType}; +use entity::item::shield::{Shield, ShieldType}; +use entity::item::unit::{Unit, UnitType}; +use crate::ShopItem; +use stats::items::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; // #[derive(Debug)] // pub enum ArmorShopItem { @@ -342,8 +342,8 @@ impl ArmorShop { pub fn generate_armor_list(&mut self, character_level: usize) -> Vec { self.generate_frame_list(character_level).into_iter() - .chain(self.generate_barrier_list(character_level).into_iter()) - .chain(self.generate_unit_list(character_level).into_iter()) + .chain(self.generate_barrier_list(character_level)) + .chain(self.generate_unit_list(character_level)) .collect() } } diff --git a/src/shops/src/lib.rs b/src/shops/src/lib.rs new file mode 100644 index 0000000..94abdec --- /dev/null +++ b/src/shops/src/lib.rs @@ -0,0 +1,95 @@ +mod weapon; +mod tool; +mod armor; + +use async_std::sync::{Arc, Mutex}; +use futures::future::OptionFuture; +use std::collections::HashMap; +use entity::item::ItemDetail; +use maps::room::Difficulty; +use entity::character::SectionID; + +pub use weapon::{WeaponShop, WeaponShopItem}; +pub use tool::{ToolShop, ToolShopItem}; +pub use armor::{ArmorShop, ArmorShopItem}; + +pub trait ShopItem { + fn price(&self) -> usize; + fn as_bytes(&self) -> [u8; 12]; + fn as_item(&self) -> ItemDetail; +} + +#[async_trait::async_trait] +pub trait ItemShops { + async fn generate_weapon_list(&self, difficulty: Difficulty, section_id: SectionID, char_level: usize) -> Option>; + async fn generate_tool_list(&self, char_level: usize) -> Vec; + async fn generate_armor_list(&self, char_level: usize) -> Vec; +} + + +#[derive(Clone)] +pub struct StandardItemShops { + weapon_shop: HashMap<(Difficulty, SectionID), Arc>>>, + tool_shop: Arc>>, + armor_shop: Arc>>, +} + +impl Default for StandardItemShops { + fn default() -> StandardItemShops { + let difficulty = [Difficulty::Normal, Difficulty::Hard, Difficulty::VeryHard, Difficulty::Ultimate]; + let section_id = [SectionID::Viridia, SectionID::Greenill, SectionID::Skyly, SectionID::Bluefull, SectionID::Purplenum, + SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill]; + + let mut weapon_shop = HashMap::new(); + for d in difficulty.iter() { + for id in section_id.iter() { + weapon_shop.insert((*d, *id), Arc::new(Mutex::new(WeaponShop::new(*d, *id)))); + } + } + + StandardItemShops { + weapon_shop, + tool_shop: Arc::new(Mutex::new(ToolShop::default())), + armor_shop: Arc::new(Mutex::new(ArmorShop::default())), + } + } +} + +#[async_trait::async_trait] +impl ItemShops for StandardItemShops { + async fn generate_weapon_list(&self, difficulty: Difficulty, section_id: SectionID, char_level: usize) -> Option> { + OptionFuture::from( + self.weapon_shop + .get(&(difficulty, section_id)) + .map(|shop| async { + shop + .lock() + .await + .generate_weapon_list(char_level) + })).await + } + + async fn generate_tool_list(&self, char_level: usize) -> Vec { + self.tool_shop + .lock() + .await + .generate_tool_list(char_level) + } + + async fn generate_armor_list(&self, char_level: usize) -> Vec { + self.armor_shop + .lock() + .await + .generate_armor_list(char_level) + } +} + + + + +pub enum ShopType { + Weapon, + Tool, + Armor +} + diff --git a/src/ship/shops/tool.rs b/src/shops/src/tool.rs similarity index 92% rename from src/ship/shops/tool.rs rename to src/shops/src/tool.rs index b5f9718..b068d19 100644 --- a/src/ship/shops/tool.rs +++ b/src/shops/src/tool.rs @@ -6,11 +6,11 @@ use std::convert::TryInto; use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::ItemDetail; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::tech::{Technique, TechniqueDisk}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::{TOOL_STATS, TECH_STATS}; +use entity::item::ItemDetail; +use entity::item::tool::{Tool, ToolType}; +use entity::item::tech::{Technique, TechniqueDisk}; +use crate::ShopItem; +use stats::items::{TOOL_STATS, TECH_STATS}; #[derive(Debug, PartialEq, Eq)] @@ -36,16 +36,7 @@ impl Ord for ToolShopItem { impl PartialOrd for ToolShopItem { fn partial_cmp(&self, other: &ToolShopItem) -> Option { - let a = match self { - ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(), - ToolShopItem::Tech(t) => t.as_bytes(), - }; - let b = match other { - ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(), - ToolShopItem::Tech(t) => t.as_bytes(), - }; - - a.partial_cmp(&b) + Some(self.cmp(other)) } } @@ -285,7 +276,7 @@ impl ToolShop { pub fn generate_tool_list(&mut self, character_level: usize) -> Vec { let mut tools = Vec::new().into_iter() .chain(self.tools.0.clone().into_iter().map(ToolShopItem::Tool)) - .chain(self.generate_techs(character_level).into_iter()) + .chain(self.generate_techs(character_level)) .collect::>(); tools.sort(); tools diff --git a/src/ship/shops/weapon.rs b/src/shops/src/weapon.rs similarity index 98% rename from src/ship/shops/weapon.rs rename to src/shops/src/weapon.rs index a17e14d..06a8c1e 100644 --- a/src/ship/shops/weapon.rs +++ b/src/shops/src/weapon.rs @@ -8,12 +8,12 @@ use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; use rand::seq::{SliceRandom, IteratorRandom}; -use crate::entity::character::SectionID; -use crate::ship::room::Difficulty; -use crate::entity::item::ItemDetail; -use crate::entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::WEAPON_STATS; +use entity::character::SectionID; +use maps::room::Difficulty; +use entity::item::ItemDetail; +use entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; +use crate::ShopItem; +use stats::items::WEAPON_STATS; const TIER1_SPECIAL: [WeaponSpecial; 8] = [WeaponSpecial::Draw, WeaponSpecial::Heart, WeaponSpecial::Ice, WeaponSpecial::Bind, diff --git a/src/stats/Cargo.toml b/src/stats/Cargo.toml new file mode 100644 index 0000000..6cebc62 --- /dev/null +++ b/src/stats/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "stats" +version = "0.1.0" +edition = "2021" + +[dependencies] +entity = { workspace = true } +toml = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +lazy_static = { workspace = true } diff --git a/src/ship/item_stats.rs b/src/stats/src/items.rs similarity index 95% rename from src/ship/item_stats.rs rename to src/stats/src/items.rs index 919c076..13d0855 100644 --- a/src/ship/item_stats.rs +++ b/src/stats/src/items.rs @@ -4,13 +4,13 @@ use serde::{Serialize, Deserialize}; use std::fs::File; use std::io::Read; -use crate::entity::item::weapon::WeaponType; -use crate::entity::item::armor::ArmorType; -use crate::entity::item::shield::ShieldType; -use crate::entity::item::unit::UnitType; -use crate::entity::item::mag::MagType; -use crate::entity::item::tool::ToolType; -use crate::entity::item::tech::Technique; +use entity::item::weapon::WeaponType; +use entity::item::armor::ArmorType; +use entity::item::shield::ShieldType; +use entity::item::unit::UnitType; +use entity::item::mag::MagType; +use entity::item::tool::ToolType; +use entity::item::tech::Technique; lazy_static::lazy_static! { diff --git a/src/common/leveltable.rs b/src/stats/src/leveltable.rs similarity index 99% rename from src/common/leveltable.rs rename to src/stats/src/leveltable.rs index 9fb1465..7b06966 100644 --- a/src/common/leveltable.rs +++ b/src/stats/src/leveltable.rs @@ -1,6 +1,6 @@ use std::fs::File; use serde_json::Value; -use crate::entity::character::CharacterClass; +use entity::character::CharacterClass; use std::sync::LazyLock; pub static LEVEL_TABLE: LazyLock = LazyLock::new(CharacterLevelTable::default); diff --git a/src/stats/src/lib.rs b/src/stats/src/lib.rs new file mode 100644 index 0000000..0564e34 --- /dev/null +++ b/src/stats/src/lib.rs @@ -0,0 +1,4 @@ +#![feature(lazy_cell)] + +pub mod items; +pub mod leveltable; diff --git a/src/trade/Cargo.toml b/src/trade/Cargo.toml new file mode 100644 index 0000000..9d588b4 --- /dev/null +++ b/src/trade/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "trade" +version = "0.1.0" +edition = "2021" + + +[dependencies] +networking = { workspace = true } +items = { workspace = true } + +async-std = { workspace = true } +futures = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } \ No newline at end of file diff --git a/src/ship/trade.rs b/src/trade/src/lib.rs similarity index 79% rename from src/ship/trade.rs rename to src/trade/src/lib.rs index abe1cd2..319652c 100644 --- a/src/ship/trade.rs +++ b/src/trade/src/lib.rs @@ -1,45 +1,8 @@ use std::collections::HashMap; -use crate::common::serverstate::ClientId; -use crate::ship::items; +use networking::serverstate::ClientId; use async_std::sync::{Arc, Mutex, MutexGuard}; use futures::future::{Future, OptionFuture}; - -#[derive(Debug, Clone)] -pub enum TradeItem { - Individual(items::ClientItemId), - Stacked(items::ClientItemId, usize), -} - -impl TradeItem { - pub fn stacked(&self) -> Option<(items::ClientItemId, usize)> { - match self { - TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)), - _ => None - } - } - - pub fn stacked_mut(&mut self) -> Option<(items::ClientItemId, &mut usize)> { - match self { - TradeItem::Stacked(item_id, ref mut amount) => Some((*item_id, amount)), - _ => None - } - } - - pub fn item_id(&self) -> items::ClientItemId { - match self { - TradeItem::Individual(item_id) => *item_id, - TradeItem::Stacked(item_id, _) => *item_id, - } - } - - pub fn amount(&self) -> usize { - match self { - TradeItem::Individual(_) => 1, - TradeItem::Stacked(_, amount) => *amount, - } - } -} - +use items::trade::TradeItem; #[derive(Debug, Clone, Eq, PartialEq)] pub enum TradeStatus { diff --git a/tests/common.rs b/tests/common.rs index e9dccd0..31f373e 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -1,22 +1,83 @@ #![allow(dead_code)] -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::EntityGateway; -use elseware::entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; -use elseware::entity::character::{CharacterEntity, NewCharacterEntity}; -use elseware::entity::item::{Meseta, BankName, BankIdentifier}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::ship::room::Difficulty; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::EntityGateway; +use entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; +use entity::character::{CharacterEntity, NewCharacterEntity, SectionID}; +use entity::item::{Meseta, BankIdentifier}; +use ship_server::{ShipServerState, ShipServerStateBuilder, RecvShipPacket}; +use maps::room::{RoomMode, Difficulty, Episode}; +use maps::area::MapArea; +use maps::maps::null_free_roam_maps; +use maps::object::MapObject; +use maps::monster::MonsterType; +use quests::{QuestList, QuestLoadError}; +use drops::{DropTable, ItemDropType}; +use shops::{ItemShops, WeaponShopItem, ToolShopItem, ArmorShopItem}; -use elseware::entity::item; +use entity::item; use libpso::packet::ship::*; use libpso::packet::login::{Login, Session}; -use libpso::{utf8_to_array, utf8_to_utf16_array}; +use libpso::util::{utf8_to_array, utf8_to_utf16_array}; +fn null_quest_builder(_mode: RoomMode) -> Result { + Ok(Default::default()) +} + +struct NullDropTable; + +impl DropTable for NullDropTable { + fn get_drop(&mut self, _map_area: &MapArea, _monster: &MonsterType) -> Option { + None + } + fn get_box_drop(&mut self, _map_area: &MapArea, _object: &MapObject) -> Option { + None + } +} + +pub fn null_drop_table_builder(_episode: Episode, _difficult: Difficulty, _section_id: SectionID) -> Box { + Box::new(NullDropTable) +} + +struct NullItemShops; + +#[async_trait::async_trait] +impl ItemShops for NullItemShops { + async fn generate_weapon_list(&self, _difficulty: Difficulty, _section_id: SectionID, _char_level: usize) -> Option> { + Some(Vec::new()) + } + async fn generate_tool_list(&self, _char_level: usize) -> Vec { + Vec::new() + } + async fn generate_armor_list(&self, _char_level: usize) -> Vec { + Vec::new() + } +} + +pub fn standard_ship_buildable(gateway: EG) -> ShipServerStateBuilder { + ShipServerState::builder() + .gateway(gateway) + .standard_quest_builder(Box::new(null_quest_builder)) + .government_quest_builder(Box::new(null_quest_builder)) + .drop_table_builder(Box::new(null_drop_table_builder)) + .map_builder(Box::new(null_free_roam_maps)) + .item_shops(NullItemShops) +} + +pub fn standard_ship(gateway: EG) -> ShipServerState { + ShipServerState::builder() + .gateway(gateway) + .standard_quest_builder(Box::new(null_quest_builder)) + .government_quest_builder(Box::new(null_quest_builder)) + .drop_table_builder(Box::new(null_drop_table_builder)) + .map_builder(Box::new(null_free_roam_maps)) + .item_shops(NullItemShops) + .build() +} //TODO: remove kb_conf_preset -pub async fn new_user_character(entity_gateway: &mut EG, username: &str, password: &str, kb_conf_preset: usize) -> (UserAccountEntity, CharacterEntity) { +pub async fn new_user_character(entity_gateway: &mut EG, username: &str, password: &str) -> (UserAccountEntity, CharacterEntity) { let new_user = NewUserAccountEntity { email: format!("{}@pso.com", username), username: username.into(), @@ -46,12 +107,12 @@ pub async fn log_in_char(ship: &mut ShipServerState(ship: &mut ShipServerState(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str, difficulty: Difficulty) { ship.handle(id, RecvShipPacket::CreateRoom(CreateRoom { unknown: [0; 2], - name: utf8_to_utf16_array!(name, 16), - password: utf8_to_utf16_array!(password, 16), + name: utf8_to_utf16_array(name), + password: utf8_to_utf16_array(password), difficulty: difficulty.into(), battle: 0, challenge: 0, @@ -100,9 +161,23 @@ pub async fn join_room(ship: &mut ShipServerState pub struct WeaponBuilder { weapon: item::weapon::WeaponType, grind: u8, + special: Option, + attributes: [Option; 3], + tekked: bool, } + impl WeaponBuilder { + fn new(weapon: item::weapon::WeaponType) -> WeaponBuilder { + WeaponBuilder { + weapon, + grind: 0, + special: None, + attributes: [None; 3], + tekked: true, + } + } + pub fn grind(self, grind: u8) -> WeaponBuilder { WeaponBuilder { grind, @@ -110,28 +185,267 @@ impl WeaponBuilder { } } + pub fn special(self, special: item::weapon::WeaponSpecial) -> WeaponBuilder { + WeaponBuilder { + special: Some(special), + ..self + } + } + + pub fn attr(mut self, attr: item::weapon::Attribute, value: i8) -> WeaponBuilder { + self.attributes + .iter_mut() + .find(|k| k.is_none()) + .map(|empty_attr| { + *empty_attr = Some(item::weapon::WeaponAttribute { + attr, + value, + }) + }); + + self + } + + pub fn untekked(self) -> WeaponBuilder { + WeaponBuilder { + tekked: false, + ..self + } + } + pub fn as_new(self) -> item::NewItemEntity { item::NewItemEntity { item: item::ItemDetail::Weapon( item::weapon::Weapon { weapon: self.weapon, grind: self.grind, - special: None, - attrs: [None, None, None], - tekked: true, + special: self.special, + attrs: self.attributes, + tekked: self.tekked, + } + ) + } + } +} + +pub struct ArmorBuilder { + armor: item::armor::ArmorType, + dfp: u8, + evp: u8, + slots: u8, +} + +impl ArmorBuilder { + pub fn new(armor: item::armor::ArmorType) -> ArmorBuilder { + ArmorBuilder { + armor: armor, + dfp: 0, + evp: 0, + slots: 0, + } + } + + pub fn slots(self, slots: u8) -> ArmorBuilder { + ArmorBuilder { + slots, + ..self + } + } + + pub fn dfp(self, dfp: u8) -> ArmorBuilder { + ArmorBuilder { + dfp, + ..self + } + } + + pub fn evp(self, evp: u8) -> ArmorBuilder { + ArmorBuilder { + evp, + ..self + } + } + + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Armor( + item::armor::Armor { + armor: self.armor, + dfp: self.dfp, + evp: self.evp, + slots: self.slots, + } + ) + } + } +} + +pub struct ShieldBuilder { + shield: item::shield::ShieldType, + dfp: u8, + evp: u8, +} + +impl ShieldBuilder { + pub fn new(shield: item::shield::ShieldType) -> ShieldBuilder { + ShieldBuilder { + shield: shield, + dfp: 0, + evp: 0, + } + } + + pub fn dfp(self, dfp: u8) -> ShieldBuilder { + ShieldBuilder { + dfp, + ..self + } + } + + pub fn evp(self, evp: u8) -> ShieldBuilder { + ShieldBuilder { + evp, + ..self + } + } + + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Shield( + item::shield::Shield { + shield: self.shield, + dfp: self.dfp, + evp: self.evp, + } + ) + } + } +} + + +pub struct UnitBuilder { + unit: item::unit::UnitType, + modifier: Option, +} + +impl UnitBuilder { + pub fn modifier(self, modifier: item::unit::UnitModifier) -> UnitBuilder { + UnitBuilder { + modifier: Some(modifier), + ..self + } + } + + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Unit( + item::unit::Unit { + unit: self.unit, + modifier: self.modifier, + } + ) + } + } +} + + +pub struct MagBuilder { +} + +impl MagBuilder { + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Mag( + item::mag::Mag::baby_mag(0) + ) + } + } +} + + + +pub struct ToolBuilder { + tool: item::tool::ToolType, +} + +impl ToolBuilder { + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Tool ( + item::tool::Tool { + tool: self.tool, + } + ), + } + } +} + +pub struct TechBuilder { + tech: item::tech::Technique, + level: u32, +} + + +impl TechBuilder { + pub fn level(self, level: u32) -> TechBuilder { + TechBuilder { + level, + ..self + } + } + + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::TechniqueDisk ( + item::tech::TechniqueDisk { + tech: self.tech, + level: self.level, } ) } } } + pub struct ItemBuilder; impl ItemBuilder { pub fn weapon(weapon: item::weapon::WeaponType) -> WeaponBuilder { - WeaponBuilder { - weapon, - grind: 0, + WeaponBuilder::new(weapon) + } + + pub fn armor(armor: item::armor::ArmorType) -> ArmorBuilder { + ArmorBuilder::new(armor) + } + + pub fn shield(shield: item::shield::ShieldType) -> ShieldBuilder { + ShieldBuilder::new(shield) + } + + pub fn unit(unit: item::unit::UnitType) -> UnitBuilder { + UnitBuilder { + unit: unit, + modifier: None, } } + + pub fn baby_mag() -> MagBuilder { + MagBuilder { + } + } + + pub fn tool(tool: item::tool::ToolType) -> ToolBuilder { + ToolBuilder { + tool: tool, + } + } + + pub fn tech(tech: item::tech::Technique) -> TechBuilder { + TechBuilder { + tech: tech, + level: 0, + } + } + + } diff --git a/tests/test_bank.rs b/tests/test_bank.rs index 71fc8f5..7f825af 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -1,8 +1,9 @@ use std::collections::BTreeSet; -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::{RecvShipPacket, SendShipPacket}; +use shops::StandardItemShops; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -15,27 +16,17 @@ use common::*; async fn test_bank_items_sent_in_character_login() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 item = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![item]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; let packets = ship.handle(ClientId(1), RecvShipPacket::MenuSelect(MenuSelect { @@ -50,30 +41,20 @@ async fn test_bank_items_sent_in_character_login() { async fn test_request_bank_items() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut bank = Vec::new(); for _ in 0..3 { bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -98,26 +79,20 @@ async fn test_request_bank_items() { async fn test_request_stacked_bank_items() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool ( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -141,48 +116,26 @@ async fn test_request_stacked_bank_items() { async fn test_request_bank_items_sorted() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 item1 = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap(); let monomate = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool ( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap(); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap(); let item2 = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Calibur, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Calibur) + .as_new() + ).await.unwrap(); let bank = vec![item::BankItemEntity::Individual(item1), vec![monomate].into(), item2.into()]; entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -207,39 +160,21 @@ async fn test_request_bank_items_sorted() { async fn test_deposit_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 item0 = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(); let item1 = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![item0, item1])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -286,26 +221,20 @@ async fn test_deposit_individual_item() { async fn test_deposit_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -347,26 +276,20 @@ async fn test_deposit_stacked_item() { async fn test_deposit_partial_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -417,37 +340,27 @@ async fn test_deposit_partial_stacked_item() { async fn test_deposit_stacked_item_with_stack_already_in_bank() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut bank_monomates = Vec::new(); let mut inventory_monomates = Vec::new(); for _ in 0..2usize { inventory_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![inventory_monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -489,38 +402,28 @@ async fn test_deposit_stacked_item_with_stack_already_in_bank() { async fn test_deposit_stacked_item_with_full_stack_in_bank() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut inventory_monomates = Vec::new(); for _ in 0..2usize { inventory_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut bank_monomates = Vec::new(); for _ in 0..10 { bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![inventory_monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -561,44 +464,26 @@ async fn test_deposit_stacked_item_with_full_stack_in_bank() { async fn test_deposit_individual_item_in_full_bank() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut inventory = Vec::new(); inventory.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); let mut bank = Vec::new(); for _ in 0..200usize { bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inventory)).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -635,42 +520,28 @@ async fn test_deposit_individual_item_in_full_bank() { async fn test_deposit_stacked_item_in_full_bank() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut monomates = Vec::new(); for _ in 0..2usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut full_bank = Vec::new(); for _ in 0..200usize { full_bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(full_bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -708,55 +579,37 @@ async fn test_deposit_stacked_item_in_full_bank() { async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut monomates = Vec::new(); for _ in 0..2usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut bank_monomates = Vec::new(); for _ in 0..2usize { bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut almost_full_bank: Vec = Vec::new(); for _ in 0..199usize { almost_full_bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap().into()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap().into()); } almost_full_bank.push(bank_monomates.into()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(almost_full_bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -791,12 +644,10 @@ async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { async fn test_deposit_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -827,13 +678,11 @@ async fn test_deposit_meseta() { async fn test_deposit_too_much_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(999980)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -866,13 +715,11 @@ async fn test_deposit_too_much_meseta() { async fn test_deposit_meseta_when_bank_is_maxed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -906,28 +753,18 @@ async fn test_deposit_meseta_when_bank_is_maxed() { async fn test_withdraw_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut bank = Vec::new(); bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -968,26 +805,20 @@ async fn test_withdraw_individual_item() { async fn test_withdraw_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1028,25 +859,19 @@ async fn test_withdraw_stacked_item() { async fn test_withdraw_partial_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1094,37 +919,27 @@ async fn test_withdraw_partial_stacked_item() { async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut inventory_monomates = Vec::new(); let mut bank_monomates = Vec::new(); for _ in 0..2usize { inventory_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![inventory_monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1168,38 +983,28 @@ async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { async fn test_withdraw_stacked_item_with_full_stack_in_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut bank_monomates = Vec::new(); for _ in 0..2usize { bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut inventory_monomates = Vec::new(); for _ in 0..10usize { inventory_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![inventory_monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1240,44 +1045,26 @@ async fn test_withdraw_stacked_item_with_full_stack_in_inventory() { async fn test_withdraw_individual_item_in_full_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut bank = Vec::new(); bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); let mut inventory = Vec::new(); for _ in 0..30usize { inventory.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inventory)).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1310,42 +1097,28 @@ async fn test_withdraw_individual_item_in_full_inventory() { async fn test_withdraw_stacked_item_in_full_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut monomates = Vec::new(); for _ in 0..2usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut inventory = Vec::new(); for _ in 0..30usize { inventory.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inventory)).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1384,55 +1157,37 @@ async fn test_withdraw_stacked_item_in_full_inventory() { async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut bank_item = Vec::new(); for _ in 0..2usize { bank_item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_item]), &item::BankIdentifier::Character).await.unwrap(); let mut items = Vec::new(); for _i in 0..29usize { items.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap().into()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap().into()); } let mut item29 = Vec::new(); for _ in 0..2usize { item29.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } items.push(item::InventoryItemEntity::Stacked(item29)); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1470,12 +1225,10 @@ async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { async fn test_withdraw_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1506,13 +1259,11 @@ async fn test_withdraw_meseta() { async fn test_withdraw_too_much_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999980)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1545,13 +1296,11 @@ async fn test_withdraw_too_much_meseta() { async fn test_withdraw_meseta_inventory_is_maxed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1586,13 +1335,13 @@ async fn test_withdraw_meseta_inventory_is_maxed() { async fn test_withdraw_meseta_and_buy_a_few_monomates_with_it() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(100)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1638,7 +1387,7 @@ async fn test_withdraw_meseta_and_buy_a_few_monomates_with_it() { async fn test_deposit_items_into_shared_banks() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let item0 = entity_gateway.create_item(ItemBuilder::weapon(item::weapon::WeaponType::Saber).as_new()).await.unwrap(); let item1 = entity_gateway.create_item(ItemBuilder::weapon(item::weapon::WeaponType::Buster).as_new()).await.unwrap(); @@ -1649,9 +1398,7 @@ async fn test_deposit_items_into_shared_banks() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![item0, item1, item2, item3, item4, item5])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1762,12 +1509,10 @@ async fn test_deposit_items_into_shared_banks() { async fn test_deposit_meseta_into_shared_banks() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1839,7 +1584,7 @@ async fn test_deposit_meseta_into_shared_banks() { async fn test_withdraw_items_from_shared_banks() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let item0 = entity_gateway.create_item(ItemBuilder::weapon(item::weapon::WeaponType::Saber).as_new()).await.unwrap(); let item1 = entity_gateway.create_item(ItemBuilder::weapon(item::weapon::WeaponType::Buster).as_new()).await.unwrap(); @@ -1852,9 +1597,7 @@ async fn test_withdraw_items_from_shared_banks() { entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![item2, item3]), &item::BankIdentifier::Shared(item::BankName("asdf".into()))).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![item4, item5]), &item::BankIdentifier::Shared(item::BankName("qwer".into()))).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1951,14 +1694,12 @@ async fn test_withdraw_items_from_shared_banks() { async fn test_withdraw_meseta_from_shared_banks() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Shared(item::BankName("asdf".into())), item::Meseta(300)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Shared(item::BankName("qwer".into())), item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_character.rs b/tests/test_character.rs index ca16eac..237ded9 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -1,8 +1,8 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use ship_server::RecvShipPacket; -use libpso::character::settings::{DEFAULT_KEYBOARD_CONFIG1, DEFAULT_KEYBOARD_CONFIG2, DEFAULT_KEYBOARD_CONFIG3, DEFAULT_KEYBOARD_CONFIG4}; +use libpso::character::settings::{DEFAULT_KEYBOARD_CONFIG1, DEFAULT_KEYBOARD_CONFIG4}; use libpso::packet::ship::*; #[path = "common.rs"] @@ -13,11 +13,9 @@ use common::*; async fn test_save_options() { let mut entity_gateway = InMemoryGateway::default(); - let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -35,11 +33,9 @@ async fn test_save_options() { async fn test_change_keyboard_mappings() { let mut entity_gateway = InMemoryGateway::default(); - let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 2).await; + let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 0317e9d..db71ec9 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -1,13 +1,12 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::common::leveltable::CharacterLevelTable; -use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; -use elseware::ship::monster::MonsterType; -use elseware::ship::location::RoomId; -use elseware::ship::map::variant::{MapVariant, MapVariantMode}; -use elseware::ship::map::maps::Maps; -use elseware::ship::map::area::MapArea; -use elseware::ship::map::enemy::MapEnemy; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use stats::leveltable::CharacterLevelTable; +use ship_server::{SendShipPacket, RecvShipPacket}; +use maps::variant::{MapVariant, MapVariantMode}; +use maps::maps::Maps; +use maps::area::MapArea; +use maps::enemy::MapEnemy; +use maps::monster::MonsterType; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -20,18 +19,17 @@ use common::*; async fn test_character_gains_exp() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -54,20 +52,19 @@ async fn test_character_gains_exp() { async fn test_character_levels_up() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 49; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -93,18 +90,17 @@ async fn test_character_levels_up() { async fn test_character_levels_up_multiple_times() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::DarkFalz, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::DarkFalz2, MapArea::DarkFalz))], - Vec::new(), - ) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::DarkFalz, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::DarkFalz2, MapArea::DarkFalz))], + Vec::new(), + ) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -129,19 +125,18 @@ async fn test_character_levels_up_multiple_times() { async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .build()); + 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 mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; diff --git a/tests/test_item_actions.rs b/tests/test_item_actions.rs index 77d52bc..1237063 100644 --- a/tests/test_item_actions.rs +++ b/tests/test_item_actions.rs @@ -1,7 +1,7 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::item; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use ship_server::RecvShipPacket; +use entity::item; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -14,37 +14,25 @@ use common::*; async fn test_equip_unit_from_equip_menu() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor{ - armor: item::armor::ArmorType::Frame, - dfp: 0, - evp: 0, - slots: 4, - }), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .slots(4) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: None, - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: Some(item::unit::UnitModifier::Plus), - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .modifier(item::unit::UnitModifier::Plus) + .as_new() + ).await.unwrap()); let equipped = item::EquippedEntity { weapon: None, @@ -56,9 +44,7 @@ async fn test_equip_unit_from_equip_menu() { entity_gateway.set_character_equips(&char1.id, &equipped).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -91,37 +77,25 @@ async fn test_equip_unit_from_equip_menu() { async fn test_unequip_armor_with_units() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor{ - armor: item::armor::ArmorType::Frame, - dfp: 0, - evp: 0, - slots: 4, - }), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .slots(4) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: None, - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: Some(item::unit::UnitModifier::Plus), - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .modifier(item::unit::UnitModifier::Plus) + .as_new() + ).await.unwrap()); let equipped = item::EquippedEntity { weapon: None, @@ -133,9 +107,7 @@ async fn test_unequip_armor_with_units() { entity_gateway.set_character_equips(&char1.id, &equipped).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -159,43 +131,29 @@ async fn test_unequip_armor_with_units() { async fn test_sort_items() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor{ - armor: item::armor::ArmorType::Frame, - dfp: 0, - evp: 0, - slots: 4, - }), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .slots(4) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: None, - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: Some(item::unit::UnitModifier::Plus), - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .modifier(item::unit::UnitModifier::Plus) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -216,8 +174,8 @@ async fn test_sort_items() { ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::SortItems(SortItems { client: 255, target: 255, - item_ids: [0x10001u32, 0x10002, 0x10000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + item_ids: [0x10001u32, 0x10002, 0x10000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], })))).await.unwrap(); diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs index 02b01b1..91f179b 100644 --- a/tests/test_item_drop.rs +++ b/tests/test_item_drop.rs @@ -1,15 +1,14 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::character::SectionID; -use elseware::common::leveltable::CharacterLevelTable; -use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; -use elseware::ship::room::{Episode, Difficulty}; -use elseware::ship::monster::MonsterType; -use elseware::ship::location::RoomId; -use elseware::ship::drops::{DropTable, MonsterDropStats, MonsterDropType}; -use elseware::ship::drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; -use elseware::ship::map::{Maps, MapVariant, MapArea, MapVariantMode, MapEnemy}; -use elseware::entity::item::weapon::WeaponType; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::InMemoryGateway; +use ship_server::{SendShipPacket, RecvShipPacket}; +use maps::monster::MonsterType; +use drops::{StandardDropTable, MonsterDropStats, MonsterDropType}; +use drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; +use maps::maps::Maps; +use maps::area::MapArea; +use maps::variant::{MapVariant, MapVariantMode}; +use maps::enemy::MapEnemy; +use entity::item::weapon::WeaponType; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -21,34 +20,33 @@ use common::*; #[async_std::test] async fn test_enemy_drops_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() - .monster_stat(MonsterType::Hildebear, MonsterDropStats { - dar: 100, - drop_type: MonsterDropType::Weapon, - min_meseta: 0, - max_meseta: 0, - }) - .rare_table(RareDropTable::builder() - .rate(MonsterType::Hildebear, RareDropRate { - rate: 1.0, - item: RareDropItem::Weapon(WeaponType::DarkFlow) - }) - .build(episode, difficulty, section_id)) - .build(episode, difficulty, section_id) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + StandardDropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -76,35 +74,34 @@ async fn test_enemy_drops_item() { #[async_std::test] async fn test_enemy_drops_item_for_two_players() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() - .monster_stat(MonsterType::Hildebear, MonsterDropStats { - dar: 100, - drop_type: MonsterDropType::Weapon, - min_meseta: 0, - max_meseta: 0, - }) - .rare_table(RareDropTable::builder() - .rate(MonsterType::Hildebear, RareDropRate { - rate: 1.0, - item: RareDropItem::Weapon(WeaponType::DarkFlow) - }) - .build(episode, difficulty, section_id)) - .build(episode, difficulty, section_id) - })) - .build()); + 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 mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + StandardDropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -144,35 +141,34 @@ async fn test_enemy_drops_item_for_two_players() { #[async_std::test] async fn test_enemy_drops_item_for_two_players_and_pick_up() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() - .monster_stat(MonsterType::Hildebear, MonsterDropStats { - dar: 100, - drop_type: MonsterDropType::Weapon, - min_meseta: 0, - max_meseta: 0, - }) - .rare_table(RareDropTable::builder() - .rate(MonsterType::Hildebear, RareDropRate { - rate: 1.0, - item: RareDropItem::Weapon(WeaponType::DarkFlow) - }) - .build(episode, difficulty, section_id)) - .build(episode, difficulty, section_id) - })) - .build()); + 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 mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + StandardDropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; diff --git a/tests/test_item_id.rs b/tests/test_item_id.rs index f8ba644..3302806 100644 --- a/tests/test_item_id.rs +++ b/tests/test_item_id.rs @@ -1,9 +1,7 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::TechLevel; -//use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::RecvShipPacket; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -16,21 +14,17 @@ use common::*; #[async_std::test] async fn test_use_monomate_after_leaving_and_rejoining_room() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() { let mut item = Vec::new(); for _ in 0..2usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } @@ -42,22 +36,16 @@ async fn test_use_monomate_after_leaving_and_rejoining_room() { let mut item = Vec::new(); for _ in 0..2usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p2_items.push(item::InventoryItemEntity::Stacked(item)); } entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -111,22 +99,18 @@ async fn test_use_monomate_after_leaving_and_rejoining_room() { #[async_std::test] async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let (_user3, char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).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 (_user3, char3) = new_user_character(&mut entity_gateway, "a3", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monofluid, item::tool::ToolType::Difluid, item::tool::ToolType::Trifluid].into_iter() { let mut item = Vec::new(); for _ in 0..2usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } @@ -137,13 +121,9 @@ async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins let mut item = Vec::new(); for _ in 0..6usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p2_items.push(item::InventoryItemEntity::Stacked(item)); } @@ -154,24 +134,14 @@ async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins p3_items.push( item::InventoryItemEntity::Individual( entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap() + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap() )); } entity_gateway.set_character_inventory(&char3.id, &item::InventoryEntity::new(p3_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; log_in_char(&mut ship, ClientId(3), "a3", "a").await; @@ -300,20 +270,16 @@ async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins #[async_std::test] async fn test_depositing_a_full_stack_then_withdrawing_part() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monofluid, item::tool::ToolType::Difluid, item::tool::ToolType::Trifluid].into_iter() { let mut item = Vec::new(); for _ in 0..5usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } @@ -322,19 +288,13 @@ async fn test_depositing_a_full_stack_then_withdrawing_part() { let mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_item_pickup.rs b/tests/test_item_pickup.rs index 394cc3a..ccef78a 100644 --- a/tests/test_item_pickup.rs +++ b/tests/test_item_pickup.rs @@ -1,7 +1,7 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::RecvShipPacket; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -14,29 +14,19 @@ use common::*; async fn test_pick_up_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -85,31 +75,23 @@ async fn test_pick_up_individual_item() { async fn test_pick_up_item_stack_of_items_already_in_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_monomate = Vec::new(); p1_monomate.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); let mut p2_items = Vec::new(); for (_slot, tool) in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter().enumerate() { let mut item = Vec::new(); for _ in 0..5usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p2_items.push(item); } @@ -117,9 +99,7 @@ async fn test_pick_up_item_stack_of_items_already_in_inventory() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_monomate])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -161,24 +141,18 @@ async fn test_pick_up_item_stack_of_items_already_in_inventory() { async fn test_pick_up_item_stack_of_items_not_already_held() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p2_monomate = Vec::new(); p2_monomate.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_monomate])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -220,31 +194,21 @@ async fn test_pick_up_item_stack_of_items_not_already_held() { async fn test_pick_up_meseta_when_inventory_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_items = Vec::new(); for _ in 0..30usize { p1_items.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -293,50 +257,32 @@ async fn test_pick_up_meseta_when_inventory_full() { async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); for _slot in 0..29usize { p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap().into()); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap().into()); } p1_inv.push(item::InventoryItemEntity::Stacked(vec![entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()])); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()])); let mut p2_monomates = Vec::new(); p2_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -376,45 +322,27 @@ async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() { async fn test_can_not_pick_up_item_when_inventory_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); for _slot in 0..30usize { p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()); } let mut p2_inv = Vec::new(); p2_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -466,13 +394,11 @@ async fn test_can_not_pick_up_item_when_inventory_full() { async fn test_can_not_drop_more_meseta_than_is_held() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -506,38 +432,28 @@ async fn test_can_not_drop_more_meseta_than_is_held() { async fn test_pick_up_stack_that_would_exceed_stack_limit() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_monomates = Vec::new(); for _ in 0..6usize { p1_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut p2_monomates = Vec::new(); for _ in 0..6usize { p2_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_monomates])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -580,15 +496,13 @@ async fn test_pick_up_stack_that_would_exceed_stack_limit() { async fn test_can_not_pick_up_meseta_when_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -635,15 +549,13 @@ async fn test_can_not_pick_up_meseta_when_full() { async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999998)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -689,26 +601,20 @@ async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { async fn test_player_drops_partial_stack_and_other_player_picks_it_up() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut monomates = Vec::new(); for _ in 0..5usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; diff --git a/tests/test_item_use.rs b/tests/test_item_use.rs index b6b8502..274a344 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -1,9 +1,8 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::TechLevel; -//use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::RecvShipPacket; +use entity::character::TechLevel; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -17,29 +16,23 @@ use common::*; async fn test_use_monomate() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() { let mut item = Vec::new(); for _ in 0..2usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -64,29 +57,23 @@ async fn test_use_monomate() { async fn test_use_monomate_twice() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() { let mut item = Vec::new(); for _ in 0..3usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -116,25 +103,19 @@ async fn test_use_monomate_twice() { async fn test_use_last_monomate() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() { p1_inv.push(item::InventoryItemEntity::Stacked(vec![entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()])); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()])); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -158,23 +139,17 @@ async fn test_use_last_monomate() { async fn test_use_nonstackable_tool() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_items = Vec::new(); p1_items.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::HuntersReport, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::HuntersReport) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -193,29 +168,23 @@ async fn test_use_nonstackable_tool() { async fn test_use_materials() { let mut entity_gateway = InMemoryGateway::default(); - let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); for tool in vec![item::tool::ToolType::PowerMaterial, item::tool::ToolType::LuckMaterial].into_iter() { let mut item = Vec::new(); for _ in 0..5usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_inv.push(item::InventoryItemEntity::Stacked(item)); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -255,32 +224,23 @@ async fn test_use_materials() { #[async_std::test] async fn test_jackolantern() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let p1_inv = vec![ item::InventoryItemEntity::Stacked( vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::JackOLantern, - } - ), - }).await.unwrap(), - entity_gateway.create_item(item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::JackOLantern, - } - ), - }).await.unwrap(), + ItemBuilder::tool(item::tool::ToolType::JackOLantern) + .as_new() + ).await.unwrap(), + entity_gateway.create_item( + ItemBuilder::tool(item::tool::ToolType::JackOLantern) + .as_new() + ).await.unwrap(), ])]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -310,46 +270,29 @@ async fn test_jackolantern() { async fn test_use_barta_1() { let mut entity_gateway = InMemoryGateway::default(); - let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::TechniqueDisk( - item::tech::TechniqueDisk { - tech: item::tech::Technique::Foie, - level: 3, - } - ) - } + ItemBuilder::tech(item::tech::Technique::Foie) + .level(3) + .as_new() ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::TechniqueDisk( - item::tech::TechniqueDisk { - tech: item::tech::Technique::Barta, - level: 4, - } - ) - } + ItemBuilder::tech(item::tech::Technique::Barta) + .level(4) + .as_new() ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::TechniqueDisk( - item::tech::TechniqueDisk { - tech: item::tech::Technique::Zonde, - level: 5, - } - ) - } + ItemBuilder::tech(item::tech::Technique::Zonde) + .level(5) + .as_new() ).await.unwrap() ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -380,31 +323,19 @@ async fn test_use_barta_1() { async fn test_use_monogrinder() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let saber = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(); let mut grinders = Vec::new(); for _ in 0..3usize { grinders.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monogrinder, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monogrinder) + .as_new() + ).await.unwrap()); } let equipped = item::EquippedEntity { @@ -418,9 +349,7 @@ async fn test_use_monogrinder() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![item::InventoryItemEntity::Individual(saber), item::InventoryItemEntity::Stacked(grinders)])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_mags.rs b/tests/test_mags.rs index 1a7d687..8ffc6a9 100644 --- a/tests/test_mags.rs +++ b/tests/test_mags.rs @@ -1,8 +1,8 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::{CharacterClass, SectionID}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::RecvShipPacket; +use entity::character::{CharacterClass, SectionID}; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -15,25 +15,19 @@ use common::*; async fn test_mag_feed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mag = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Mag( - item::mag::Mag::baby_mag(0) - ), - }).await.unwrap(); + ItemBuilder::baby_mag() + .as_new() + ).await.unwrap(); let mut monomates = Vec::new(); for _ in 0..7usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let equipped = item::EquippedEntity { @@ -50,9 +44,7 @@ async fn test_mag_feed() { inventory.push(item::InventoryItemEntity::Stacked(monomates)); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inventory)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -87,8 +79,8 @@ async fn test_mag_feed() { async fn test_mag_change_owner() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; char1.char_class = CharacterClass::RAmarl; char1.section_id = SectionID::Redria; entity_gateway.save_character(&char1).await.unwrap(); @@ -97,17 +89,13 @@ async fn test_mag_change_owner() { entity_gateway.save_character(&char2).await.unwrap(); let mag = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Mag( - item::mag::Mag::baby_mag(0) - ), - }).await.unwrap(); + ItemBuilder::baby_mag() + .as_new() + ).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![mag])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -152,34 +140,24 @@ async fn test_mag_change_owner() { async fn test_mag_cell() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mag = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Mag( - item::mag::Mag::baby_mag(0) - ), - }).await.unwrap(); + ItemBuilder::baby_mag() + .as_new() + ).await.unwrap(); for _ in 0..1000usize { let fed_tool = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool ( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap(); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap(); entity_gateway.feed_mag(&mag.id, &fed_tool.id).await.unwrap(); } let mag_cell = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::CellOfMag502, - } - ), - }).await.unwrap(); + ItemBuilder::tool(item::tool::ToolType::CellOfMag502) + .as_new() + ).await.unwrap(); let equipped = item::EquippedEntity { weapon: None, @@ -191,9 +169,7 @@ async fn test_mag_cell() { entity_gateway.set_character_equips(&char1.id, &equipped).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![mag, mag_cell])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index 00b512d..5e65574 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -1,8 +1,6 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; -use elseware::ship::location::RoomId; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use ship_server::{RecvShipPacket, SendShipPacket}; use libpso::packet::ship::*; //use libpso::packet::messages::*; @@ -15,10 +13,10 @@ use common::*; #[async_std::test] async fn test_set_valid_quest_group() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .standard_quest_builder(Box::new(quests::load_standard_quests)) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -35,10 +33,11 @@ async fn test_set_valid_quest_group() { #[async_std::test] async fn test_set_invalid_quest_group() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .standard_quest_builder(Box::new(quests::load_standard_quests)) + .government_quest_builder(Box::new(quests::load_government_quests)) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -57,13 +56,11 @@ async fn test_set_invalid_quest_group() { #[async_std::test] async fn test_get_room_info() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; _char1.name = String::from("GODmar"); entity_gateway.save_character(&_char1).await.unwrap(); - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -80,11 +77,9 @@ async fn test_get_room_info() { #[async_std::test] async fn test_cannot_get_room_info_after_room_is_closed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + 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 mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -102,11 +97,9 @@ async fn test_cannot_get_room_info_after_room_is_closed() { #[async_std::test] async fn test_cannot_join_room_after_its_closed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + 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 mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; diff --git a/tests/test_shops.rs b/tests/test_shops.rs index cf230c9..59540b7 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -1,9 +1,10 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; -use elseware::ship::room::Difficulty; -use elseware::ship::items::state::ItemStateError; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::{RecvShipPacket, SendShipPacket}; +use maps::room::Difficulty; +use items::state::ItemStateError; +use shops::StandardItemShops; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -16,13 +17,13 @@ use common::*; async fn test_player_opens_weapon_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -46,13 +47,13 @@ async fn test_player_opens_weapon_shop() { async fn test_player_opens_tool_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -76,13 +77,13 @@ async fn test_player_opens_tool_shop() { async fn test_player_opens_armor_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -106,14 +107,14 @@ async fn test_player_opens_armor_shop() { async fn test_player_buys_from_weapon_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -144,14 +145,14 @@ async fn test_player_buys_from_weapon_shop() { async fn test_player_buys_from_tool_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -181,14 +182,14 @@ async fn test_player_buys_from_tool_shop() { async fn test_player_buys_multiple_from_tool_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -222,14 +223,14 @@ async fn test_player_buys_multiple_from_tool_shop() { async fn test_player_buys_from_armor_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -259,30 +260,23 @@ async fn test_player_buys_from_armor_shop() { async fn test_player_sells_3_attr_weapon_to_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 5, - special: Some(item::weapon::WeaponSpecial::Charge), - attrs: [Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Hit, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Native, value: 100}),], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .grind(5) + .special(item::weapon::WeaponSpecial::Charge) + .attr(item::weapon::Attribute::Hit, 100) + .attr(item::weapon::Attribute::Dark, 100) + .attr(item::weapon::Attribute::Native, 100) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -303,15 +297,15 @@ async fn test_player_sells_3_attr_weapon_to_shop() { async fn test_other_clients_see_purchase() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; char1.exp = 80000000; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -346,23 +340,19 @@ async fn test_other_clients_see_purchase() { async fn test_other_clients_see_stacked_purchase() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate - } - ), - }).await.unwrap(); - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap(); + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -397,11 +387,9 @@ async fn test_other_clients_see_stacked_purchase() { async fn test_buying_item_without_enough_mseseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Normal).await; @@ -432,14 +420,14 @@ async fn test_buying_item_without_enough_mseseta() { async fn test_player_double_buys_from_tool_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -497,14 +485,14 @@ async fn test_player_double_buys_from_tool_shop() { async fn test_techs_disappear_from_shop_when_bought() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -559,14 +547,14 @@ async fn test_techs_disappear_from_shop_when_bought() { async fn test_units_disappear_from_shop_when_bought() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -620,30 +608,24 @@ async fn test_units_disappear_from_shop_when_bought() { async fn test_player_sells_untekked_weapon() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 5, - special: Some(item::weapon::WeaponSpecial::Charge), - attrs: [Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Hit, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Native, value: 100}),], - tekked: false, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .untekked() + .grind(5) + .special(item::weapon::WeaponSpecial::Charge) + .attr(item::weapon::Attribute::Hit, 100) + .attr(item::weapon::Attribute::Dark, 100) + .attr(item::weapon::Attribute::Native, 100) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -664,30 +646,22 @@ async fn test_player_sells_untekked_weapon() { async fn test_player_sells_rare_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::DarkFlow, - grind: 5, - special: None, - attrs: [Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Hit, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Native, value: 100}),], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::DarkFlow) + .grind(5) + .attr(item::weapon::Attribute::Hit, 100) + .attr(item::weapon::Attribute::Dark, 100) + .attr(item::weapon::Attribute::Native, 100) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -708,29 +682,23 @@ async fn test_player_sells_rare_item() { async fn test_player_sells_partial_photon_drop_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); let mut photon_drops = Vec::new(); for _ in 0..7usize { photon_drops.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::PhotonDrop, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::PhotonDrop) + .as_new() + ).await.unwrap()); } p1_inv.push(item::InventoryItemEntity::Stacked(photon_drops)); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -751,27 +719,18 @@ async fn test_player_sells_partial_photon_drop_stack() { async fn test_player_sells_basic_frame() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor { - armor: item::armor::ArmorType::Frame, - dfp: 0, - evp: 0, - slots: 0, - } - ), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -792,27 +751,21 @@ async fn test_player_sells_basic_frame() { async fn test_player_sells_max_frame() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor { - armor: item::armor::ArmorType::Frame, - dfp: 2, - evp: 2, - slots: 4, - } - ), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .dfp(2) + .evp(2) + .slots(4) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -833,26 +786,18 @@ async fn test_player_sells_max_frame() { async fn test_player_sells_basic_barrier() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Shield( - item::shield::Shield { - shield: item::shield::ShieldType::Barrier, - dfp: 0, - evp: 0, - } - ), - }).await.unwrap()); + ItemBuilder::shield(item::shield::ShieldType::Barrier) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -873,26 +818,20 @@ async fn test_player_sells_basic_barrier() { async fn test_player_sells_max_barrier() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Shield( - item::shield::Shield { - shield: item::shield::ShieldType::Barrier, - dfp: 5, - evp: 5, - } - ), - }).await.unwrap()); + ItemBuilder::shield(item::shield::ShieldType::Barrier) + .dfp(5) + .evp(5) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -913,25 +852,19 @@ async fn test_player_sells_max_barrier() { async fn test_player_sells_1_star_minusminus_unit() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit { - unit: item::unit::UnitType::PriestMind, - modifier: Some(item::unit::UnitModifier::MinusMinus), - } - ), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::PriestMind) + .modifier(item::unit::UnitModifier::MinusMinus) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -952,25 +885,19 @@ async fn test_player_sells_1_star_minusminus_unit() { async fn test_player_sells_5_star_plusplus_unit() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit { - unit: item::unit::UnitType::GeneralHp, - modifier: Some(item::unit::UnitModifier::PlusPlus), - } - ), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::GeneralHp) + .modifier(item::unit::UnitModifier::PlusPlus) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -991,27 +918,21 @@ async fn test_player_sells_5_star_plusplus_unit() { async fn test_player_sells_rare_frame() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor { - armor: item::armor::ArmorType::StinkFrame, - dfp: 10, - evp: 20, - slots: 3, - } - ), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::StinkFrame) + .dfp(10) + .evp(20) + .slots(3) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1032,26 +953,20 @@ async fn test_player_sells_rare_frame() { async fn test_player_sells_rare_barrier() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Shield( - item::shield::Shield { - shield: item::shield::ShieldType::RedRing, - dfp: 10, - evp: 20, - } - ), - }).await.unwrap()); + ItemBuilder::shield(item::shield::ShieldType::RedRing) + .dfp(10) + .evp(20) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1072,25 +987,18 @@ async fn test_player_sells_rare_barrier() { async fn test_player_sells_rare_unit() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit { - unit: item::unit::UnitType::V101, - modifier: None, - } - ), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::V101) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1111,26 +1019,19 @@ async fn test_player_sells_rare_unit() { async fn test_player_cant_sell_if_meseta_would_go_over_max() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999995)).await.unwrap(); let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit { - unit: item::unit::UnitType::V101, - modifier: None, - } - ), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::V101) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; diff --git a/tests/test_trade.rs b/tests/test_trade.rs index 4155a46..8266892 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -1,10 +1,10 @@ use std::convert::TryInto; -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; -use elseware::entity::item::{Meseta, ItemEntity}; -use elseware::ship::packet::handler::trade::TradeError; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::{ShipServerState, RecvShipPacket, SendShipPacket}; +use entity::item::{Meseta, ItemEntity, InventoryItemEntity}; +use ship_server::trade::TradeError; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -62,7 +62,7 @@ struct TradeItemBuilder { } impl TradeItemBuilder { - fn individual(mut self, item: &elseware::entity::item::InventoryItemEntity, item_id: u32) -> Self { + fn individual(mut self, item: &InventoryItemEntity, item_id: u32) -> Self { let idata = item.with_individual(|i| i.item.as_client_bytes()).unwrap(); self.items[self.count] = TradeItem { item_data: idata[0..12].try_into().unwrap(), @@ -74,7 +74,7 @@ impl TradeItemBuilder { self } - fn stacked(mut self, item: &elseware::entity::item::InventoryItemEntity, item_id: u32, amount: u8) -> Self { + fn stacked(mut self, item: &InventoryItemEntity, item_id: u32, amount: u8) -> Self { let idata = item .with_stacked(|i| i[0].item.tool().unwrap().as_stacked_bytes(i.len())) .map(|mut data| { @@ -113,29 +113,19 @@ impl TradeItemBuilder { async fn test_trade_one_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -214,29 +204,19 @@ async fn test_trade_one_individual_item() { async fn test_trade_player2_to_player1() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p2_inv = Vec::new(); p2_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -315,29 +295,19 @@ async fn test_trade_player2_to_player1() { async fn test_reverse_trade_ack_order() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -416,20 +386,16 @@ async fn test_reverse_trade_ack_order() { async fn test_trade_one_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -439,9 +405,7 @@ async fn test_trade_one_stacked_item() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -520,20 +484,16 @@ async fn test_trade_one_stacked_item() { async fn test_trade_partial_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -543,9 +503,7 @@ async fn test_trade_partial_stacked_item() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -627,42 +585,24 @@ async fn test_trade_partial_stacked_item() { async fn test_trade_individual_both() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()]; + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()]; let p2_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()]; + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -792,20 +732,16 @@ async fn test_trade_individual_both() { async fn test_trade_stacked_both() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -816,13 +752,9 @@ async fn test_trade_stacked_both() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -832,9 +764,7 @@ async fn test_trade_stacked_both() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -962,20 +892,16 @@ async fn test_trade_stacked_both() { async fn test_trade_partial_stack_both() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -986,13 +912,9 @@ async fn test_trade_partial_stack_both() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -1002,9 +924,7 @@ async fn test_trade_partial_stack_both() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1138,20 +1058,16 @@ async fn test_trade_partial_stack_both() { async fn test_trade_same_stacked_item_to_eachother() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..3).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1162,13 +1078,9 @@ async fn test_trade_same_stacked_item_to_eachother() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1178,9 +1090,7 @@ async fn test_trade_same_stacked_item_to_eachother() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1310,20 +1220,16 @@ async fn test_trade_same_stacked_item_to_eachother() { async fn test_trade_stacked_when_already_have_partial_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..3).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1334,13 +1240,9 @@ async fn test_trade_stacked_when_already_have_partial_stack() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1350,9 +1252,7 @@ async fn test_trade_stacked_when_already_have_partial_stack() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1450,34 +1350,22 @@ async fn test_trade_stacked_when_already_have_partial_stack() { async fn test_trade_individual_for_stacked() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()]; + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()]; let p2_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1487,9 +1375,7 @@ async fn test_trade_individual_for_stacked() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1620,68 +1506,34 @@ async fn test_trade_individual_for_stacked() { async fn test_trade_multiple_individual() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Buster, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Buster) + .as_new() + ).await.unwrap(), ]; let p2_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Autogun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Autogun) + .as_new() + ).await.unwrap(), ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1878,20 +1730,16 @@ async fn test_trade_multiple_individual() { async fn test_trade_multiple_stacked() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack1 = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1901,13 +1749,9 @@ async fn test_trade_multiple_stacked() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Dimate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Dimate) + .as_new() + ).await }})) .await .into_iter() @@ -1918,13 +1762,9 @@ async fn test_trade_multiple_stacked() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -1934,13 +1774,9 @@ async fn test_trade_multiple_stacked() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Difluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Difluid) + .as_new() + ).await }})) .await .into_iter() @@ -1950,9 +1786,7 @@ async fn test_trade_multiple_stacked() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack1, p2_stack2])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2145,24 +1979,15 @@ async fn test_trade_multiple_stacked() { async fn test_trade_not_enough_inventory_space_individual() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_inv = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -2174,17 +1999,8 @@ async fn test_trade_not_enough_inventory_space_individual() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -2195,9 +2011,7 @@ async fn test_trade_not_enough_inventory_space_individual() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2268,20 +2082,16 @@ async fn test_trade_not_enough_inventory_space_individual() { async fn test_trade_not_enough_inventory_space_stacked() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -2292,17 +2102,8 @@ async fn test_trade_not_enough_inventory_space_stacked() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -2313,9 +2114,7 @@ async fn test_trade_not_enough_inventory_space_stacked() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2385,20 +2184,16 @@ async fn test_trade_not_enough_inventory_space_stacked() { async fn test_trade_stack_too_big() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..8).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -2409,13 +2204,9 @@ async fn test_trade_stack_too_big() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -2425,9 +2216,7 @@ async fn test_trade_stack_too_big() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2501,14 +2290,12 @@ async fn test_trade_stack_too_big() { async fn test_trade_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; entity_gateway.set_character_meseta(&char1.id, Meseta(2323)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2582,15 +2369,13 @@ async fn test_trade_meseta() { async fn test_trade_too_much_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2634,15 +2419,13 @@ async fn test_trade_too_much_meseta() { async fn test_trade_invalid_amount_of_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2686,15 +2469,13 @@ async fn test_trade_invalid_amount_of_meseta() { async fn test_trade_meseta_request_and_items_dont_match() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2738,12 +2519,10 @@ async fn test_trade_meseta_request_and_items_dont_match() { async fn test_player_declined_trade() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2769,29 +2548,19 @@ async fn test_player_declined_trade() { async fn test_back_out_of_trade_last_minute() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2835,24 +2604,15 @@ async fn test_back_out_of_trade_last_minute() { async fn test_valid_trade_when_both_inventories_are_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_inv = futures::future::join_all((0..30).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() ).await }})) .await @@ -2864,17 +2624,8 @@ async fn test_valid_trade_when_both_inventories_are_full() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -2885,9 +2636,7 @@ async fn test_valid_trade_when_both_inventories_are_full() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2977,24 +2726,15 @@ async fn test_valid_trade_when_both_inventories_are_full() { async fn test_invalid_trade_when_both_inventories_are_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_inv = futures::future::join_all((0..30).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() ).await }})) .await @@ -3006,17 +2746,8 @@ async fn test_invalid_trade_when_both_inventories_are_full() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -3027,9 +2758,7 @@ async fn test_invalid_trade_when_both_inventories_are_full() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3129,13 +2858,11 @@ async fn test_invalid_trade_when_both_inventories_are_full() { async fn test_client_tries_to_start_two_trades() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let (_user2, _char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).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, _char3) = new_user_character(&mut entity_gateway, "a3", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; log_in_char(&mut ship, ClientId(3), "a3", "a").await; @@ -3162,13 +2889,11 @@ async fn test_client_tries_to_start_two_trades() { async fn test_client_tries_trading_with_client_already_trading() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let (_user2, _char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).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, _char3) = new_user_character(&mut entity_gateway, "a3", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; log_in_char(&mut ship, ClientId(3), "a3", "a").await; @@ -3201,31 +2926,21 @@ async fn test_client_tries_trading_with_client_already_trading() { async fn test_add_then_remove_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); for _ in 0..2 { p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3314,20 +3029,16 @@ async fn test_add_then_remove_individual_item() { async fn test_add_then_remove_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack1 = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -3338,13 +3049,9 @@ async fn test_add_then_remove_stacked_item() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -3354,9 +3061,7 @@ async fn test_add_then_remove_stacked_item() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3449,20 +3154,16 @@ async fn test_add_then_remove_stacked_item() { async fn test_add_then_remove_partial_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack1 = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -3473,13 +3174,9 @@ async fn test_add_then_remove_partial_stack() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -3489,9 +3186,7 @@ async fn test_add_then_remove_partial_stack() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3573,14 +3268,12 @@ async fn test_add_then_remove_partial_stack() { async fn test_add_then_remove_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; entity_gateway.set_character_meseta(&char1.id, Meseta(2323)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3659,29 +3352,19 @@ async fn test_add_then_remove_meseta() { async fn test_items_to_trade_data_does_not_match() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3742,29 +3425,19 @@ async fn test_items_to_trade_data_does_not_match() { async fn test_items_to_trade_id_does_not_match() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3813,20 +3486,16 @@ async fn test_items_to_trade_id_does_not_match() { async fn test_stack_is_same_amount_in_request_and_items_to_trade() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -3836,9 +3505,7 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3887,20 +3554,16 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade() { async fn test_stack_is_same_amount_in_request_and_items_to_trade2() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -3910,9 +3573,7 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade2() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3961,54 +3622,28 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade2() { async fn test_items_to_trade_count_less_than() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Brand, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Brand) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Buster, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Buster) + .as_new() + ).await.unwrap(), ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -4063,56 +3698,30 @@ async fn test_items_to_trade_count_less_than() { async fn test_items_to_trade_count_greater_than() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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; entity_gateway.set_character_meseta(&char1.id, Meseta(23)).await.unwrap(); let p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Brand, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Brand) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Buster, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Buster) + .as_new() + ).await.unwrap(), ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -4173,54 +3782,28 @@ async fn test_items_to_trade_count_greater_than() { async fn test_items_to_trade_count_mismatch_with_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Brand, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Brand) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Buster, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Buster) + .as_new() + ).await.unwrap(), ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -4275,29 +3858,19 @@ async fn test_items_to_trade_count_mismatch_with_meseta() { async fn test_dropping_item_after_trade() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).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 mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await;