From 16041640c274363de8288c8cf34b89eff2584187 Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 13:35:16 -0700 Subject: [PATCH 01/29] get elseware to compile on latest rust --- src/lib.rs | 5 ++--- src/ship/items/floor.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2c3d9c0..54fc603 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,11 @@ #![allow(clippy::type_complexity)] #![allow(incomplete_features)] #![feature(inline_const)] -#![feature(drain_filter)] +#![feature(extract_if)] #![feature(try_blocks)] -#![feature(once_cell)] #![feature(test)] #![feature(error_generic_member_access)] -#![feature(provide_any)] +#![feature(lazy_cell)] extern crate test; diff --git a/src/ship/items/floor.rs b/src/ship/items/floor.rs index c71b7fd..b0e968f 100644 --- a/src/ship/items/floor.rs +++ b/src/ship/items/floor.rs @@ -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() From 622c6e598d949783acd448623f17a013e5ac2e4f Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 21:37:23 -0700 Subject: [PATCH 02/29] break out entity and maps into separate crates --- Cargo.toml | 48 +++- common/Cargo.toml | 8 + common/src/lib.rs | 0 entity/Cargo.toml | 57 +++++ {src/entity => entity/src}/account.rs | 0 {src/entity => entity/src}/character.rs | 4 +- .../src}/gateway/entitygateway.rs | 8 +- .../entity => entity/src}/gateway/inmemory.rs | 10 +- {src/entity => entity/src}/gateway/mod.rs | 0 .../postgres/migrations/V0001__initial.sql | 0 .../postgres/migrations/V0002__equips.sql | 0 .../postgres/migrations/V0003__item_notes.sql | 0 .../postgres/migrations/V0004__meseta.sql | 0 .../postgres/migrations/V0005__trade.sql | 0 .../postgres/migrations/V0006__playtime.sql | 0 .../migrations/V0007__player_keyconfig.sql | 0 .../migrations/V0008__playtime_not_null.sql | 0 .../migrations/V0009__no_player_keyconfig.sql | 0 .../V0010__char_create_timestamp.sql | 0 .../migrations/V0011__shared_bank.sql | 0 .../postgres/migrations/V0012__room.sql | 0 .../postgres/migrations/V0013__room2.sql | 0 entity/src/gateway/postgres/migrations/mod.rs | 3 + .../src}/gateway/postgres/mod.rs | 0 .../src}/gateway/postgres/models.rs | 14 +- .../src}/gateway/postgres/postgres.rs | 14 +- {src/entity => entity/src}/item/armor.rs | 2 +- {src/entity => entity/src}/item/esweapon.rs | 0 {src/entity => entity/src}/item/mag.rs | 8 +- {src/entity => entity/src}/item/mod.rs | 30 +-- {src/entity => entity/src}/item/shield.rs | 0 {src/entity => entity/src}/item/tech.rs | 0 {src/entity => entity/src}/item/tool.rs | 0 {src/entity => entity/src}/item/unit.rs | 0 {src/entity => entity/src}/item/weapon.rs | 2 +- src/entity/mod.rs => entity/src/lib.rs | 0 {src/entity => entity/src}/room.rs | 4 +- entity/src/team.rs | 31 +++ maps/Cargo.toml | 15 ++ {src/ship/map => maps/src}/area.rs | 2 +- {src/ship/map => maps/src}/enemy.rs | 43 ++-- maps/src/lib.rs | 7 + {src/ship/map => maps/src}/maps.rs | 18 +- maps/src/monster.rs | 212 ++++++++++++++++++ {src/ship/map => maps/src}/object.rs | 8 +- maps/src/room.rs | 150 +++++++++++++ {src/ship/map => maps/src}/variant.rs | 3 +- networking/Cargo.toml | 4 + networking/src/lib.rs | 0 src/bin/login.rs | 2 +- src/bin/main.rs | 10 +- src/bin/ship.rs | 2 +- src/common/interserver.rs | 4 +- src/common/leveltable.rs | 2 +- src/common/mainloop/interserver.rs | 3 +- src/entity/gateway/postgres/migrations/mod.rs | 3 - src/lib.rs | 2 +- src/login/character.rs | 44 ++-- src/login/login.rs | 29 +-- src/ship/character.rs | 4 +- src/ship/chatcommand.rs | 4 +- src/ship/client.rs | 8 +- src/ship/drops/box_drop_table.rs | 12 +- src/ship/drops/generic_armor.rs | 10 +- src/ship/drops/generic_shield.rs | 10 +- src/ship/drops/generic_unit.rs | 10 +- src/ship/drops/generic_weapon.rs | 10 +- src/ship/drops/mod.rs | 46 ++-- src/ship/drops/rare_drop_table.rs | 20 +- src/ship/drops/tech_table.rs | 8 +- src/ship/drops/tool_table.rs | 12 +- src/ship/item_stats.rs | 14 +- src/ship/items/actions.rs | 16 +- src/ship/items/apply_item.rs | 14 +- src/ship/items/bank.rs | 6 +- src/ship/items/floor.rs | 8 +- src/ship/items/inventory.rs | 10 +- src/ship/items/state.rs | 12 +- src/ship/items/tasks.rs | 14 +- src/ship/map/mod.rs | 12 - src/ship/mod.rs | 4 +- src/ship/packet/builder/message.rs | 2 +- src/ship/packet/handler/auth.rs | 2 +- src/ship/packet/handler/communication.rs | 2 +- src/ship/packet/handler/direct_message.rs | 4 +- src/ship/packet/handler/lobby.rs | 6 +- src/ship/packet/handler/message.rs | 4 +- src/ship/packet/handler/quest.rs | 4 +- src/ship/packet/handler/room.rs | 24 +- src/ship/packet/handler/settings.rs | 2 +- src/ship/packet/handler/trade.rs | 4 +- src/ship/quests.rs | 11 +- src/ship/room.rs | 168 +------------- src/ship/ship.rs | 143 ++++++------ src/ship/shops/armor.rs | 8 +- src/ship/shops/mod.rs | 2 +- src/ship/shops/tool.rs | 6 +- src/ship/shops/weapon.rs | 8 +- tests/common.rs | 12 +- tests/test_bank.rs | 4 +- tests/test_character.rs | 2 +- tests/test_exp_gain.rs | 12 +- tests/test_item_actions.rs | 4 +- tests/test_item_drop.rs | 15 +- tests/test_item_id.rs | 6 +- tests/test_item_pickup.rs | 4 +- tests/test_item_use.rs | 6 +- tests/test_mags.rs | 6 +- tests/test_rooms.rs | 4 +- tests/test_shops.rs | 6 +- tests/test_trade.rs | 10 +- 111 files changed, 989 insertions(+), 572 deletions(-) create mode 100644 common/Cargo.toml create mode 100644 common/src/lib.rs create mode 100644 entity/Cargo.toml rename {src/entity => entity/src}/account.rs (100%) rename {src/entity => entity/src}/character.rs (98%) rename {src/entity => entity/src}/gateway/entitygateway.rs (98%) rename {src/entity => entity/src}/gateway/inmemory.rs (99%) rename {src/entity => entity/src}/gateway/mod.rs (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0001__initial.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0002__equips.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0003__item_notes.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0004__meseta.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0005__trade.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0006__playtime.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0007__player_keyconfig.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0008__playtime_not_null.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0009__no_player_keyconfig.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0010__char_create_timestamp.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0011__shared_bank.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0012__room.sql (100%) rename {src/entity => entity/src}/gateway/postgres/migrations/V0013__room2.sql (100%) create mode 100644 entity/src/gateway/postgres/migrations/mod.rs rename {src/entity => entity/src}/gateway/postgres/mod.rs (100%) rename {src/entity => entity/src}/gateway/postgres/models.rs (99%) rename {src/entity => entity/src}/gateway/postgres/postgres.rs (99%) rename {src/entity => entity/src}/item/armor.rs (99%) rename {src/entity => entity/src}/item/esweapon.rs (100%) rename {src/entity => entity/src}/item/mag.rs (99%) rename {src/entity => entity/src}/item/mod.rs (84%) rename {src/entity => entity/src}/item/shield.rs (100%) rename {src/entity => entity/src}/item/tech.rs (100%) rename {src/entity => entity/src}/item/tool.rs (100%) rename {src/entity => entity/src}/item/unit.rs (100%) rename {src/entity => entity/src}/item/weapon.rs (99%) rename src/entity/mod.rs => entity/src/lib.rs (100%) rename {src/entity => entity/src}/room.rs (93%) create mode 100644 entity/src/team.rs create mode 100644 maps/Cargo.toml rename {src/ship/map => maps/src}/area.rs (99%) rename {src/ship/map => maps/src}/enemy.rs (93%) create mode 100644 maps/src/lib.rs rename {src/ship/map => maps/src}/maps.rs (97%) create mode 100644 maps/src/monster.rs rename {src/ship/map => maps/src}/object.rs (98%) create mode 100644 maps/src/room.rs rename {src/ship/map => maps/src}/variant.rs (99%) create mode 100644 networking/Cargo.toml create mode 100644 networking/src/lib.rs delete mode 100644 src/entity/gateway/postgres/migrations/mod.rs delete mode 100644 src/ship/map/mod.rs diff --git a/Cargo.toml b/Cargo.toml index c2e511d..7561e6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,20 @@ version = "0.1.0" authors = ["Jake Probst "] edition = "2021" -[dependencies] +[workspace] +members = [ + "entity", + "maps", + "common", + "networking", +] + +[workspace.dependencies] libpso = { git = "http://git.sharnoth.com/jake/libpso" } +entity = { path = "./entity" } +maps = { path = "./maps" } +common = { path = "./common" } +networking = { path = "./networking" } async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" rand = "0.7.3" @@ -33,3 +45,37 @@ sqlx = { version = "0.6.2", features = ["runtime-async-std-native-tls", "postgre strum = "0.19.5" strum_macros = "0.19" anyhow = { version = "1.0.68", features = ["backtrace"] } + +[dependencies] +libpso = { git = "http://git.sharnoth.com/jake/libpso" } +entity = { path = "./entity" } +maps = { path = "./maps" } +common = { path = "./common" } +networking = { path = "./networking" } +async-std = { version = "1.9.0", features = ["unstable", "attributes"] } +futures = "0.3.5" +rand = "0.7.3" +rand_chacha = "0.2.2" +crc = "^1.0.0" +bcrypt = "0.10" +chrono = { workspace = true } +serde = "*" +serde_json = "*" +ron = "*" +toml = "*" +log = "*" +fern = { version = "0.5", features = ["colored"] } +byteorder = "1" +enum-utils = "0.1.2" +derive_more = { version = "0.99.3", features = ["display"]} +thiserror = "1.0.37" +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 = { workspace = true } \ No newline at end of file diff --git a/common/Cargo.toml b/common/Cargo.toml new file mode 100644 index 0000000..552f659 --- /dev/null +++ b/common/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "common" +version = "0.1.0" +edition = "2021" + + +[dependencies] +derive_more = { workspace = true } \ No newline at end of file diff --git a/common/src/lib.rs b/common/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/entity/Cargo.toml b/entity/Cargo.toml new file mode 100644 index 0000000..6603cbb --- /dev/null +++ b/entity/Cargo.toml @@ -0,0 +1,57 @@ +[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 } + + +#libpso = { git = "http://git.sharnoth.com/jake/libpso" } +#async-std = { version = "1.9.0", features = ["unstable", "attributes"] } +#futures = "0.3.5" +#rand = "0.7.3" +#rand_chacha = "0.2.2" +#crc = "^1.0.0" +#bcrypt = "0.10" +#chrono = "0.4.11" +#serde = "*" +#serde_json = "*" +#ron = "*" +#toml = "*" +#log = "*" +#fern = { version = "0.5", features = ["colored"] } +#byteorder = "1" +#enum-utils = "0.1.2" +#derive_more = { version = "0.99.3", features = ["display"]} +#thiserror = "1.0.37" +#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"] } + +#[lib] +#name = "entity" +#path = "lib.rs" \ No newline at end of file diff --git a/src/entity/account.rs b/entity/src/account.rs similarity index 100% rename from src/entity/account.rs rename to entity/src/account.rs diff --git a/src/entity/character.rs b/entity/src/character.rs similarity index 98% rename from src/entity/character.rs rename to entity/src/character.rs index 080bb1b..643e009 100644 --- a/src/entity/character.rs +++ b/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 { diff --git a/src/entity/gateway/entitygateway.rs b/entity/src/gateway/entitygateway.rs similarity index 98% rename from src/entity/gateway/entitygateway.rs rename to entity/src/gateway/entitygateway.rs index df922ac..4f7ae67 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/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/entity/src/gateway/inmemory.rs similarity index 99% rename from src/entity/gateway/inmemory.rs rename to entity/src/gateway/inmemory.rs index 50a650e..970beed 100644 --- a/src/entity/gateway/inmemory.rs +++ b/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/entity/src/gateway/mod.rs similarity index 100% rename from src/entity/gateway/mod.rs rename to entity/src/gateway/mod.rs diff --git a/src/entity/gateway/postgres/migrations/V0001__initial.sql b/entity/src/gateway/postgres/migrations/V0001__initial.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0001__initial.sql rename to entity/src/gateway/postgres/migrations/V0001__initial.sql diff --git a/src/entity/gateway/postgres/migrations/V0002__equips.sql b/entity/src/gateway/postgres/migrations/V0002__equips.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0002__equips.sql rename to entity/src/gateway/postgres/migrations/V0002__equips.sql diff --git a/src/entity/gateway/postgres/migrations/V0003__item_notes.sql b/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 entity/src/gateway/postgres/migrations/V0003__item_notes.sql diff --git a/src/entity/gateway/postgres/migrations/V0004__meseta.sql b/entity/src/gateway/postgres/migrations/V0004__meseta.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0004__meseta.sql rename to entity/src/gateway/postgres/migrations/V0004__meseta.sql diff --git a/src/entity/gateway/postgres/migrations/V0005__trade.sql b/entity/src/gateway/postgres/migrations/V0005__trade.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0005__trade.sql rename to entity/src/gateway/postgres/migrations/V0005__trade.sql diff --git a/src/entity/gateway/postgres/migrations/V0006__playtime.sql b/entity/src/gateway/postgres/migrations/V0006__playtime.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0006__playtime.sql rename to entity/src/gateway/postgres/migrations/V0006__playtime.sql diff --git a/src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql b/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 entity/src/gateway/postgres/migrations/V0007__player_keyconfig.sql diff --git a/src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql b/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 entity/src/gateway/postgres/migrations/V0008__playtime_not_null.sql diff --git a/src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql b/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 entity/src/gateway/postgres/migrations/V0009__no_player_keyconfig.sql diff --git a/src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql b/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 entity/src/gateway/postgres/migrations/V0010__char_create_timestamp.sql diff --git a/src/entity/gateway/postgres/migrations/V0011__shared_bank.sql b/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 entity/src/gateway/postgres/migrations/V0011__shared_bank.sql diff --git a/src/entity/gateway/postgres/migrations/V0012__room.sql b/entity/src/gateway/postgres/migrations/V0012__room.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0012__room.sql rename to entity/src/gateway/postgres/migrations/V0012__room.sql diff --git a/src/entity/gateway/postgres/migrations/V0013__room2.sql b/entity/src/gateway/postgres/migrations/V0013__room2.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0013__room2.sql rename to entity/src/gateway/postgres/migrations/V0013__room2.sql diff --git a/entity/src/gateway/postgres/migrations/mod.rs b/entity/src/gateway/postgres/migrations/mod.rs new file mode 100644 index 0000000..fd67f6f --- /dev/null +++ b/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/entity/src/gateway/postgres/mod.rs similarity index 100% rename from src/entity/gateway/postgres/mod.rs rename to entity/src/gateway/postgres/mod.rs diff --git a/src/entity/gateway/postgres/models.rs b/entity/src/gateway/postgres/models.rs similarity index 99% rename from src/entity/gateway/postgres/models.rs rename to entity/src/gateway/postgres/models.rs index f3a2f39..13c2a6b 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/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 { diff --git a/src/entity/gateway/postgres/postgres.rs b/entity/src/gateway/postgres/postgres.rs similarity index 99% rename from src/entity/gateway/postgres/postgres.rs rename to entity/src/gateway/postgres/postgres.rs index c31217f..f1219ba 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/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/entity/src/item/armor.rs similarity index 99% rename from src/entity/item/armor.rs rename to entity/src/item/armor.rs index 45e9ed4..bd0cc48 100644 --- a/src/entity/item/armor.rs +++ b/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/entity/src/item/esweapon.rs similarity index 100% rename from src/entity/item/esweapon.rs rename to entity/src/item/esweapon.rs diff --git a/src/entity/item/mag.rs b/entity/src/item/mag.rs similarity index 99% rename from src/entity/item/mag.rs rename to entity/src/item/mag.rs index 17fa1b4..45d424a 100644 --- a/src/entity/item/mag.rs +++ b/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/entity/src/item/mod.rs similarity index 84% rename from src/entity/item/mod.rs rename to entity/src/item/mod.rs index 7023f7c..d418579 100644 --- a/src/entity/item/mod.rs +++ b/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/entity/src/item/shield.rs similarity index 100% rename from src/entity/item/shield.rs rename to entity/src/item/shield.rs diff --git a/src/entity/item/tech.rs b/entity/src/item/tech.rs similarity index 100% rename from src/entity/item/tech.rs rename to entity/src/item/tech.rs diff --git a/src/entity/item/tool.rs b/entity/src/item/tool.rs similarity index 100% rename from src/entity/item/tool.rs rename to entity/src/item/tool.rs diff --git a/src/entity/item/unit.rs b/entity/src/item/unit.rs similarity index 100% rename from src/entity/item/unit.rs rename to entity/src/item/unit.rs diff --git a/src/entity/item/weapon.rs b/entity/src/item/weapon.rs similarity index 99% rename from src/entity/item/weapon.rs rename to entity/src/item/weapon.rs index 29a9357..a5753d6 100644 --- a/src/entity/item/weapon.rs +++ b/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/entity/src/lib.rs similarity index 100% rename from src/entity/mod.rs rename to entity/src/lib.rs diff --git a/src/entity/room.rs b/entity/src/room.rs similarity index 93% rename from src/entity/room.rs rename to entity/src/room.rs index a5eeea4..30d3b6b 100644 --- a/src/entity/room.rs +++ b/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/entity/src/team.rs b/entity/src/team.rs new file mode 100644 index 0000000..2a5bfac --- /dev/null +++ b/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/maps/Cargo.toml b/maps/Cargo.toml new file mode 100644 index 0000000..cf0401e --- /dev/null +++ b/maps/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "maps" +version = "0.1.0" +edition = "2021" + +[dependencies] +common = { workspace = true } +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/maps/src/area.rs similarity index 99% rename from src/ship/map/area.rs rename to maps/src/area.rs index 02361c3..bb64737 100644 --- a/src/ship/map/area.rs +++ b/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/maps/src/enemy.rs similarity index 93% rename from src/ship/map/enemy.rs rename to maps/src/enemy.rs index 4989041..08e0f61 100644 --- a/src/ship/map/enemy.rs +++ b/maps/src/enemy.rs @@ -1,19 +1,24 @@ // 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::area::{MapArea, MapAreaError}; +use crate::room::Episode; +use crate::monster::MonsterType; + +#[derive(Clone, Copy)] +pub enum RareEnemyEvent { + Easter, + Halloween, + Christmas, +} #[derive(Debug, Copy, Clone)] pub struct RawMapEnemy { @@ -69,6 +74,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); + toml::from_str::(s.as_str()).unwrap() +} + #[derive(Error, Debug)] #[error("")] pub enum MapEnemyError { @@ -76,6 +92,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 +120,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: Option) -> MapEnemy { if enemy.can_be_rare() && self.roll_is_rare(&enemy.monster) { enemy.into_rare(event) } @@ -345,12 +362,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: Option) -> 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, Some(RareEnemyEvent::Easter)) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}}, + (MonsterType::RagRappy, Episode::Two, Some(RareEnemyEvent::Halloween)) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}}, + (MonsterType::RagRappy, Episode::Two, Some(RareEnemyEvent::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/maps/src/lib.rs b/maps/src/lib.rs new file mode 100644 index 0000000..fa2b60e --- /dev/null +++ b/maps/src/lib.rs @@ -0,0 +1,7 @@ +pub mod area; +pub mod enemy; +pub mod object; +pub mod variant; +pub mod maps; +pub mod monster; +pub mod room; diff --git a/src/ship/map/maps.rs b/maps/src/maps.rs similarity index 97% rename from src/ship/map/maps.rs rename to maps/src/maps.rs index 05c7e29..6684d52 100644 --- a/src/ship/map/maps.rs +++ b/maps/src/maps.rs @@ -6,14 +6,14 @@ 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::enemy::{MapEnemy, RawMapEnemy, RareEnemyEvent, 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 +325,7 @@ impl Maps { enemies: Vec>, objects: Vec>, rare_monster_table: &RareMonsterAppearTable, - event: ShipEvent) + event: Option) { self.enemy_data = enemies .into_iter() @@ -358,7 +358,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: Option) -> Maps { let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); let map_variants = default_map_variants(room_mode.episode(), room_mode.player_mode()); Maps { diff --git a/maps/src/monster.rs b/maps/src/monster.rs new file mode 100644 index 0000000..a72288d --- /dev/null +++ b/maps/src/monster.rs @@ -0,0 +1,212 @@ +#![allow(dead_code)] +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use std::path::PathBuf; +use serde::{Serialize, Deserialize}; +use crate::room::{Difficulty, Episode, RoomMode}; + + +#[derive(Debug)] +pub enum MonsterParseError { + UnknownMonster(String), +} + +pub struct MonsterStatError; + +#[derive(Debug, Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, enum_utils::FromStr, derive_more::Display)] +pub enum MonsterType { + Hildebear, + Hildeblue, + Mothmant, + Monest, + RagRappy, + AlRappy, + SavageWolf, + BarbarousWolf, + Booma, + Gobooma, + Gigobooma, + GrassAssassin, + PoisonLily, + NarLily, + NanoDragon, + EvilShark, + PalShark, + GuilShark, + PofuillySlime, + PouillySlime, + PanArms, + Hidoom, + Migium, + Dubchic, + Garanz, + SinowBeat, + SinowGold, + Canadine, + Canane, + RingCanadine, + Delsaber, + ChaosSorcerer, + BeeR, + BeeL, + DarkGunner, + DeathGunner, + ChaosBringer, + DarkBelra, + Claw, + Bulk, + Bulclaw, + Dimenian, + LaDimenian, + SoDimenian, + Dragon, + DeRolLe, + DeRolLeBody, + DeRolLeMine, + VolOptPartA, + VolOptPillar, + VolOptMonitor, + VolOptAmp, + VolOptCore, + VolOptUnused, + VolOpt, + VolOptTrap, + DarkFalz, + DarkFalz1, + DarkFalz2, + DarkFalz3, + Darvant, + UltDarvant, + Dubwitch, + Gillchic, + EventRappy, + Merillia, + Meriltas, + Gee, + GiGue, + Mericarol, + Merikle, + Mericus, + UlGibbon, + ZolGibbon, + Gibbles, + SinowBerill, + SinowSpigell, + Dolmolm, + Dolmdarl, + Morfos, + Recobox, + Recon, + SinowZoa, + SinowZele, + Deldepth, + Delbiter, + BarbaRay, + PigRay, + GolDragon, + GalGryphon, + OlgaFlow, + OlgaFlow1, + OlgaFlow2, + Gael, + Giel, + StRappy, + HalloRappy, + EasterRappy, + LoveRappy, + IllGill, + DelLily, + Epsilon, + Epsiguard, + Boota, + ZeBoota, + BaBoota, + SandRappyCrater, + SandRappyDesert, + ZuCrater, + PazuzuCrater, + Astark, + SatelliteLizardCrater, + YowieCrater, + Dorphon, + DorphonEclair, + Goran, + GoranDetonator, + PyroGoran, + DelRappyCrater, + DelRappyDesert, + MerissaA, + MerissaAA, + ZuDesert, + PazuzuDesert, + SatelliteLizardDesert, + YowieDesert, + Girtablulu, + SaintMillion, + Shambertin, + Kondrieu, +} + + +#[derive(Deserialize, Debug)] +pub struct MonsterStats { + pub atp: u16, + pub mst: u16, + pub evp: u16, + pub hp: u16, + pub dfp: u16, + pub ata: u16, + pub lck: u16, + pub esp: u16, + pub exp: u32, +} + +fn load_battle_param(filename: &str) -> HashMap { + let mut path = PathBuf::from("data/battle_param/"); + path.push(filename); + + 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() + .into_iter() + .map(|(monster_name, stats)| { + (monster_name.parse().unwrap(), stats) + }).collect() +} + +pub fn load_monster_stats_table(mode: &RoomMode) -> Result, MonsterStatError> { + match mode { + RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep1_multi_normal.toml")), + RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep1_multi_hard.toml")), + RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep1_multi_veryhard.toml")), + RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep1_multi_ultimate.toml")), + + RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep2_multi_normal.toml")), + RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep2_multi_hard.toml")), + RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep2_multi_veryhard.toml")), + RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep2_multi_ultimate.toml")), + + RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep4_multi_normal.toml")), + RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep4_multi_hard.toml")), + RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep4_multi_veryhard.toml")), + RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep4_multi_ultimate.toml")), + + RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep1_solo_normal.toml")), + RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep1_solo_hard.toml")), + RoomMode::Single {episode: Episode::One, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep1_solo_veryhard.toml")), + RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep1_solo_ultimate.toml")), + + RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep2_solo_normal.toml")), + RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep2_solo_hard.toml")), + RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep2_solo_veryhard.toml")), + RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep2_solo_ultimate.toml")), + + RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep4_solo_normal.toml")), + RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep4_solo_hard.toml")), + RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep4_solo_veryhard.toml")), + RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep4_solo_ultimate.toml")), + _ => Err(MonsterStatError), + } +} diff --git a/src/ship/map/object.rs b/maps/src/object.rs similarity index 98% rename from src/ship/map/object.rs rename to maps/src/object.rs index 81bce6a..0f73442 100644 --- a/src/ship/map/object.rs +++ b/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/maps/src/room.rs b/maps/src/room.rs new file mode 100644 index 0000000..8370e7c --- /dev/null +++ b/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/maps/src/variant.rs similarity index 99% rename from src/ship/map/variant.rs rename to maps/src/variant.rs index 0fa7c65..78fa4bf 100644 --- a/src/ship/map/variant.rs +++ b/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/networking/Cargo.toml b/networking/Cargo.toml new file mode 100644 index 0000000..b0ee8a2 --- /dev/null +++ b/networking/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "networking" +version = "0.1.0" +edition = "2021" diff --git a/networking/src/lib.rs b/networking/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/bin/login.rs b/src/bin/login.rs index f8b6b94..28d78f0 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -1,5 +1,5 @@ use log::{info}; -use elseware::entity::gateway::postgres::PostgresGateway; +use entity::gateway::postgres::PostgresGateway; use elseware::login::login::LoginServerState; use elseware::login::character::CharacterServerState; use elseware::common::interserver::AuthToken; diff --git a/src/bin/main.rs b/src/bin/main.rs index 0a3ada0..23aa720 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -8,11 +8,11 @@ use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, use elseware::ship::ship::{ShipServerStateBuilder, ShipEvent}; #[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 entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; +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() diff --git a/src/bin/ship.rs b/src/bin/ship.rs index ff1ccc6..0f289b7 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -1,5 +1,5 @@ use log::{info}; -use elseware::entity::gateway::postgres::PostgresGateway; +use entity::gateway::postgres::PostgresGateway; use elseware::ship::ship::ShipServerStateBuilder; use elseware::common::interserver::AuthToken; diff --git a/src/common/interserver.rs b/src/common/interserver.rs index 1f6e0ff..be49a9f 100644 --- a/src/common/interserver.rs +++ b/src/common/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/common/leveltable.rs b/src/common/leveltable.rs index 9fb1465..7b06966 100644 --- a/src/common/leveltable.rs +++ b/src/common/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/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs index dbe940d..d524952 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/common/mainloop/interserver.rs @@ -13,8 +13,7 @@ use crate::common::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 entity::gateway::entitygateway::EntityGateway; use async_std::channel; use std::fmt::Debug; 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/lib.rs b/src/lib.rs index 54fc603..3802b3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ extern crate test; pub mod common; -pub mod entity; +//pub mod entity; pub mod patch; pub mod login; pub mod ship; diff --git a/src/login/character.rs b/src/login/character.rs index f23beea..07969ef 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -12,8 +12,8 @@ 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}; @@ -21,15 +21,15 @@ use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipM 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 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::login::{get_login_status}; use crate::common::interserver::AuthToken; @@ -484,7 +484,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 +515,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? } @@ -834,9 +834,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 +858,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 +901,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/login.rs b/src/login/login.rs index b4fcad6..4b1433c 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -14,8 +14,8 @@ 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 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; @@ -178,8 +178,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 +204,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 +224,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 +283,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 +318,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 +368,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/ship/character.rs b/src/ship/character.rs index 348f8ac..afe73c6 100644 --- a/src/ship/character.rs +++ b/src/ship/character.rs @@ -1,10 +1,10 @@ use libpso::character::character; use crate::common::leveltable::CharacterStats; -use crate::entity::character::CharacterEntity; +use 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 entity::item::Meseta; #[derive(Default)] diff --git a/src/ship/chatcommand.rs b/src/ship/chatcommand.rs index 97d5054..7d2c643 100644 --- a/src/ship/chatcommand.rs +++ b/src/ship/chatcommand.rs @@ -1,10 +1,10 @@ use libpso::packet::ship::PlayerChat; -use crate::entity::gateway::EntityGateway; +use 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 entity::item::{BankName, BankIdentifier}; use crate::ship::packet::builder::message::bank_item_list; async fn default_bank<'a, EG>(id: ClientId, diff --git a/src/ship/client.rs b/src/ship/client.rs index 5495309..58f75f7 100644 --- a/src/ship/client.rs +++ b/src/ship/client.rs @@ -7,13 +7,13 @@ 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 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 maps::area::MapArea; use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; diff --git a/src/ship/drops/box_drop_table.rs b/src/ship/drops/box_drop_table.rs index f507d27..4ad1e60 100644 --- a/src/ship/drops/box_drop_table.rs +++ b/src/ship/drops/box_drop_table.rs @@ -2,18 +2,18 @@ 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 entity::character::SectionID; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::map::{MapObject, MapObjectType, FixedBoxDropType}; +use maps::object::{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::item::ItemDetail; #[derive(Debug, Serialize, Deserialize)] struct BoxDropRate { @@ -204,7 +204,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/ship/drops/generic_armor.rs index 2bf5895..80e4761 100644 --- a/src/ship/drops/generic_armor.rs +++ b/src/ship/drops/generic_armor.rs @@ -1,12 +1,12 @@ 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 entity::character::SectionID; +use entity::item::armor::{ArmorType, Armor}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; use crate::ship::drops::{ItemDropType, load_data_file}; use crate::ship::item_stats::{armor_stats, ArmorStats}; diff --git a/src/ship/drops/generic_shield.rs b/src/ship/drops/generic_shield.rs index 9eec585..fd5752e 100644 --- a/src/ship/drops/generic_shield.rs +++ b/src/ship/drops/generic_shield.rs @@ -1,12 +1,12 @@ 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 entity::item::shield::{ShieldType, Shield}; +use entity::character::SectionID; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; use crate::ship::drops::{ItemDropType, load_data_file}; use crate::ship::item_stats::{shield_stats, ShieldStats}; diff --git a/src/ship/drops/generic_unit.rs b/src/ship/drops/generic_unit.rs index 73bc4a6..137f7d0 100644 --- a/src/ship/drops/generic_unit.rs +++ b/src/ship/drops/generic_unit.rs @@ -1,12 +1,12 @@ 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 entity::character::SectionID; +use entity::item::unit::{UnitType, Unit, UnitModifier}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; use crate::ship::drops::{ItemDropType, load_data_file}; use crate::ship::item_stats::{unit_stats, UnitStats}; diff --git a/src/ship/drops/generic_weapon.rs b/src/ship/drops/generic_weapon.rs index d1fb2bb..38290e7 100644 --- a/src/ship/drops/generic_weapon.rs +++ b/src/ship/drops/generic_weapon.rs @@ -1,13 +1,13 @@ 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 entity::character::SectionID; +use entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; use crate::ship::drops::{ItemDropType, load_data_file}; diff --git a/src/ship/drops/mod.rs b/src/ship/drops/mod.rs index 5d8062c..5c228e0 100644 --- a/src/ship/drops/mod.rs +++ b/src/ship/drops/mod.rs @@ -22,10 +22,10 @@ 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 maps::monster::MonsterType; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; use crate::ship::drops::generic_weapon::GenericWeaponTable; use crate::ship::drops::generic_armor::GenericArmorTable; use crate::ship::drops::generic_shield::GenericShieldTable; @@ -33,8 +33,8 @@ 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::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 +55,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 +90,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, diff --git a/src/ship/drops/rare_drop_table.rs b/src/ship/drops/rare_drop_table.rs index 51151ba..0eb6cc8 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/ship/drops/rare_drop_table.rs @@ -1,16 +1,16 @@ 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 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::ship::drops::{ItemDropType, load_data_file}; use crate::ship::drops::generic_weapon::AttributeTable; use crate::ship::drops::generic_armor::GenericArmorTable; diff --git a/src/ship/drops/tech_table.rs b/src/ship/drops/tech_table.rs index 6e6396f..79bf095 100644 --- a/src/ship/drops/tech_table.rs +++ b/src/ship/drops/tech_table.rs @@ -3,10 +3,10 @@ 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 entity::item::tech::{Technique, TechniqueDisk}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; use crate::ship::drops::{ItemDropType, load_data_file}; diff --git a/src/ship/drops/tool_table.rs b/src/ship/drops/tool_table.rs index 69a14cd..0ce9e6d 100644 --- a/src/ship/drops/tool_table.rs +++ b/src/ship/drops/tool_table.rs @@ -1,12 +1,12 @@ -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 entity::item::tool::{Tool, ToolType}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; use crate::ship::drops::{ItemDropType, load_data_file}; use crate::ship::drops::tech_table::TechniqueTable; diff --git a/src/ship/item_stats.rs b/src/ship/item_stats.rs index 919c076..13d0855 100644 --- a/src/ship/item_stats.rs +++ b/src/ship/item_stats.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/ship/items/actions.rs b/src/ship/items/actions.rs index 0c06691..2359950 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/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 entity::item::{Meseta, ItemNote}; use async_std::sync::Arc; use std::future::Future; use futures::future::BoxFuture; @@ -9,12 +9,12 @@ 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 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::ship::ship::SendShipPacket; use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; use crate::ship::items::bank::{BankItem, BankItemDetail}; @@ -25,7 +25,7 @@ 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 maps::monster::MonsterType; pub enum TriggerCreateItem { Yes, diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index 4c1a636..9c7e3c2 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -4,13 +4,13 @@ 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 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::ship::items::state::ItemStateProxy; use crate::ship::items::inventory::InventoryItemDetail; diff --git a/src/ship/items/bank.rs b/src/ship/items/bank.rs index 73f0e10..f6d12cd 100644 --- a/src/ship/items/bank.rs +++ b/src/ship/items/bank.rs @@ -1,12 +1,12 @@ use std::cmp::Ordering; use libpso::character::character; use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity}; +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 entity::character::CharacterEntityId; +use entity::item::BankIdentifier; use crate::ship::items::state::ItemStateError; use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; diff --git a/src/ship/items/floor.rs b/src/ship/items/floor.rs index b0e968f..6d03133 100644 --- a/src/ship/items/floor.rs +++ b/src/ship/items/floor.rs @@ -1,10 +1,10 @@ use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemEntityId, ItemDetail}; +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}; diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index da131d8..ca0e51d 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -1,14 +1,14 @@ 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 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 entity::character::CharacterEntityId; +use entity::item::tool::ToolType; +use entity::item::mag::Mag; +use 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}; diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index 906762a..9058c05 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -4,12 +4,12 @@ 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 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 crate::ship::drops::ItemDrop; use crate::ship::items::ClientItemId; use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState}; diff --git a/src/ship/items/tasks.rs b/src/ship/items/tasks.rs index 0c3f948..f224f4c 100644 --- a/src/ship/items/tasks.rs +++ b/src/ship/items/tasks.rs @@ -1,13 +1,13 @@ use futures::future::BoxFuture; use crate::ship::items::ClientItemId; -use crate::entity::item::Meseta; +use 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 maps::area::MapArea; +use entity::character::{CharacterEntity, CharacterEntityId}; +use entity::gateway::{EntityGateway, EntityGatewayTransaction}; +use entity::item::ItemModifier; +use entity::room::RoomEntityId; use crate::ship::items::state::{ItemState, ItemStateProxy, IndividualItemDetail}; use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction}; use crate::ship::items::inventory::InventoryItem; @@ -16,7 +16,7 @@ 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 maps::monster::MonsterType; use crate::ship::items::actions; 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 index c58edb6..3978099 100644 --- a/src/ship/mod.rs +++ b/src/ship/mod.rs @@ -6,8 +6,8 @@ pub mod client; pub mod room; pub mod items; pub mod item_stats; -pub mod map; -pub mod monster; +//pub mod map; +//pub mod monster; pub mod drops; pub mod packet; pub mod quests; diff --git a/src/ship/packet/builder/message.rs b/src/ship/packet/builder/message.rs index ac60484..f83ebbd 100644 --- a/src/ship/packet/builder/message.rs +++ b/src/ship/packet/builder/message.rs @@ -1,6 +1,6 @@ use libpso::packet::messages::*; use libpso::packet::ship::*; -use crate::entity::item; +use entity::item; use crate::common::leveltable::CharacterStats; use crate::ship::ship::{ShipError}; use crate::ship::items::ClientItemId; diff --git a/src/ship/packet/handler/auth.rs b/src/ship/packet/handler/auth.rs index 698de75..bd0c846 100644 --- a/src/ship/packet/handler/auth.rs +++ b/src/ship/packet/handler/auth.rs @@ -3,7 +3,7 @@ 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 entity::gateway::EntityGateway; use crate::ship::items::state::ItemState; use crate::common::interserver::ShipMessage; diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs index c0ac3e5..2f7ef43 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship/packet/handler/communication.rs @@ -2,7 +2,7 @@ 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 entity::gateway::EntityGateway; use futures::future::join_all; diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 3c914e8..0886f79 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -10,8 +10,8 @@ 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 entity::gateway::EntityGateway; +use entity::item; use libpso::utf8_to_utf16_array; use crate::ship::packet::builder; use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem}; diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index d5506c4..ae95afb 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -7,9 +7,9 @@ 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 entity::gateway::EntityGateway; +use entity::room::RoomNote; +use maps::area::MapArea; use futures::future::join_all; // this function needs a better home diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index f380d14..a46b90c 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -1,7 +1,7 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::entity::gateway::EntityGateway; -use crate::entity::item::Meseta; +use entity::gateway::EntityGateway; +use entity::item::Meseta; use crate::common::serverstate::ClientId; use crate::common::leveltable::LEVEL_TABLE; use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemDropLocation}; diff --git a/src/ship/packet/handler/quest.rs b/src/ship/packet/handler/quest.rs index 1c8c31e..b219684 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/quest.rs @@ -4,7 +4,7 @@ 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 maps::enemy::RareMonsterAppearTable; use crate::ship::location::{ClientLocation}; use crate::ship::packet::builder::quest; use libpso::util::array_to_utf8; @@ -118,7 +118,7 @@ pub async fn player_chose_quest(id: ClientId, .clone(); let rare_monster_table = RareMonsterAppearTable::new(room.mode.episode()); - room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_table, event); + room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_table, event.rare_enemy_event()); room.map_areas = quest.map_areas.clone(); let bin = quest::quest_header(&questmenuselect, &quest.bin_blob, "bin"); diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 9198c63..cf5d6af 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -1,4 +1,4 @@ -use std::convert::{TryFrom, Into}; +use std::convert::Into; use futures::stream::StreamExt; use async_std::sync::Arc; @@ -7,13 +7,15 @@ 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 entity::gateway::EntityGateway; +use entity::character::SectionID; +use 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::room::{Rooms, RoomState, RoomCreationError}; +use maps::room::{Episode, Difficulty, RoomMode}; +use maps::enemy::RareEnemyEvent; +use maps::maps::Maps; use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; use crate::ship::packet::builder; use crate::ship::items::state::ItemState; @@ -26,7 +28,7 @@ pub async fn create_room(id: ClientId, clients: &Clients, item_state: &mut ItemState, rooms: &Rooms, - map_builder: Arc Maps + Send + Sync>>, + map_builder: Arc) -> Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, event: ShipEvent) -> Result, anyhow::Error> @@ -36,7 +38,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 +67,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(); diff --git a/src/ship/packet/handler/settings.rs b/src/ship/packet/handler/settings.rs index de7bfaa..c8ebd52 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship/packet/handler/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 entity::gateway::EntityGateway; pub async fn update_config(id: ClientId, update_config: UpdateConfig, diff --git a/src/ship/packet/handler/trade.rs b/src/ship/packet/handler/trade.rs index c1cb2d0..f3128d0 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship/packet/handler/trade.rs @@ -8,11 +8,11 @@ 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 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 entity::item::Meseta; use crate::ship::trade::ClientTradeState; pub const MESETA_ITEM_ID: ClientItemId = ClientItemId(0xFFFFFF01); diff --git a/src/ship/quests.rs b/src/ship/quests.rs index 4f5eb26..91e5d4d 100644 --- a/src/ship/quests.rs +++ b/src/ship/quests.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/ship/room.rs b/src/ship/room.rs index b3a03c2..441feb5 100644 --- a/src/ship/room.rs +++ b/src/ship/room.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,16 +7,19 @@ use futures::stream::{FuturesOrdered, Stream}; use thiserror::Error; use rand::Rng; -use crate::ship::map::Maps; +use maps::maps::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 entity::character::SectionID; +use entity::room::{RoomEntityId, RoomEntityMode}; +use maps::monster::{load_monster_stats_table, MonsterType, MonsterStats}; +use maps::area::MapAreaLookup; +use maps::enemy::RareEnemyEvent; use crate::ship::quests; use crate::ship::ship::{ShipError, ShipEvent}; use crate::ship::location::{MAX_ROOMS, RoomId}; +use maps::room::{Episode, Difficulty, RoomMode}; + #[derive(Clone)] pub struct Rooms([Arc>>; MAX_ROOMS]); @@ -123,156 +126,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, @@ -369,7 +223,7 @@ impl RoomState { name: String, password: [u16; 16], event: ShipEvent, - map_builder: Arc Maps + Send + Sync>>, + map_builder: Arc) -> Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, ) -> Result { let mode = match mode { @@ -397,7 +251,7 @@ impl RoomState { random_seed: rand::thread_rng().gen(), name, password, - maps: map_builder(mode, event), + maps: map_builder(mode, event.rare_enemy_event()), section_id, drop_table: Box::new(drop_table_builder(episode, difficulty, section_id)), bursting: false, diff --git a/src/ship/ship.rs b/src/ship/ship.rs index cd40965..cfe31f7 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -18,14 +18,16 @@ 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 entity::gateway::{EntityGateway, GatewayError}; +use entity::character::SectionID; +use 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 maps::area::MapAreaError; +use maps::maps::{Maps, MapsError, generate_free_roam_maps}; +use maps::enemy::RareEnemyEvent; use crate::ship::packet::handler; use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop}; use crate::ship::trade::TradeState; @@ -38,57 +40,6 @@ 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)] pub enum ShipError { @@ -139,7 +90,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}")] @@ -166,6 +117,70 @@ impl> From for ShipError { } */ +#[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, + } + } +} + +impl ShipEvent { + pub fn rare_enemy_event(&self) -> Option { + match self { + ShipEvent::Easter => Some(RareEnemyEvent::Easter), + ShipEvent::Halloween => Some(RareEnemyEvent::Halloween), + ShipEvent::Christmas => Some(RareEnemyEvent::Christmas), + _ => None, + } + } +} + + #[derive(Debug)] pub enum RecvShipPacket { @@ -343,14 +358,14 @@ impl SendServerPacket for SendShipPacket { #[derive(Clone)] pub struct ItemShops { - pub weapon_shop: HashMap<(room::Difficulty, SectionID), Arc>>>, + pub weapon_shop: HashMap<(maps::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 difficulty = [maps::room::Difficulty::Normal, maps::room::Difficulty::Hard, maps::room::Difficulty::VeryHard, maps::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]; @@ -377,8 +392,8 @@ pub struct ShipServerStateBuilder { port: Option, auth_token: Option, event: Option, - map_builder: Option Maps + Send + Sync>>, - drop_table_builder: Option DropTable + Send + Sync>>, + map_builder: Option) -> Maps + Send + Sync>>, + drop_table_builder: Option DropTable + Send + Sync>>, num_blocks: usize, } @@ -436,13 +451,13 @@ impl ShipServerStateBuilder { } #[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 DropTable + Send + Sync>) -> ShipServerStateBuilder { self.drop_table_builder = Some(drop_table_builder); self } @@ -514,8 +529,8 @@ 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 DropTable + Send + Sync>>, } impl ShipServerState { diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index d1d8b47..23fca20 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -5,10 +5,10 @@ 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 entity::item::ItemDetail; +use entity::item::armor::{Armor, ArmorType}; +use entity::item::shield::{Shield, ShieldType}; +use entity::item::unit::{Unit, UnitType}; use crate::ship::shops::ShopItem; use crate::ship::item_stats::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; diff --git a/src/ship/shops/mod.rs b/src/ship/shops/mod.rs index 573b667..7a999b7 100644 --- a/src/ship/shops/mod.rs +++ b/src/ship/shops/mod.rs @@ -2,7 +2,7 @@ mod weapon; mod tool; mod armor; -use crate::entity::item::ItemDetail; +use entity::item::ItemDetail; pub trait ShopItem { fn price(&self) -> usize; diff --git a/src/ship/shops/tool.rs b/src/ship/shops/tool.rs index b5f9718..73a44c7 100644 --- a/src/ship/shops/tool.rs +++ b/src/ship/shops/tool.rs @@ -6,9 +6,9 @@ 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 entity::item::ItemDetail; +use entity::item::tool::{Tool, ToolType}; +use entity::item::tech::{Technique, TechniqueDisk}; use crate::ship::shops::ShopItem; use crate::ship::item_stats::{TOOL_STATS, TECH_STATS}; diff --git a/src/ship/shops/weapon.rs b/src/ship/shops/weapon.rs index 14509c8..6174b5a 100644 --- a/src/ship/shops/weapon.rs +++ b/src/ship/shops/weapon.rs @@ -8,10 +8,10 @@ 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 entity::character::SectionID; +use maps::room::Difficulty; +use entity::item::ItemDetail; +use entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; use crate::ship::shops::ShopItem; use crate::ship::item_stats::WEAPON_STATS; diff --git a/tests/common.rs b/tests/common.rs index e9dccd0..6c8b577 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -1,14 +1,14 @@ #![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 entity::gateway::EntityGateway; +use entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; +use entity::character::{CharacterEntity, NewCharacterEntity}; +use entity::item::{Meseta, BankName, BankIdentifier}; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::ship::room::Difficulty; +use maps::room::Difficulty; -use elseware::entity::item; +use entity::item; use libpso::packet::ship::*; use libpso::packet::login::{Login, Session}; diff --git a/tests/test_bank.rs b/tests/test_bank.rs index 71fc8f5..227e043 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -1,7 +1,7 @@ use std::collections::BTreeSet; use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; use libpso::packet::ship::*; diff --git a/tests/test_character.rs b/tests/test_character.rs index ca16eac..9ea3c93 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -1,5 +1,5 @@ use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; use libpso::character::settings::{DEFAULT_KEYBOARD_CONFIG1, DEFAULT_KEYBOARD_CONFIG2, DEFAULT_KEYBOARD_CONFIG3, DEFAULT_KEYBOARD_CONFIG4}; diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 0317e9d..6cecb60 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -1,13 +1,13 @@ use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; +use 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 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::*; diff --git a/tests/test_item_actions.rs b/tests/test_item_actions.rs index 77d52bc..d840cab 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 entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::item; +use entity::item; use libpso::packet::ship::*; use libpso::packet::messages::*; diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs index 02b01b1..3f2f55a 100644 --- a/tests/test_item_drop.rs +++ b/tests/test_item_drop.rs @@ -1,15 +1,18 @@ use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::character::SectionID; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use 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 maps::room::{Episode, Difficulty}; +use maps::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 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::*; diff --git a/tests/test_item_id.rs b/tests/test_item_id.rs index f8ba644..0d8d70e 100644 --- a/tests/test_item_id.rs +++ b/tests/test_item_id.rs @@ -1,8 +1,8 @@ use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::TechLevel; +use entity::character::TechLevel; //use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; use libpso::packet::ship::*; diff --git a/tests/test_item_pickup.rs b/tests/test_item_pickup.rs index 394cc3a..ca1b118 100644 --- a/tests/test_item_pickup.rs +++ b/tests/test_item_pickup.rs @@ -1,6 +1,6 @@ use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; use libpso::packet::ship::*; diff --git a/tests/test_item_use.rs b/tests/test_item_use.rs index b6b8502..fab748b 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -1,8 +1,8 @@ use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::TechLevel; +use entity::character::TechLevel; //use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; use libpso::packet::ship::*; diff --git a/tests/test_mags.rs b/tests/test_mags.rs index 1a7d687..fe098d9 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 entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::{CharacterClass, SectionID}; +use entity::character::{CharacterClass, SectionID}; use libpso::packet::ship::*; use libpso::packet::messages::*; diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index 00b512d..73c2a77 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -1,6 +1,6 @@ use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; use elseware::ship::location::RoomId; diff --git a/tests/test_shops.rs b/tests/test_shops.rs index cf230c9..6a94a04 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -1,8 +1,8 @@ use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; -use elseware::ship::room::Difficulty; +use maps::room::Difficulty; use elseware::ship::items::state::ItemStateError; use libpso::packet::ship::*; diff --git a/tests/test_trade.rs b/tests/test_trade.rs index 4155a46..a895ed4 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -1,9 +1,9 @@ use std::convert::TryInto; use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; -use elseware::entity::item::{Meseta, ItemEntity}; +use entity::item::{Meseta, ItemEntity, InventoryItemEntity}; use elseware::ship::packet::handler::trade::TradeError; use libpso::packet::ship::*; @@ -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| { From fbeaf5e93e06ca844883d143ea00ca609ef1bf74 Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 22:04:20 -0700 Subject: [PATCH 03/29] genuflect towards the great clippy --- maps/src/enemy.rs | 2 +- src/bin/patch.rs | 4 +--- src/common/mainloop/interserver.rs | 8 ++------ src/ship/drops/box_drop_table.rs | 5 ++--- src/ship/drops/generic_armor.rs | 8 ++++---- src/ship/drops/generic_shield.rs | 4 ++-- src/ship/drops/generic_weapon.rs | 6 +++--- src/ship/items/apply_item.rs | 2 +- src/ship/items/bank.rs | 12 ++---------- src/ship/packet/builder/room.rs | 1 + src/ship/shops/armor.rs | 4 ++-- src/ship/shops/tool.rs | 13 ++----------- src/ship/shops/weapon.rs | 4 ++-- 13 files changed, 25 insertions(+), 48 deletions(-) diff --git a/maps/src/enemy.rs b/maps/src/enemy.rs index 08e0f61..033b05d 100644 --- a/maps/src/enemy.rs +++ b/maps/src/enemy.rs @@ -81,7 +81,7 @@ pub fn load_rare_monster_file(episode: Episode) let mut f = File::open(path).unwrap(); let mut s = String::new(); - f.read_to_string(&mut s); + f.read_to_string(&mut s).unwrap(); toml::from_str::(s.as_str()).unwrap() } diff --git a/src/bin/patch.rs b/src/bin/patch.rs index e7304d8..6716391 100644 --- a/src/bin/patch.rs +++ b/src/bin/patch.rs @@ -12,7 +12,5 @@ fn main() { elseware::common::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/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs index d524952..0465f43 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/common/mainloop/interserver.rs @@ -219,12 +219,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/ship/drops/box_drop_table.rs b/src/ship/drops/box_drop_table.rs index 4ad1e60..e5e6f8d 100644 --- a/src/ship/drops/box_drop_table.rs +++ b/src/ship/drops/box_drop_table.rs @@ -13,7 +13,6 @@ 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 entity::item::ItemDetail; #[derive(Debug, Serialize, Deserialize)] struct BoxDropRate { @@ -176,8 +175,8 @@ impl BoxDropTable { fn random_box_drop(&self, map_area: &MapArea, rng: &mut R) -> Option { 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(); + 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(); let btype = type_weights.sample(rng); match btype { 0 => self.weapon_table.get_drop(map_area, rng), diff --git a/src/ship/drops/generic_armor.rs b/src/ship/drops/generic_armor.rs index 80e4761..6c70934 100644 --- a/src/ship/drops/generic_armor.rs +++ b/src/ship/drops/generic_armor.rs @@ -46,8 +46,8 @@ 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(); + 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(); 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 { @@ -80,8 +80,8 @@ 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(); + 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(); slot_weights.sample(rng) } diff --git a/src/ship/drops/generic_shield.rs b/src/ship/drops/generic_shield.rs index fd5752e..3ca20c9 100644 --- a/src/ship/drops/generic_shield.rs +++ b/src/ship/drops/generic_shield.rs @@ -36,8 +36,8 @@ 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(); + 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(); 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_weapon.rs b/src/ship/drops/generic_weapon.rs index 38290e7..0872c8e 100644 --- a/src/ship/drops/generic_weapon.rs +++ b/src/ship/drops/generic_weapon.rs @@ -240,7 +240,7 @@ impl AttributeTable { fn generate_attribute(&self, pattern: &PercentPatternType, rates: &AttributeRate, rng: &mut R) -> Option { - let attribute_weights = WeightedIndex::new(&[rates.none, rates.native, rates.abeast, rates.machine, rates.dark, rates.hit]).unwrap(); + let attribute_weights = WeightedIndex::new([rates.none, rates.native, rates.abeast, rates.machine, rates.dark, rates.hit]).unwrap(); let attr = match attribute_weights.sample(rng) { 0 => return None, 1 => Attribute::Native, @@ -253,7 +253,7 @@ impl AttributeTable { let percents = self.percent_rates.get_by_pattern(pattern); - let value_weights = WeightedIndex::new(&percents.as_array()).unwrap(); + let value_weights = WeightedIndex::new(percents.as_array()).unwrap(); let value = value_weights.sample(rng); let percent = ((value + 1) * 5) as i8; @@ -477,7 +477,7 @@ impl GenericWeaponTable { let pattern = std::cmp::min(area % ratio.inc, 3); let weights = self.grind_rates.grind_rate[pattern as usize]; - let grind_choice = WeightedIndex::new(&weights).unwrap(); + let grind_choice = WeightedIndex::new(weights).unwrap(); grind_choice.sample(rng) } diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index 9c7e3c2..ef0e05f 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -226,7 +226,7 @@ pub async fn liberta_kit(entity_gateway: &mut EG, used_cell: fn jack_o_lantern() -> Result, anyhow::Error> { - let mag_rate = WeightedIndex::new(&[13, 13, 13, 13, 12, 12, 12, 12]).unwrap(); + let mag_rate = WeightedIndex::new([13, 13, 13, 13, 12, 12, 12, 12]).unwrap(); let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) { 0 => ToolType::CellOfMag502, 1 => ToolType::CellOfMag213, diff --git a/src/ship/items/bank.rs b/src/ship/items/bank.rs index f6d12cd..799cb03 100644 --- a/src/ship/items/bank.rs +++ b/src/ship/items/bank.rs @@ -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)) } } @@ -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/packet/builder/room.rs b/src/ship/packet/builder/room.rs index 2b5c8e5..1f922a1 100644 --- a/src/ship/packet/builder/room.rs +++ b/src/ship/packet/builder/room.rs @@ -17,6 +17,7 @@ pub async fn join_room(id: ClientId, event: ShipEvent) -> 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 { diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index 23fca20..557856e 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -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/ship/shops/tool.rs b/src/ship/shops/tool.rs index 73a44c7..9691456 100644 --- a/src/ship/shops/tool.rs +++ b/src/ship/shops/tool.rs @@ -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/ship/shops/weapon.rs index 6174b5a..699b76a 100644 --- a/src/ship/shops/weapon.rs +++ b/src/ship/shops/weapon.rs @@ -412,7 +412,7 @@ impl WeaponShop { .last() .unwrap(); - let attr_choice = WeightedIndex::new(&[tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); + let attr_choice = WeightedIndex::new([tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); let attr = match attr_choice.sample(&mut self.rng) { 0 => return None, 1 => Attribute::Native, @@ -439,7 +439,7 @@ impl WeaponShop { .last() .unwrap(); - let attr_choice = WeightedIndex::new(&[tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); + let attr_choice = WeightedIndex::new([tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); let attr = match attr_choice.sample(&mut self.rng) { 0 => return None, 1 => Attribute::Native, From 5bf9ef59bf9bd5a8f9e8b250dba57ca1ae619ee0 Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 22:16:30 -0700 Subject: [PATCH 04/29] actually this shouldn't be needed --- Cargo.toml | 3 --- common/Cargo.toml | 8 -------- common/src/lib.rs | 0 maps/Cargo.toml | 1 - 4 files changed, 12 deletions(-) delete mode 100644 common/Cargo.toml delete mode 100644 common/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 7561e6b..3e3c47b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" members = [ "entity", "maps", - "common", "networking", ] @@ -16,7 +15,6 @@ members = [ libpso = { git = "http://git.sharnoth.com/jake/libpso" } entity = { path = "./entity" } maps = { path = "./maps" } -common = { path = "./common" } networking = { path = "./networking" } async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" @@ -50,7 +48,6 @@ anyhow = { version = "1.0.68", features = ["backtrace"] } libpso = { git = "http://git.sharnoth.com/jake/libpso" } entity = { path = "./entity" } maps = { path = "./maps" } -common = { path = "./common" } networking = { path = "./networking" } async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" diff --git a/common/Cargo.toml b/common/Cargo.toml deleted file mode 100644 index 552f659..0000000 --- a/common/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "common" -version = "0.1.0" -edition = "2021" - - -[dependencies] -derive_more = { workspace = true } \ No newline at end of file diff --git a/common/src/lib.rs b/common/src/lib.rs deleted file mode 100644 index e69de29..0000000 diff --git a/maps/Cargo.toml b/maps/Cargo.toml index cf0401e..db84b6a 100644 --- a/maps/Cargo.toml +++ b/maps/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -common = { workspace = true } byteorder = { workspace = true } serde = { workspace = true } thiserror = { workspace = true } From fc62be05e21cab11c072a8ea8b80b6d01f50c10c Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 22:17:27 -0700 Subject: [PATCH 05/29] cleanup --- entity/Cargo.toml | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/entity/Cargo.toml b/entity/Cargo.toml index 6603cbb..ce90e98 100644 --- a/entity/Cargo.toml +++ b/entity/Cargo.toml @@ -21,37 +21,3 @@ futures = { workspace = true } strum = { workspace = true } strum_macros = { workspace = true } toml = { workspace = true } - - -#libpso = { git = "http://git.sharnoth.com/jake/libpso" } -#async-std = { version = "1.9.0", features = ["unstable", "attributes"] } -#futures = "0.3.5" -#rand = "0.7.3" -#rand_chacha = "0.2.2" -#crc = "^1.0.0" -#bcrypt = "0.10" -#chrono = "0.4.11" -#serde = "*" -#serde_json = "*" -#ron = "*" -#toml = "*" -#log = "*" -#fern = { version = "0.5", features = ["colored"] } -#byteorder = "1" -#enum-utils = "0.1.2" -#derive_more = { version = "0.99.3", features = ["display"]} -#thiserror = "1.0.37" -#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"] } - -#[lib] -#name = "entity" -#path = "lib.rs" \ No newline at end of file From 6ac3ad50dc90447cde1bdff03e18b07366638749 Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 22:29:50 -0700 Subject: [PATCH 06/29] oh wow this has been wrong this entire time --- src/ship/items/bank.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ship/items/bank.rs b/src/ship/items/bank.rs index 799cb03..885aba4 100644 --- a/src/ship/items/bank.rs +++ b/src/ship/items/bank.rs @@ -336,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) } From 2c930d43332bd8a949fc9b97e3b7f213be3d0b80 Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 23:17:37 -0700 Subject: [PATCH 07/29] maybe specifying only 1 test job at a time will keep it from running out of memory --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index ae267b5..fd5f76f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -33,7 +33,7 @@ steps: - name: target-cache path: /drone/src/target commands: - - cargo test + - cargo test --jobs 1 volumes: - name: cache From 3b28d650eef512d6093712a8ed6cbf7296496d1a Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 23:31:47 -0700 Subject: [PATCH 08/29] crates for shops and stats --- Cargo.toml | 6 ++++++ shops/Cargo.toml | 13 +++++++++++++ {src/ship/shops => shops/src}/armor.rs | 4 ++-- src/ship/shops/mod.rs => shops/src/lib.rs | 0 {src/ship/shops => shops/src}/tool.rs | 4 ++-- {src/ship/shops => shops/src}/weapon.rs | 4 ++-- src/ship/client.rs | 2 +- src/ship/drops/generic_armor.rs | 2 +- src/ship/drops/generic_shield.rs | 2 +- src/ship/drops/generic_unit.rs | 2 +- src/ship/items/actions.rs | 2 +- src/ship/items/inventory.rs | 2 +- src/ship/items/tasks.rs | 2 +- src/ship/mod.rs | 4 ++-- src/ship/packet/builder/message.rs | 2 +- src/ship/packet/handler/direct_message.rs | 2 +- src/ship/ship.rs | 2 +- stats/Cargo.toml | 10 ++++++++++ src/ship/item_stats.rs => stats/src/items.rs | 0 stats/src/lib.rs | 1 + 20 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 shops/Cargo.toml rename {src/ship/shops => shops/src}/armor.rs (98%) rename src/ship/shops/mod.rs => shops/src/lib.rs (100%) rename {src/ship/shops => shops/src}/tool.rs (98%) rename {src/ship/shops => shops/src}/weapon.rs (99%) create mode 100644 stats/Cargo.toml rename src/ship/item_stats.rs => stats/src/items.rs (100%) create mode 100644 stats/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 3e3c47b..0ea2e3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,8 @@ members = [ "entity", "maps", "networking", + "shops", + "stats", ] [workspace.dependencies] @@ -16,6 +18,8 @@ libpso = { git = "http://git.sharnoth.com/jake/libpso" } entity = { path = "./entity" } maps = { path = "./maps" } networking = { path = "./networking" } +shops = { path = "./shops" } +stats = { path = "./stats" } async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" rand = "0.7.3" @@ -49,6 +53,8 @@ libpso = { git = "http://git.sharnoth.com/jake/libpso" } entity = { path = "./entity" } maps = { path = "./maps" } networking = { path = "./networking" } +shops = { path = "./shops" } +stats = { path = "./stats" } async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" rand = "0.7.3" diff --git a/shops/Cargo.toml b/shops/Cargo.toml new file mode 100644 index 0000000..495bf2f --- /dev/null +++ b/shops/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "shops" +version = "0.1.0" +edition = "2021" + +[dependencies] +maps = { workspace = true } +stats = { workspace = true } +entity = { workspace = true } + +rand = { workspace = true } +toml = { workspace = true } +serde = { workspace = true } \ No newline at end of file diff --git a/src/ship/shops/armor.rs b/shops/src/armor.rs similarity index 98% rename from src/ship/shops/armor.rs rename to shops/src/armor.rs index 557856e..f424877 100644 --- a/src/ship/shops/armor.rs +++ b/shops/src/armor.rs @@ -9,8 +9,8 @@ use entity::item::ItemDetail; use entity::item::armor::{Armor, ArmorType}; use entity::item::shield::{Shield, ShieldType}; use entity::item::unit::{Unit, UnitType}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; +use crate::ShopItem; +use stats::items::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; // #[derive(Debug)] // pub enum ArmorShopItem { diff --git a/src/ship/shops/mod.rs b/shops/src/lib.rs similarity index 100% rename from src/ship/shops/mod.rs rename to shops/src/lib.rs diff --git a/src/ship/shops/tool.rs b/shops/src/tool.rs similarity index 98% rename from src/ship/shops/tool.rs rename to shops/src/tool.rs index 9691456..b068d19 100644 --- a/src/ship/shops/tool.rs +++ b/shops/src/tool.rs @@ -9,8 +9,8 @@ use rand::distributions::{WeightedIndex, Distribution}; use entity::item::ItemDetail; use entity::item::tool::{Tool, ToolType}; use entity::item::tech::{Technique, TechniqueDisk}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::{TOOL_STATS, TECH_STATS}; +use crate::ShopItem; +use stats::items::{TOOL_STATS, TECH_STATS}; #[derive(Debug, PartialEq, Eq)] diff --git a/src/ship/shops/weapon.rs b/shops/src/weapon.rs similarity index 99% rename from src/ship/shops/weapon.rs rename to shops/src/weapon.rs index 699b76a..06a8c1e 100644 --- a/src/ship/shops/weapon.rs +++ b/shops/src/weapon.rs @@ -12,8 +12,8 @@ use entity::character::SectionID; use maps::room::Difficulty; use entity::item::ItemDetail; use entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::WEAPON_STATS; +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/ship/client.rs b/src/ship/client.rs index 58f75f7..abdf6ea 100644 --- a/src/ship/client.rs +++ b/src/ship/client.rs @@ -14,7 +14,7 @@ use entity::item; use crate::ship::ship::ShipError; use crate::ship::items; use maps::area::MapArea; -use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; +use shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; #[derive(Clone, Default)] diff --git a/src/ship/drops/generic_armor.rs b/src/ship/drops/generic_armor.rs index 6c70934..4fa2667 100644 --- a/src/ship/drops/generic_armor.rs +++ b/src/ship/drops/generic_armor.rs @@ -8,7 +8,7 @@ use entity::item::armor::{ArmorType, Armor}; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{armor_stats, ArmorStats}; +use stats::items::{armor_stats, ArmorStats}; #[derive(Debug, Serialize, Deserialize)] diff --git a/src/ship/drops/generic_shield.rs b/src/ship/drops/generic_shield.rs index 3ca20c9..bed92a6 100644 --- a/src/ship/drops/generic_shield.rs +++ b/src/ship/drops/generic_shield.rs @@ -8,7 +8,7 @@ use entity::character::SectionID; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{shield_stats, ShieldStats}; +use stats::items::{shield_stats, ShieldStats}; #[derive(Debug, Serialize, Deserialize)] diff --git a/src/ship/drops/generic_unit.rs b/src/ship/drops/generic_unit.rs index 137f7d0..a5e1da5 100644 --- a/src/ship/drops/generic_unit.rs +++ b/src/ship/drops/generic_unit.rs @@ -8,7 +8,7 @@ use entity::item::unit::{UnitType, Unit, UnitModifier}; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{unit_stats, UnitStats}; +use stats::items::{unit_stats, UnitStats}; diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index 2359950..f5f93f0 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -21,7 +21,7 @@ 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 shops::ShopItem; use crate::ship::drops::{ItemDrop, ItemDropType}; use crate::ship::packet::builder; use crate::ship::location::AreaClient; diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index ca0e51d..e30eb93 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -9,7 +9,7 @@ use entity::character::CharacterEntityId; use entity::item::tool::ToolType; use entity::item::mag::Mag; use entity::item::weapon::Weapon; -use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem}; +use 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}; diff --git a/src/ship/items/tasks.rs b/src/ship/items/tasks.rs index f224f4c..d4910a1 100644 --- a/src/ship/items/tasks.rs +++ b/src/ship/items/tasks.rs @@ -12,7 +12,7 @@ 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 shops::ShopItem; use crate::ship::trade::TradeItem; use crate::ship::location::AreaClient; use crate::ship::drops::ItemDrop; diff --git a/src/ship/mod.rs b/src/ship/mod.rs index 3978099..d769c38 100644 --- a/src/ship/mod.rs +++ b/src/ship/mod.rs @@ -5,12 +5,12 @@ pub mod character; pub mod client; pub mod room; pub mod items; -pub mod item_stats; +//pub mod item_stats; //pub mod map; //pub mod monster; pub mod drops; pub mod packet; pub mod quests; -pub mod shops; +//pub mod shops; pub mod trade; pub mod chatcommand; diff --git a/src/ship/packet/builder/message.rs b/src/ship/packet/builder/message.rs index f83ebbd..85bc90b 100644 --- a/src/ship/packet/builder/message.rs +++ b/src/ship/packet/builder/message.rs @@ -10,7 +10,7 @@ use crate::ship::items::bank::BankState; use crate::ship::items::floor::FloorItem; use crate::ship::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 { diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 0886f79..c43efc9 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -14,7 +14,7 @@ use entity::gateway::EntityGateway; use entity::item; use libpso::utf8_to_utf16_array; use crate::ship::packet::builder; -use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem}; +use shops::{ShopItem, ToolShopItem, ArmorShopItem}; use crate::ship::items::state::{ItemState, ItemStateError}; use crate::ship::items::floor::{FloorType, FloorItemDetail}; use crate::ship::items::actions::TriggerCreateItem; diff --git a/src/ship/ship.rs b/src/ship/ship.rs index cfe31f7..ec3f132 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -29,7 +29,7 @@ use maps::area::MapAreaError; use maps::maps::{Maps, MapsError, generate_free_roam_maps}; use maps::enemy::RareEnemyEvent; use crate::ship::packet::handler; -use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop}; +use shops::{WeaponShop, ToolShop, ArmorShop}; use crate::ship::trade::TradeState; use crate::ship::chatcommand; diff --git a/stats/Cargo.toml b/stats/Cargo.toml new file mode 100644 index 0000000..e1d5801 --- /dev/null +++ b/stats/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "stats" +version = "0.1.0" +edition = "2021" + +[dependencies] +entity = { workspace = true } +toml = { workspace = true } +serde = { workspace = true } +lazy_static = { workspace = true } diff --git a/src/ship/item_stats.rs b/stats/src/items.rs similarity index 100% rename from src/ship/item_stats.rs rename to stats/src/items.rs diff --git a/stats/src/lib.rs b/stats/src/lib.rs new file mode 100644 index 0000000..339b22d --- /dev/null +++ b/stats/src/lib.rs @@ -0,0 +1 @@ +pub mod items; From 72aa0f7f135ce8566c1220d235933b4bc1c733e9 Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 23:38:56 -0700 Subject: [PATCH 09/29] clean up toplevel cargo.toml a bit --- Cargo.toml | 64 ++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0ea2e3a..20c9340 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,12 +14,14 @@ members = [ ] [workspace.dependencies] -libpso = { git = "http://git.sharnoth.com/jake/libpso" } entity = { path = "./entity" } maps = { path = "./maps" } networking = { path = "./networking" } shops = { path = "./shops" } stats = { path = "./stats" } + +libpso = { git = "http://git.sharnoth.com/jake/libpso" } + async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" rand = "0.7.3" @@ -49,36 +51,32 @@ strum_macros = "0.19" anyhow = { version = "1.0.68", features = ["backtrace"] } [dependencies] -libpso = { git = "http://git.sharnoth.com/jake/libpso" } -entity = { path = "./entity" } -maps = { path = "./maps" } -networking = { path = "./networking" } -shops = { path = "./shops" } -stats = { path = "./stats" } -async-std = { version = "1.9.0", features = ["unstable", "attributes"] } -futures = "0.3.5" -rand = "0.7.3" -rand_chacha = "0.2.2" -crc = "^1.0.0" -bcrypt = "0.10" +entity = { workspace = true } +maps = { workspace = true } +networking = { workspace = true } +shops = { workspace = true } +stats = { workspace = true } + +libpso = { workspace = true } + +ages-prs = { workspace = true } +anyhow = { workspace = true } +async-recursion = { workspace = true } +async-std = { workspace = true } +async-trait = { workspace = true } +bcrypt = { workspace = true } +byteorder = { workspace = true } chrono = { workspace = true } -serde = "*" -serde_json = "*" -ron = "*" -toml = "*" -log = "*" -fern = { version = "0.5", features = ["colored"] } -byteorder = "1" -enum-utils = "0.1.2" -derive_more = { version = "0.99.3", features = ["display"]} -thiserror = "1.0.37" -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 = { workspace = true } \ No newline at end of file +crc = { workspace = true } +derive_more = { workspace = true } +enum-utils = { workspace = true } +fern = { workspace = true } +futures = { workspace = true } +log = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } +ron = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +toml = { workspace = true } +thiserror = { workspace = true } \ No newline at end of file From 5d98fb8cc9afdbb76aacfa97aead98c58a621602 Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 10 Nov 2023 23:48:06 -0700 Subject: [PATCH 10/29] move leveltable to stats crate --- src/common/mod.rs | 1 - src/login/character.rs | 2 +- src/ship/character.rs | 2 +- src/ship/packet/builder/message.rs | 2 +- src/ship/packet/builder/mod.rs | 2 +- src/ship/packet/handler/direct_message.rs | 2 +- src/ship/packet/handler/lobby.rs | 2 +- src/ship/packet/handler/message.rs | 2 +- src/ship/packet/handler/room.rs | 2 +- stats/Cargo.toml | 1 + {src/common => stats/src}/leveltable.rs | 0 stats/src/lib.rs | 3 +++ 12 files changed, 12 insertions(+), 9 deletions(-) rename {src/common => stats/src}/leveltable.rs (100%) diff --git a/src/common/mod.rs b/src/common/mod.rs index d02076e..c8adde9 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,7 +1,6 @@ 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/ diff --git a/src/login/character.rs b/src/login/character.rs index 07969ef..ef74730 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -18,7 +18,7 @@ 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 stats::leveltable::LEVEL_TABLE; use libpso::{utf8_to_array, utf8_to_utf16_array}; use entity::gateway::{EntityGateway, GatewayError}; diff --git a/src/ship/character.rs b/src/ship/character.rs index afe73c6..90ba63b 100644 --- a/src/ship/character.rs +++ b/src/ship/character.rs @@ -1,5 +1,5 @@ use libpso::character::character; -use crate::common::leveltable::CharacterStats; +use stats::leveltable::CharacterStats; use entity::character::CharacterEntity; //use crate::ship::items::{CharacterInventory, CharacterBank}; use crate::ship::items::bank::BankState; diff --git a/src/ship/packet/builder/message.rs b/src/ship/packet/builder/message.rs index 85bc90b..d420187 100644 --- a/src/ship/packet/builder/message.rs +++ b/src/ship/packet/builder/message.rs @@ -1,7 +1,7 @@ use libpso::packet::messages::*; use libpso::packet::ship::*; use entity::item; -use crate::common::leveltable::CharacterStats; +use stats::leveltable::CharacterStats; use crate::ship::ship::{ShipError}; use crate::ship::items::ClientItemId; use crate::ship::items::inventory::InventoryItem; diff --git a/src/ship/packet/builder/mod.rs b/src/ship/packet/builder/mod.rs index f74015e..4872aaa 100644 --- a/src/ship/packet/builder/mod.rs +++ b/src/ship/packet/builder/mod.rs @@ -6,7 +6,7 @@ pub mod ship; use libpso::character::character::Inventory; use libpso::packet::ship::{PlayerHeader, PlayerInfo}; -use crate::common::leveltable::LEVEL_TABLE; +use stats::leveltable::LEVEL_TABLE; use crate::ship::character::CharacterBytesBuilder; use crate::ship::ship::ClientState; use crate::ship::location::AreaClient; diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index c43efc9..dea6911 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -3,7 +3,7 @@ use rand::Rng; use rand::seq::SliceRandom; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::leveltable::LEVEL_TABLE; +use stats::leveltable::LEVEL_TABLE; use crate::common::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemShops}; use crate::ship::location::ClientLocation; diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index ae95afb..d085cc6 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -1,6 +1,6 @@ use libpso::packet::ship::*; use crate::common::serverstate::ClientId; -use crate::common::leveltable::LEVEL_TABLE; +use stats::leveltable::LEVEL_TABLE; use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; use crate::ship::room::Rooms; use crate::ship::character::{FullCharacterBytesBuilder}; diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index a46b90c..497f2d9 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -3,7 +3,7 @@ use libpso::packet::messages::*; use entity::gateway::EntityGateway; use entity::item::Meseta; use crate::common::serverstate::ClientId; -use crate::common::leveltable::LEVEL_TABLE; +use stats::leveltable::LEVEL_TABLE; use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemDropLocation}; use crate::ship::room::Rooms; use crate::ship::location::{ClientLocation, ClientLocationError}; diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index cf5d6af..9fc8ccc 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -6,7 +6,7 @@ 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 stats::leveltable::LEVEL_TABLE; use entity::gateway::EntityGateway; use entity::character::SectionID; use entity::room::{NewRoomEntity, RoomEntityMode, RoomNote}; diff --git a/stats/Cargo.toml b/stats/Cargo.toml index e1d5801..6cebc62 100644 --- a/stats/Cargo.toml +++ b/stats/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" entity = { workspace = true } toml = { workspace = true } serde = { workspace = true } +serde_json = { workspace = true } lazy_static = { workspace = true } diff --git a/src/common/leveltable.rs b/stats/src/leveltable.rs similarity index 100% rename from src/common/leveltable.rs rename to stats/src/leveltable.rs diff --git a/stats/src/lib.rs b/stats/src/lib.rs index 339b22d..0564e34 100644 --- a/stats/src/lib.rs +++ b/stats/src/lib.rs @@ -1 +1,4 @@ +#![feature(lazy_cell)] + pub mod items; +pub mod leveltable; From 926483b6deeba946af870d0678cea55c3ea00952 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 00:07:56 -0700 Subject: [PATCH 11/29] remove cargo cache for now, not enough disk space on my poverty ci vps --- .drone.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index fd5f76f..a8f5ce2 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,8 +12,6 @@ steps: volumes: - name: cache path: /usr/local/cargo - - name: target-cache - path: /drone/src/target commands: - cargo build - name: clippy! @@ -21,8 +19,6 @@ steps: volumes: - name: cache path: /usr/local/cargo - - name: target-cache - path: /drone/src/target commands: - cargo clippy -- --deny warnings - name: test @@ -30,8 +26,6 @@ steps: volumes: - name: cache path: /usr/local/cargo - - name: target-cache - path: /drone/src/target commands: - cargo test --jobs 1 From d73a07391be7ba5e91cfb65ae17366113e56d92a Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 14:28:41 -0700 Subject: [PATCH 12/29] break out the rest of everything into its own crate --- Cargo.toml | 24 ++ client/Cargo.toml | 20 ++ {src/ship => client/src}/client.rs | 18 +- client/src/lib.rs | 3 + drops/Cargo.toml | 17 ++ .../drops => drops/src}/box_drop_table.rs | 14 +- .../ship/drops => drops/src}/generic_armor.rs | 2 +- .../drops => drops/src}/generic_shield.rs | 2 +- {src/ship/drops => drops/src}/generic_unit.rs | 2 +- .../drops => drops/src}/generic_weapon.rs | 2 +- src/ship/drops/mod.rs => drops/src/lib.rs | 15 +- .../drops => drops/src}/rare_drop_table.rs | 8 +- {src/ship/drops => drops/src}/tech_table.rs | 2 +- {src/ship/drops => drops/src}/tool_table.rs | 4 +- items/Cargo.toml | 25 +++ {src/ship/items => items/src}/actions.rs | 36 +-- {src/ship/items => items/src}/apply_item.rs | 4 +- {src/ship/items => items/src}/bank.rs | 8 +- {src/ship/items => items/src}/floor.rs | 8 +- {src/ship/items => items/src}/inventory.rs | 8 +- .../items => items/src}/itemstateaction.rs | 0 src/ship/items/mod.rs => items/src/lib.rs | 3 + {src/ship/items => items/src}/manager.rs | 18 +- {src/ship/items => items/src}/state.rs | 14 +- {src/ship/items => items/src}/tasks.rs | 21 +- items/src/trade.rs | 38 ++++ location/Cargo.toml | 12 + location/src/lib.rs | 3 + {src/ship => location/src}/location.rs | 2 +- maps/src/enemy.rs | 18 +- maps/src/lib.rs | 52 +++++ maps/src/maps.rs | 7 +- networking/Cargo.toml | 14 ++ {src/common => networking/src}/cipherkeys.rs | 0 {src/common => networking/src}/interserver.rs | 0 networking/src/lib.rs | 18 ++ .../src}/mainloop/client.rs | 6 +- .../src}/mainloop/interserver.rs | 9 +- .../common => networking/src}/mainloop/mod.rs | 0 {src/common => networking/src}/serverstate.rs | 0 pktbuilder/Cargo.toml | 22 ++ {src/ship => pktbuilder/src}/character.rs | 5 +- .../builder/mod.rs => pktbuilder/src/lib.rs | 9 +- .../builder => pktbuilder/src}/lobby.rs | 15 +- .../builder => pktbuilder/src}/message.rs | 100 ++++----- .../builder => pktbuilder/src}/quest.rs | 5 +- .../packet/builder => pktbuilder/src}/room.rs | 21 +- .../packet/builder => pktbuilder/src}/ship.rs | 5 +- pktbuilder/src/team.rs | 107 +++++++++ .../builder => pktbuilder/src}/trade.rs | 0 quests/Cargo.toml | 18 ++ quests/src/lib.rs | 4 + {src/ship => quests/src}/quests.rs | 0 room/Cargo.toml | 17 ++ room/src/lib.rs | 3 + {src/ship => room/src}/room.rs | 33 +-- src/bin/login.rs | 8 +- src/bin/main.rs | 30 +-- src/bin/patch.rs | 4 +- src/bin/ship.rs | 8 +- src/common/mod.rs | 18 -- src/lib.rs | 3 +- src/login/character.rs | 11 +- src/login/login.rs | 4 +- src/patch/patch.rs | 4 +- src/ship/chatcommand.rs | 8 +- src/ship/drops/drop_table.rs | 0 src/ship/mod.rs | 16 +- src/ship/monster.rs | 212 ------------------ src/ship/packet/handler/auth.rs | 6 +- src/ship/packet/handler/communication.rs | 4 +- src/ship/packet/handler/direct_message.rs | 38 ++-- src/ship/packet/handler/lobby.rs | 30 +-- src/ship/packet/handler/message.rs | 30 ++- src/ship/packet/handler/quest.rs | 16 +- src/ship/packet/handler/room.rs | 23 +- src/ship/packet/handler/settings.rs | 2 +- src/ship/packet/handler/ship.rs | 6 +- src/ship/packet/handler/trade.rs | 28 +-- src/ship/packet/mod.rs | 2 +- src/ship/ship.rs | 105 ++------- tests/common.rs | 4 +- tests/test_bank.rs | 2 +- tests/test_character.rs | 2 +- tests/test_exp_gain.rs | 5 +- tests/test_item_actions.rs | 2 +- tests/test_item_drop.rs | 12 +- tests/test_item_id.rs | 4 +- tests/test_item_pickup.rs | 2 +- tests/test_item_use.rs | 3 +- tests/test_mags.rs | 2 +- tests/test_rooms.rs | 4 +- tests/test_shops.rs | 6 +- tests/test_trade.rs | 2 +- trade/Cargo.toml | 14 ++ trade/src/lib.rs | 4 + {src/ship => trade/src}/trade.rs | 42 +--- 97 files changed, 828 insertions(+), 719 deletions(-) create mode 100644 client/Cargo.toml rename {src/ship => client/src}/client.rs (93%) create mode 100644 client/src/lib.rs create mode 100644 drops/Cargo.toml rename {src/ship/drops => drops/src}/box_drop_table.rs (95%) rename {src/ship/drops => drops/src}/generic_armor.rs (98%) rename {src/ship/drops => drops/src}/generic_shield.rs (98%) rename {src/ship/drops => drops/src}/generic_unit.rs (98%) rename {src/ship/drops => drops/src}/generic_weapon.rs (99%) rename src/ship/drops/mod.rs => drops/src/lib.rs (96%) rename {src/ship/drops => drops/src}/rare_drop_table.rs (96%) rename {src/ship/drops => drops/src}/tech_table.rs (98%) rename {src/ship/drops => drops/src}/tool_table.rs (98%) create mode 100644 items/Cargo.toml rename {src/ship/items => items/src}/actions.rs (97%) rename {src/ship/items => items/src}/apply_item.rs (99%) rename {src/ship/items => items/src}/bank.rs (97%) rename {src/ship/items => items/src}/floor.rs (94%) rename {src/ship/items => items/src}/inventory.rs (98%) rename {src/ship/items => items/src}/itemstateaction.rs (100%) rename src/ship/items/mod.rs => items/src/lib.rs (87%) rename {src/ship/items => items/src}/manager.rs (99%) rename {src/ship/items => items/src}/state.rs (97%) rename {src/ship/items => items/src}/tasks.rs (97%) create mode 100644 items/src/trade.rs create mode 100644 location/Cargo.toml create mode 100644 location/src/lib.rs rename {src/ship => location/src}/location.rs (99%) rename {src/common => networking/src}/cipherkeys.rs (100%) rename {src/common => networking/src}/interserver.rs (100%) rename {src/common => networking/src}/mainloop/client.rs (97%) rename {src/common => networking/src}/mainloop/interserver.rs (95%) rename {src/common => networking/src}/mainloop/mod.rs (100%) rename {src/common => networking/src}/serverstate.rs (100%) create mode 100644 pktbuilder/Cargo.toml rename {src/ship => pktbuilder/src}/character.rs (98%) rename src/ship/packet/builder/mod.rs => pktbuilder/src/lib.rs (88%) rename {src/ship/packet/builder => pktbuilder/src}/lobby.rs (91%) rename {src/ship/packet/builder => pktbuilder/src}/message.rs (74%) rename {src/ship/packet/builder => pktbuilder/src}/quest.rs (94%) rename {src/ship/packet/builder => pktbuilder/src}/room.rs (85%) rename {src/ship/packet/builder => pktbuilder/src}/ship.rs (85%) create mode 100644 pktbuilder/src/team.rs rename {src/ship/packet/builder => pktbuilder/src}/trade.rs (100%) create mode 100644 quests/Cargo.toml create mode 100644 quests/src/lib.rs rename {src/ship => quests/src}/quests.rs (100%) create mode 100644 room/Cargo.toml create mode 100644 room/src/lib.rs rename {src/ship => room/src}/room.rs (90%) delete mode 100644 src/common/mod.rs delete mode 100644 src/ship/drops/drop_table.rs delete mode 100644 src/ship/monster.rs create mode 100644 trade/Cargo.toml create mode 100644 trade/src/lib.rs rename {src/ship => trade/src}/trade.rs (79%) diff --git a/Cargo.toml b/Cargo.toml index 20c9340..5737f97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,19 @@ edition = "2021" [workspace] members = [ + "client", + "drops", "entity", + "items", + "location", "maps", "networking", + "pktbuilder", + "quests", + "room", "shops", "stats", + "trade", ] [workspace.dependencies] @@ -19,6 +27,14 @@ maps = { path = "./maps" } networking = { path = "./networking" } shops = { path = "./shops" } stats = { path = "./stats" } +items = { path = "./items" } +pktbuilder = { path = "./pktbuilder" } +quests = { path = "./quests" } +location = { path = "./location" } +client = { path = "./client" } +drops = { path = "./drops" } +trade = { path = "./trade" } +room = { path = "./room" } libpso = { git = "http://git.sharnoth.com/jake/libpso" } @@ -56,6 +72,14 @@ maps = { workspace = true } networking = { workspace = true } shops = { workspace = true } stats = { workspace = true } +items = { workspace = true } +pktbuilder = { workspace = true } +quests = { workspace = true } +location = { workspace = true } +client = { workspace = true } +drops = { workspace = true } +trade = { workspace = true } +room = { workspace = true } libpso = { workspace = true } diff --git a/client/Cargo.toml b/client/Cargo.toml new file mode 100644 index 0000000..12f9698 --- /dev/null +++ b/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/client/src/client.rs similarity index 93% rename from src/ship/client.rs rename to client/src/client.rs index abdf6ea..21b2281 100644 --- a/src/ship/client.rs +++ b/client/src/client.rs @@ -6,17 +6,23 @@ use futures::future::BoxFuture; use libpso::packet::ship::*; use libpso::packet::login::Session; -use crate::common::serverstate::ClientId; +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 items; 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)] pub struct Clients(Arc>>>); @@ -46,7 +52,7 @@ impl Clients { .await; let client = clients .get(&client_id) - .ok_or_else(|| ShipError::ClientNotFound(client_id))? + .ok_or_else(|| ClientError::NotFound(client_id))? .read() .await; @@ -69,7 +75,7 @@ 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_else(|| ClientError::NotFound(*client_id))? .read() .await; client_states[cindex].write(c); @@ -95,7 +101,7 @@ impl Clients { .await; let mut client = clients .get(&client_id) - .ok_or_else(|| ShipError::ClientNotFound(client_id))? + .ok_or_else(|| ClientError::NotFound(client_id))? .write() .await; diff --git a/client/src/lib.rs b/client/src/lib.rs new file mode 100644 index 0000000..c8ab57b --- /dev/null +++ b/client/src/lib.rs @@ -0,0 +1,3 @@ +pub mod client; + +pub use client::*; diff --git a/drops/Cargo.toml b/drops/Cargo.toml new file mode 100644 index 0000000..199e7c6 --- /dev/null +++ b/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/drops/src/box_drop_table.rs similarity index 95% rename from src/ship/drops/box_drop_table.rs rename to drops/src/box_drop_table.rs index e5e6f8d..01f41eb 100644 --- a/src/ship/drops/box_drop_table.rs +++ b/drops/src/box_drop_table.rs @@ -5,14 +5,14 @@ use serde::{Serialize, Deserialize}; use entity::character::SectionID; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; +use crate::{ItemDropType, load_data_file}; use maps::object::{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::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 { diff --git a/src/ship/drops/generic_armor.rs b/drops/src/generic_armor.rs similarity index 98% rename from src/ship/drops/generic_armor.rs rename to drops/src/generic_armor.rs index 4fa2667..82e9a58 100644 --- a/src/ship/drops/generic_armor.rs +++ b/drops/src/generic_armor.rs @@ -7,7 +7,7 @@ use entity::character::SectionID; use entity::item::armor::{ArmorType, Armor}; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; +use crate::{ItemDropType, load_data_file}; use stats::items::{armor_stats, ArmorStats}; diff --git a/src/ship/drops/generic_shield.rs b/drops/src/generic_shield.rs similarity index 98% rename from src/ship/drops/generic_shield.rs rename to drops/src/generic_shield.rs index bed92a6..c7bbf1f 100644 --- a/src/ship/drops/generic_shield.rs +++ b/drops/src/generic_shield.rs @@ -7,7 +7,7 @@ use entity::item::shield::{ShieldType, Shield}; use entity::character::SectionID; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; +use crate::{ItemDropType, load_data_file}; use stats::items::{shield_stats, ShieldStats}; diff --git a/src/ship/drops/generic_unit.rs b/drops/src/generic_unit.rs similarity index 98% rename from src/ship/drops/generic_unit.rs rename to drops/src/generic_unit.rs index a5e1da5..cc1caa0 100644 --- a/src/ship/drops/generic_unit.rs +++ b/drops/src/generic_unit.rs @@ -7,7 +7,7 @@ use entity::character::SectionID; use entity::item::unit::{UnitType, Unit, UnitModifier}; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; +use crate::{ItemDropType, load_data_file}; use stats::items::{unit_stats, UnitStats}; diff --git a/src/ship/drops/generic_weapon.rs b/drops/src/generic_weapon.rs similarity index 99% rename from src/ship/drops/generic_weapon.rs rename to drops/src/generic_weapon.rs index 0872c8e..557130c 100644 --- a/src/ship/drops/generic_weapon.rs +++ b/drops/src/generic_weapon.rs @@ -8,7 +8,7 @@ use entity::character::SectionID; use entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial}; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; +use crate::{ItemDropType, load_data_file}; diff --git a/src/ship/drops/mod.rs b/drops/src/lib.rs similarity index 96% rename from src/ship/drops/mod.rs rename to drops/src/lib.rs index 5c228e0..bccffd4 100644 --- a/src/ship/drops/mod.rs +++ b/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; @@ -26,13 +25,13 @@ use maps::monster::MonsterType; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; use 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::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}; diff --git a/src/ship/drops/rare_drop_table.rs b/drops/src/rare_drop_table.rs similarity index 96% rename from src/ship/drops/rare_drop_table.rs rename to drops/src/rare_drop_table.rs index 0eb6cc8..b9ab745 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/drops/src/rare_drop_table.rs @@ -11,10 +11,10 @@ use entity::character::SectionID; use maps::monster::MonsterType; use maps::room::{Difficulty, Episode}; use maps::area::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 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/drops/src/tech_table.rs similarity index 98% rename from src/ship/drops/tech_table.rs rename to drops/src/tech_table.rs index 79bf095..9b1101b 100644 --- a/src/ship/drops/tech_table.rs +++ b/drops/src/tech_table.rs @@ -7,7 +7,7 @@ use entity::item::tech::{Technique, TechniqueDisk}; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; use entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; +use crate::{ItemDropType, load_data_file}; diff --git a/src/ship/drops/tool_table.rs b/drops/src/tool_table.rs similarity index 98% rename from src/ship/drops/tool_table.rs rename to drops/src/tool_table.rs index 0ce9e6d..9645c34 100644 --- a/src/ship/drops/tool_table.rs +++ b/drops/src/tool_table.rs @@ -7,8 +7,8 @@ use entity::item::tool::{Tool, ToolType}; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; use entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::drops::tech_table::TechniqueTable; +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/items/Cargo.toml b/items/Cargo.toml new file mode 100644 index 0000000..84ce90c --- /dev/null +++ b/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/items/src/actions.rs similarity index 97% rename from src/ship/items/actions.rs rename to items/src/actions.rs index f5f93f0..873e735 100644 --- a/src/ship/items/actions.rs +++ b/items/src/actions.rs @@ -1,5 +1,5 @@ // TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency -use crate::ship::items::ClientItemId; +use crate::ClientItemId; use entity::item::{Meseta, ItemNote}; use async_std::sync::Arc; use std::future::Future; @@ -15,16 +15,15 @@ use entity::item::{ItemDetail, NewItemEntity, TradeId, ItemModifier}; use entity::item::tool::Tool; use entity::room::RoomEntityId; use maps::area::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::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 crate::ship::drops::{ItemDrop, ItemDropType}; -use crate::ship::packet::builder; -use crate::ship::location::AreaClient; +use drops::{ItemDrop, ItemDropType}; +//use crate::ship::packet::builder; +use location::AreaClient; use maps::monster::MonsterType; pub enum TriggerCreateItem { @@ -32,6 +31,12 @@ pub enum TriggerCreateItem { 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 +1149,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 +1166,8 @@ 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 = 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.clone(), 1); let item_detail = StackedItemDetail { entity_ids: vec![new_item.id], tool @@ -1173,7 +1179,8 @@ 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 = 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 +1194,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/items/src/apply_item.rs similarity index 99% rename from src/ship/items/apply_item.rs rename to items/src/apply_item.rs index ef0e05f..0f74627 100644 --- a/src/ship/items/apply_item.rs +++ b/items/src/apply_item.rs @@ -11,8 +11,8 @@ use entity::item::tool::{Tool, ToolType}; use entity::item::tech::TechniqueDisk; use entity::item::{ItemDetail, ItemEntityId}; use entity::item::weapon::WeaponModifier; -use crate::ship::items::state::ItemStateProxy; -use crate::ship::items::inventory::InventoryItemDetail; +use crate::state::ItemStateProxy; +use crate::inventory::InventoryItemDetail; #[derive(Error, Debug)] diff --git a/src/ship/items/bank.rs b/items/src/bank.rs similarity index 97% rename from src/ship/items/bank.rs rename to items/src/bank.rs index 885aba4..e68700a 100644 --- a/src/ship/items/bank.rs +++ b/items/src/bank.rs @@ -1,15 +1,15 @@ use std::cmp::Ordering; use libpso::character::character; -use crate::ship::items::ClientItemId; +use crate::ClientItemId; use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity}; use std::future::Future; use async_std::sync::{Arc, Mutex}; use entity::character::CharacterEntityId; use 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 crate::state::ItemStateError; +use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; +use crate::inventory::{InventoryItem, InventoryItemDetail}; #[derive(thiserror::Error, Debug)] diff --git a/src/ship/items/floor.rs b/items/src/floor.rs similarity index 94% rename from src/ship/items/floor.rs rename to items/src/floor.rs index 6d03133..29b79fa 100644 --- a/src/ship/items/floor.rs +++ b/items/src/floor.rs @@ -1,4 +1,4 @@ -use crate::ship::items::ClientItemId; +use crate::ClientItemId; use entity::item::{Meseta, ItemEntityId, ItemDetail}; use std::future::Future; @@ -6,9 +6,9 @@ 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, diff --git a/src/ship/items/inventory.rs b/items/src/inventory.rs similarity index 98% rename from src/ship/items/inventory.rs rename to items/src/inventory.rs index e30eb93..d8c0da9 100644 --- a/src/ship/items/inventory.rs +++ b/items/src/inventory.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; use libpso::character::character; -use crate::ship::items::ClientItemId; +use crate::ClientItemId; use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity}; use std::future::Future; use async_std::sync::{Arc, Mutex}; @@ -10,9 +10,9 @@ use entity::item::tool::ToolType; use entity::item::mag::Mag; use entity::item::weapon::Weapon; use 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 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/items/src/itemstateaction.rs similarity index 100% rename from src/ship/items/itemstateaction.rs rename to items/src/itemstateaction.rs diff --git a/src/ship/items/mod.rs b/items/src/lib.rs similarity index 87% rename from src/ship/items/mod.rs rename to items/src/lib.rs index 549ee51..7f4251f 100644 --- a/src/ship/items/mod.rs +++ b/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/manager.rs b/items/src/manager.rs similarity index 99% rename from src/ship/items/manager.rs rename to items/src/manager.rs index e9251c4..d368ec6 100644 --- a/src/ship/items/manager.rs +++ b/items/src/manager.rs @@ -1,4 +1,4 @@ -use crate::ship::items::ClientItemId; +use crate::ClientItemId; use std::collections::HashMap; use std::cmp::Ordering; use std::cell::RefCell; @@ -9,18 +9,18 @@ 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 maps::area::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 drops::{ItemDrop, ItemDropType}; +use location::{AreaClient, RoomId}; +use 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}; +use crate::bank::*; +use crate::floor::*; +use crate::inventory::*; +use crate::transaction::{ItemTransaction, ItemAction, TransactionError, TransactionCommitError}; #[derive(PartialEq, Eq)] pub enum FloorType { diff --git a/src/ship/items/state.rs b/items/src/state.rs similarity index 97% rename from src/ship/items/state.rs rename to items/src/state.rs index 9058c05..aa27143 100644 --- a/src/ship/items/state.rs +++ b/items/src/state.rs @@ -10,12 +10,12 @@ use entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, Ba use entity::item::tool::Tool; use entity::item::weapon::Weapon; use 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 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/items/src/tasks.rs similarity index 97% rename from src/ship/items/tasks.rs rename to items/src/tasks.rs index d4910a1..8a7a307 100644 --- a/src/ship/items/tasks.rs +++ b/items/src/tasks.rs @@ -1,24 +1,23 @@ use futures::future::BoxFuture; -use crate::ship::items::ClientItemId; +use crate::ClientItemId; use entity::item::Meseta; -use crate::ship::ship::SendShipPacket; use maps::area::MapArea; use entity::character::{CharacterEntity, CharacterEntityId}; use entity::gateway::{EntityGateway, EntityGatewayTransaction}; use entity::item::ItemModifier; use 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::state::{ItemState, ItemStateProxy, IndividualItemDetail}; +use crate::itemstateaction::{ItemStateAction, ItemAction}; +use crate::inventory::InventoryItem; +use crate::floor::FloorItem; use shops::ShopItem; -use crate::ship::trade::TradeItem; -use crate::ship::location::AreaClient; -use crate::ship::drops::ItemDrop; +use crate::trade::TradeItem; +use location::AreaClient; +use drops::ItemDrop; use maps::monster::MonsterType; -use crate::ship::items::actions; +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, { diff --git a/items/src/trade.rs b/items/src/trade.rs new file mode 100644 index 0000000..19e49bc --- /dev/null +++ b/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/location/Cargo.toml b/location/Cargo.toml new file mode 100644 index 0000000..f6768c0 --- /dev/null +++ b/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/location/src/lib.rs b/location/src/lib.rs new file mode 100644 index 0000000..dd9bd1e --- /dev/null +++ b/location/src/lib.rs @@ -0,0 +1,3 @@ +pub mod location; + +pub use location::*; diff --git a/src/ship/location.rs b/location/src/location.rs similarity index 99% rename from src/ship/location.rs rename to location/src/location.rs index 5dc805e..3dd0b2b 100644 --- a/src/ship/location.rs +++ b/location/src/location.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/maps/src/enemy.rs b/maps/src/enemy.rs index 033b05d..54ac36d 100644 --- a/maps/src/enemy.rs +++ b/maps/src/enemy.rs @@ -9,17 +9,11 @@ use thiserror::Error; use rand::{Rng, SeedableRng}; use serde::{Serialize, Deserialize}; +use crate::Holiday; use crate::area::{MapArea, MapAreaError}; use crate::room::Episode; use crate::monster::MonsterType; -#[derive(Clone, Copy)] -pub enum RareEnemyEvent { - Easter, - Halloween, - Christmas, -} - #[derive(Debug, Copy, Clone)] pub struct RawMapEnemy { id: u32, @@ -120,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: Option) -> 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) } @@ -362,12 +356,12 @@ impl MapEnemy { guaranteed rare monsters don't count towards the limit */ #[must_use] - pub fn into_rare(self, event: Option) -> 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, Some(RareEnemyEvent::Easter)) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}}, - (MonsterType::RagRappy, Episode::Two, Some(RareEnemyEvent::Halloween)) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}}, - (MonsterType::RagRappy, Episode::Two, Some(RareEnemyEvent::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/maps/src/lib.rs b/maps/src/lib.rs index fa2b60e..2da528c 100644 --- a/maps/src/lib.rs +++ b/maps/src/lib.rs @@ -5,3 +5,55 @@ 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/maps/src/maps.rs b/maps/src/maps.rs index 6684d52..4ca76d9 100644 --- a/maps/src/maps.rs +++ b/maps/src/maps.rs @@ -9,7 +9,8 @@ use thiserror::Error; //use crate::ship::ship::ShipEvent; use crate::area::MapArea; -use crate::enemy::{MapEnemy, RawMapEnemy, RareEnemyEvent, RareMonsterAppearTable}; +use crate::Holiday; +use crate::enemy::{MapEnemy, RawMapEnemy, RareMonsterAppearTable}; use crate::monster::MonsterType; use crate::variant::{MapVariant, MapVariantMode}; use crate::object::{MapObject, RawMapObject}; @@ -325,7 +326,7 @@ impl Maps { enemies: Vec>, objects: Vec>, rare_monster_table: &RareMonsterAppearTable, - event: Option) + event: Holiday) { self.enemy_data = enemies .into_iter() @@ -358,7 +359,7 @@ impl Maps { } } -pub fn generate_free_roam_maps(room_mode: RoomMode, event: Option) -> 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 { diff --git a/networking/Cargo.toml b/networking/Cargo.toml index b0ee8a2..1ecadc9 100644 --- a/networking/Cargo.toml +++ b/networking/Cargo.toml @@ -2,3 +2,17 @@ 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/networking/src/cipherkeys.rs similarity index 100% rename from src/common/cipherkeys.rs rename to networking/src/cipherkeys.rs diff --git a/src/common/interserver.rs b/networking/src/interserver.rs similarity index 100% rename from src/common/interserver.rs rename to networking/src/interserver.rs diff --git a/networking/src/lib.rs b/networking/src/lib.rs index e69de29..c8adde9 100644 --- a/networking/src/lib.rs +++ b/networking/src/lib.rs @@ -0,0 +1,18 @@ +pub mod cipherkeys; +pub mod serverstate; +pub mod mainloop; +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/common/mainloop/client.rs b/networking/src/mainloop/client.rs similarity index 97% rename from src/common/mainloop/client.rs rename to networking/src/mainloop/client.rs index d7af211..3bcb971 100644 --- a/src/common/mainloop/client.rs +++ b/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)] @@ -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/networking/src/mainloop/interserver.rs similarity index 95% rename from src/common/mainloop/interserver.rs rename to networking/src/mainloop/interserver.rs index 0465f43..5e5194b 100644 --- a/src/common/mainloop/interserver.rs +++ b/networking/src/mainloop/interserver.rs @@ -8,11 +8,10 @@ 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::serverstate::{ServerState, SendServerPacket, RecvServerPacket}; use entity::gateway::entitygateway::EntityGateway; use async_std::channel; @@ -148,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; @@ -195,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(); diff --git a/src/common/mainloop/mod.rs b/networking/src/mainloop/mod.rs similarity index 100% rename from src/common/mainloop/mod.rs rename to networking/src/mainloop/mod.rs diff --git a/src/common/serverstate.rs b/networking/src/serverstate.rs similarity index 100% rename from src/common/serverstate.rs rename to networking/src/serverstate.rs diff --git a/pktbuilder/Cargo.toml b/pktbuilder/Cargo.toml new file mode 100644 index 0000000..9c070f9 --- /dev/null +++ b/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/pktbuilder/src/character.rs similarity index 98% rename from src/ship/character.rs rename to pktbuilder/src/character.rs index 90ba63b..5d57896 100644 --- a/src/ship/character.rs +++ b/pktbuilder/src/character.rs @@ -1,9 +1,8 @@ use libpso::character::character; use stats::leveltable::CharacterStats; use entity::character::CharacterEntity; -//use crate::ship::items::{CharacterInventory, CharacterBank}; -use crate::ship::items::bank::BankState; -use crate::ship::items::inventory::InventoryState; +use items::bank::BankState; +use items::inventory::InventoryState; use entity::item::Meseta; diff --git a/src/ship/packet/builder/mod.rs b/pktbuilder/src/lib.rs similarity index 88% rename from src/ship/packet/builder/mod.rs rename to pktbuilder/src/lib.rs index 4872aaa..bdcd755 100644 --- a/src/ship/packet/builder/mod.rs +++ b/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 stats::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 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 { diff --git a/src/ship/packet/builder/lobby.rs b/pktbuilder/src/lobby.rs similarity index 91% rename from src/ship/packet/builder/lobby.rs rename to pktbuilder/src/lobby.rs index af033ca..34587c5 100644 --- a/src/ship/packet/builder/lobby.rs +++ b/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/pktbuilder/src/message.rs similarity index 74% rename from src/ship/packet/builder/message.rs rename to pktbuilder/src/message.rs index d420187..cf843df 100644 --- a/src/ship/packet/builder/message.rs +++ b/pktbuilder/src/message.rs @@ -2,20 +2,20 @@ use libpso::packet::messages::*; use libpso::packet::ship::*; use entity::item; use stats::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 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 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/pktbuilder/src/quest.rs similarity index 94% rename from src/ship/packet/builder/quest.rs rename to pktbuilder/src/quest.rs index f162269..d3f2f4f 100644 --- a/src/ship/packet/builder/quest.rs +++ b/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}; +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() diff --git a/src/ship/packet/builder/room.rs b/pktbuilder/src/room.rs similarity index 85% rename from src/ship/packet/builder/room.rs rename to pktbuilder/src/room.rs index 1f922a1..a7bbe75 100644 --- a/src/ship/packet/builder/room.rs +++ b/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,14 +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); @@ -58,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/pktbuilder/src/ship.rs similarity index 85% rename from src/ship/packet/builder/ship.rs rename to pktbuilder/src/ship.rs index 1411f2a..41c6ea0 100644 --- a/src/ship/packet/builder/ship.rs +++ b/pktbuilder/src/ship.rs @@ -1,8 +1,9 @@ use libpso::packet::login::{ShipList, ShipListEntry}; use libpso::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() diff --git a/pktbuilder/src/team.rs b/pktbuilder/src/team.rs new file mode 100644 index 0000000..9ebdfb9 --- /dev/null +++ b/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/pktbuilder/src/trade.rs similarity index 100% rename from src/ship/packet/builder/trade.rs rename to pktbuilder/src/trade.rs diff --git a/quests/Cargo.toml b/quests/Cargo.toml new file mode 100644 index 0000000..6cab926 --- /dev/null +++ b/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/quests/src/lib.rs b/quests/src/lib.rs new file mode 100644 index 0000000..de40457 --- /dev/null +++ b/quests/src/lib.rs @@ -0,0 +1,4 @@ +pub mod quests; + + +pub use quests::*; diff --git a/src/ship/quests.rs b/quests/src/quests.rs similarity index 100% rename from src/ship/quests.rs rename to quests/src/quests.rs diff --git a/room/Cargo.toml b/room/Cargo.toml new file mode 100644 index 0000000..361b597 --- /dev/null +++ b/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/room/src/lib.rs b/room/src/lib.rs new file mode 100644 index 0000000..4f8d063 --- /dev/null +++ b/room/src/lib.rs @@ -0,0 +1,3 @@ +pub mod room; + +pub use room::*; diff --git a/src/ship/room.rs b/room/src/room.rs similarity index 90% rename from src/ship/room.rs rename to room/src/room.rs index 441feb5..a065d55 100644 --- a/src/ship/room.rs +++ b/room/src/room.rs @@ -8,21 +8,28 @@ use thiserror::Error; use rand::Rng; use maps::maps::Maps; -use crate::ship::drops::DropTable; +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::enemy::RareEnemyEvent; -use crate::ship::quests; -use crate::ship::ship::{ShipError, ShipEvent}; -use crate::ship::location::{MAX_ROOMS, RoomId}; +use quests; +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)))) @@ -33,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_else(|| RoomError::Invalid(room_id.0 as u32))? .write() .await = Some(room); Ok(()) @@ -66,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_else(|| 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()) } } @@ -84,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_else(|| RoomError::Invalid(room_id.0 as u32))? .write() .await; @@ -92,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()) } } @@ -222,8 +229,8 @@ impl RoomState { section_id: SectionID, name: String, password: [u16; 16], - event: ShipEvent, - map_builder: Arc) -> Maps + Send + Sync>>, + event: Holiday, + map_builder: Arc Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, ) -> Result { let mode = match mode { @@ -251,7 +258,7 @@ impl RoomState { random_seed: rand::thread_rng().gen(), name, password, - maps: map_builder(mode, event.rare_enemy_event()), + maps: map_builder(mode, event), section_id, drop_table: Box::new(drop_table_builder(episode, difficulty, section_id)), bursting: false, diff --git a/src/bin/login.rs b/src/bin/login.rs index 28d78f0..f4c5335 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -2,7 +2,7 @@ use log::{info}; use entity::gateway::postgres::PostgresGateway; use elseware::login::login::LoginServerState; use elseware::login::character::CharacterServerState; -use elseware::common::interserver::AuthToken; +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, elseware::login::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, elseware::login::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, elseware::login::login::COMMUNICATION_PORT).await; }); info!("[auth/character] starting server"); diff --git a/src/bin/main.rs b/src/bin/main.rs index 23aa720..34e5793 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,13 +1,13 @@ use std::net::Ipv4Addr; use log::{info}; -use elseware::common::interserver::AuthToken; +use networking::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 elseware::ship::ship::ShipServerStateBuilder; -#[allow(unused_imports)] +use maps::Holiday; use entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; use entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use entity::character::NewCharacterEntity; @@ -338,25 +338,25 @@ 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, elseware::login::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, elseware::login::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, elseware::login::login::COMMUNICATION_PORT).await; }); info!("[ship] starting servers"); @@ -364,32 +364,32 @@ fn main() { .name("US/Sona-Nyl".into()) .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT) - .event(ShipEvent::Halloween) + .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, elseware::ship::ship::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), elseware::login::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) + .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, elseware::ship::ship::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), elseware::login::login::COMMUNICATION_PORT).await; }); let ship_state = ShipServerStateBuilder::default() @@ -400,11 +400,11 @@ fn main() { .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, elseware::ship::ship::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), elseware::login::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 6716391..fc9eff8 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 log::info; fn main() { info!("[patch] starting server"); @@ -9,7 +9,7 @@ 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(patch_loop); diff --git a/src/bin/ship.rs b/src/bin/ship.rs index 0f289b7..c021601 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -1,7 +1,7 @@ -use log::{info}; +use log::info; use entity::gateway::postgres::PostgresGateway; use elseware::ship::ship::ShipServerStateBuilder; -use elseware::common::interserver::AuthToken; +use networking::interserver::AuthToken; fn main() { let colors = fern::colors::ColoredLevelConfig::new() @@ -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, elseware::ship::ship::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, elseware::login::login::COMMUNICATION_PORT).await; }); info!("[auth/character] starting server"); diff --git a/src/common/mod.rs b/src/common/mod.rs deleted file mode 100644 index c8adde9..0000000 --- a/src/common/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod cipherkeys; -pub mod serverstate; -pub mod mainloop; -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/lib.rs b/src/lib.rs index 3802b3c..f194399 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,11 +5,10 @@ #![feature(try_blocks)] #![feature(test)] #![feature(error_generic_member_access)] -#![feature(lazy_cell)] extern crate test; -pub mod common; +//pub mod common; //pub mod entity; pub mod patch; pub mod login; diff --git a/src/login/character.rs b/src/login/character.rs index ef74730..6529f3d 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -15,9 +15,9 @@ use libpso::crypto::bb::PSOBBCipher; 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 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::{utf8_to_array, utf8_to_utf16_array}; @@ -32,10 +32,11 @@ use entity::item::mag::Mag; use entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel}; use crate::login::login::{get_login_status}; -use crate::common::interserver::AuthToken; +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 { diff --git a/src/login/login.rs b/src/login/login.rs index 4b1433c..cdc32d9 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -11,8 +11,8 @@ 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 entity::gateway::EntityGateway; use entity::account::{UserAccountEntity}; diff --git a/src/patch/patch.rs b/src/patch/patch.rs index 26441f8..565530d 100644 --- a/src/patch/patch.rs +++ b/src/patch/patch.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 { diff --git a/src/ship/chatcommand.rs b/src/ship/chatcommand.rs index 7d2c643..7799e17 100644 --- a/src/ship/chatcommand.rs +++ b/src/ship/chatcommand.rs @@ -1,11 +1,11 @@ use libpso::packet::ship::PlayerChat; use entity::gateway::EntityGateway; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use crate::ship::ship::{ShipServerState, SendShipPacket}; -use crate::ship::client::Clients; -use crate::ship::items::state::ItemState; +use client::Clients; +use items::state::ItemState; use entity::item::{BankName, BankIdentifier}; -use crate::ship::packet::builder::message::bank_item_list; +use pktbuilder::message::bank_item_list; async fn default_bank<'a, EG>(id: ClientId, entity_gateway: &mut EG, 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/mod.rs b/src/ship/mod.rs index d769c38..f6ada33 100644 --- a/src/ship/mod.rs +++ b/src/ship/mod.rs @@ -1,16 +1,16 @@ #[allow(clippy::module_inception)] pub mod ship; -pub mod location; -pub mod character; -pub mod client; -pub mod room; -pub mod items; +//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 drops; pub mod packet; -pub mod quests; +//pub mod quests; //pub mod shops; -pub mod trade; +//pub mod trade; pub mod chatcommand; diff --git a/src/ship/monster.rs b/src/ship/monster.rs deleted file mode 100644 index 1bdb5b7..0000000 --- a/src/ship/monster.rs +++ /dev/null @@ -1,212 +0,0 @@ -#![allow(dead_code)] -use std::collections::HashMap; -use std::fs::File; -use std::io::Read; -use std::path::PathBuf; -use serde::{Serialize, Deserialize}; -use crate::ship::room::{Difficulty, Episode, RoomMode}; - - -#[derive(Debug)] -pub enum MonsterParseError { - UnknownMonster(String), -} - -pub struct MonsterStatError; - -#[derive(Debug, Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, enum_utils::FromStr, derive_more::Display)] -pub enum MonsterType { - Hildebear, - Hildeblue, - Mothmant, - Monest, - RagRappy, - AlRappy, - SavageWolf, - BarbarousWolf, - Booma, - Gobooma, - Gigobooma, - GrassAssassin, - PoisonLily, - NarLily, - NanoDragon, - EvilShark, - PalShark, - GuilShark, - PofuillySlime, - PouillySlime, - PanArms, - Hidoom, - Migium, - Dubchic, - Garanz, - SinowBeat, - SinowGold, - Canadine, - Canane, - RingCanadine, - Delsaber, - ChaosSorcerer, - BeeR, - BeeL, - DarkGunner, - DeathGunner, - ChaosBringer, - DarkBelra, - Claw, - Bulk, - Bulclaw, - Dimenian, - LaDimenian, - SoDimenian, - Dragon, - DeRolLe, - DeRolLeBody, - DeRolLeMine, - VolOptPartA, - VolOptPillar, - VolOptMonitor, - VolOptAmp, - VolOptCore, - VolOptUnused, - VolOpt, - VolOptTrap, - DarkFalz, - DarkFalz1, - DarkFalz2, - DarkFalz3, - Darvant, - UltDarvant, - Dubwitch, - Gillchic, - EventRappy, - Merillia, - Meriltas, - Gee, - GiGue, - Mericarol, - Merikle, - Mericus, - UlGibbon, - ZolGibbon, - Gibbles, - SinowBerill, - SinowSpigell, - Dolmolm, - Dolmdarl, - Morfos, - Recobox, - Recon, - SinowZoa, - SinowZele, - Deldepth, - Delbiter, - BarbaRay, - PigRay, - GolDragon, - GalGryphon, - OlgaFlow, - OlgaFlow1, - OlgaFlow2, - Gael, - Giel, - StRappy, - HalloRappy, - EasterRappy, - LoveRappy, - IllGill, - DelLily, - Epsilon, - Epsiguard, - Boota, - ZeBoota, - BaBoota, - SandRappyCrater, - SandRappyDesert, - ZuCrater, - PazuzuCrater, - Astark, - SatelliteLizardCrater, - YowieCrater, - Dorphon, - DorphonEclair, - Goran, - GoranDetonator, - PyroGoran, - DelRappyCrater, - DelRappyDesert, - MerissaA, - MerissaAA, - ZuDesert, - PazuzuDesert, - SatelliteLizardDesert, - YowieDesert, - Girtablulu, - SaintMillion, - Shambertin, - Kondrieu, -} - - -#[derive(serde::Deserialize, Debug)] -pub struct MonsterStats { - pub atp: u16, - pub mst: u16, - pub evp: u16, - pub hp: u16, - pub dfp: u16, - pub ata: u16, - pub lck: u16, - pub esp: u16, - pub exp: u32, -} - -fn load_battle_param(filename: &str) -> HashMap { - let mut path = PathBuf::from("data/battle_param/"); - path.push(filename); - - 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() - .into_iter() - .map(|(monster_name, stats)| { - (monster_name.parse().unwrap(), stats) - }).collect() -} - -pub fn load_monster_stats_table(mode: &RoomMode) -> Result, MonsterStatError> { - match mode { - RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep1_multi_normal.toml")), - RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep1_multi_hard.toml")), - RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep1_multi_veryhard.toml")), - RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep1_multi_ultimate.toml")), - - RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep2_multi_normal.toml")), - RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep2_multi_hard.toml")), - RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep2_multi_veryhard.toml")), - RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep2_multi_ultimate.toml")), - - RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep4_multi_normal.toml")), - RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep4_multi_hard.toml")), - RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep4_multi_veryhard.toml")), - RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep4_multi_ultimate.toml")), - - RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep1_solo_normal.toml")), - RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep1_solo_hard.toml")), - RoomMode::Single {episode: Episode::One, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep1_solo_veryhard.toml")), - RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep1_solo_ultimate.toml")), - - RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep2_solo_normal.toml")), - RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep2_solo_hard.toml")), - RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep2_solo_veryhard.toml")), - RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep2_solo_ultimate.toml")), - - RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep4_solo_normal.toml")), - RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep4_solo_hard.toml")), - RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep4_solo_veryhard.toml")), - RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep4_solo_ultimate.toml")), - _ => Err(MonsterStatError), - } -} diff --git a/src/ship/packet/handler/auth.rs b/src/ship/packet/handler/auth.rs index bd0c846..915da68 100644 --- a/src/ship/packet/handler/auth.rs +++ b/src/ship/packet/handler/auth.rs @@ -1,11 +1,11 @@ use libpso::packet::login::{Login, LoginResponse, AccountStatus, Session}; use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; use crate::login::login::get_login_status; use entity::gateway::EntityGateway; -use crate::ship::items::state::ItemState; -use crate::common::interserver::ShipMessage; +use items::state::ItemState; +use networking::interserver::ShipMessage; #[allow(clippy::too_many_arguments)] pub async fn validate_login(id: ClientId, diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs index 2f7ef43..3982efc 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship/packet/handler/communication.rs @@ -1,7 +1,7 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, Clients}; -use crate::ship::location::{ClientLocation}; +use location::{ClientLocation}; use entity::gateway::EntityGateway; use futures::future::join_all; diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index dea6911..090d77d 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -4,21 +4,21 @@ use rand::seq::SliceRandom; use libpso::packet::ship::*; use libpso::packet::messages::*; use stats::leveltable::LEVEL_TABLE; -use crate::common::serverstate::ClientId; +use networking::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 location::ClientLocation; +use drops::ItemDrop; +use room::Rooms; +use items::ClientItemId; use entity::gateway::EntityGateway; use entity::item; use libpso::utf8_to_utf16_array; -use crate::ship::packet::builder; +use pktbuilder as builder; use 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 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; @@ -122,7 +122,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 +149,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 +234,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 +293,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)))] } }, @@ -440,7 +440,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 +503,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 +539,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/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index d085cc6..3033091 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -1,12 +1,14 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use stats::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::ship::ship::{SendShipPacket, ShipError}; +use maps::Holiday; +use client::Clients; +use room::Rooms; +use pktbuilder::character::FullCharacterBytesBuilder; +use location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; +//use pktbuilder; +use items::state::ItemState; use entity::gateway::EntityGateway; use entity::room::RoomNote; use maps::area::MapArea; @@ -57,11 +59,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 +79,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 +113,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 +133,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/packet/handler/message.rs index 497f2d9..ca731c9 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -2,15 +2,16 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; use entity::gateway::EntityGateway; use entity::item::Meseta; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use stats::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 crate::ship::ship::{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/packet/handler/quest.rs index b219684..6193530 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/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 networking::serverstate::ClientId; +use crate::ship::ship::{SendShipPacket, ShipError}; +use client::Clients; +use maps::Holiday; +use room::Rooms; use maps::enemy::RareMonsterAppearTable; -use crate::ship::location::{ClientLocation}; -use crate::ship::packet::builder::quest; +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?; @@ -118,7 +120,7 @@ pub async fn player_chose_quest(id: ClientId, .clone(); let rare_monster_table = RareMonsterAppearTable::new(room.mode.episode()); - room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_table, event.rare_enemy_event()); + room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_table, event); room.map_areas = quest.map_areas.clone(); let bin = quest::quest_header(&questmenuselect, &quest.bin_blob, "bin"); diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 9fc8ccc..26e98b4 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -5,20 +5,21 @@ use async_std::sync::Arc; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use stats::leveltable::LEVEL_TABLE; use entity::gateway::EntityGateway; use entity::character::SectionID; use entity::room::{NewRoomEntity, RoomEntityMode, RoomNote}; -use crate::ship::drops::DropTable; -use crate::ship::ship::{SendShipPacket, Clients, ShipEvent}; -use crate::ship::room::{Rooms, RoomState, RoomCreationError}; +use drops::DropTable; +use crate::ship::ship::SendShipPacket; +use client::Clients; +use room::{Rooms, RoomState, RoomCreationError}; +use maps::Holiday; use maps::room::{Episode, Difficulty, RoomMode}; -use maps::enemy::RareEnemyEvent; use maps::maps::Maps; -use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; -use crate::ship::packet::builder; -use crate::ship::items::state::ItemState; +use location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; +use pktbuilder as builder; +use items::state::ItemState; #[allow(clippy::too_many_arguments)] pub async fn create_room(id: ClientId, @@ -28,9 +29,9 @@ pub async fn create_room(id: ClientId, clients: &Clients, item_state: &mut ItemState, rooms: &Rooms, - map_builder: Arc) -> Maps + Send + Sync>>, + map_builder: Arc Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, - event: ShipEvent) + event: Holiday) -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, @@ -136,7 +137,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, diff --git a/src/ship/packet/handler/settings.rs b/src/ship/packet/handler/settings.rs index c8ebd52..4bd665d 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship/packet/handler/settings.rs @@ -1,5 +1,5 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, Clients}; use entity::gateway::EntityGateway; diff --git a/src/ship/packet/handler/ship.rs b/src/ship/packet/handler/ship.rs index a63ebdf..762e73f 100644 --- a/src/ship/packet/handler/ship.rs +++ b/src/ship/packet/handler/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 networking::serverstate::ClientId; +use networking::interserver::Ship; use crate::ship::ship::{SendShipPacket, ShipError}; -use crate::ship::packet::builder; +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/packet/handler/trade.rs index f3128d0..8da8f38 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship/packet/handler/trade.rs @@ -1,19 +1,19 @@ use std::convert::TryInto; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::serverstate::ClientId; +use networking::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 location::{ClientLocation}; +use items::ClientItemId; +use items::state::{ItemState, ItemStateError}; +use items::inventory::InventoryItemDetail; +use items::trade::TradeItem; use entity::gateway::EntityGateway; -use crate::ship::packet::builder; -use crate::ship::items::tasks::trade_items; -use crate::ship::location::{AreaClient, RoomId}; +use pktbuilder as builder; +use items::tasks::trade_items; +use location::{AreaClient, RoomId}; use entity::item::Meseta; -use crate::ship::trade::ClientTradeState; +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/ship/packet/mod.rs b/src/ship/packet/mod.rs index 5b46ce1..9b5f908 100644 --- a/src/ship/packet/mod.rs +++ b/src/ship/packet/mod.rs @@ -1,2 +1,2 @@ -pub mod builder; +//pub mod builder; pub mod handler; diff --git a/src/ship/ship.rs b/src/ship/ship.rs index ec3f132..33e8aa6 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -14,31 +14,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 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 crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; -use crate::ship::drops::DropTable; -use crate::ship::items; -use crate::ship::room; +use location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; +use drops::DropTable; +use items; +use room; +use maps::Holiday; use maps::area::MapAreaError; use maps::maps::{Maps, MapsError, generate_free_roam_maps}; -use maps::enemy::RareEnemyEvent; use crate::ship::packet::handler; use shops::{WeaponShop, ToolShop, ArmorShop}; -use crate::ship::trade::TradeState; +use trade::TradeState; use crate::ship::chatcommand; +use pktbuilder::quest::{QUEST_CATEGORY_MENU_ID, QUEST_SELECT_MENU_ID}; -// TODO: remove once stuff settles down -pub use crate::ship::client::*; +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(Error, Debug)] @@ -100,7 +98,7 @@ pub enum ShipError { #[error("trade error {0}")] TradeError(#[from] crate::ship::packet::handler::trade::TradeError), #[error("trade state error {0}")] - TradeStateError(#[from] crate::ship::trade::TradeStateError), + TradeStateError(#[from] trade::TradeStateError), #[error("message error {0}")] MessageError(#[from] crate::ship::packet::handler::direct_message::MessageError), #[error("room creation error {0}")] @@ -117,69 +115,6 @@ impl> From for ShipError { } */ -#[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, - } - } -} - -impl ShipEvent { - pub fn rare_enemy_event(&self) -> Option { - match self { - ShipEvent::Easter => Some(RareEnemyEvent::Easter), - ShipEvent::Halloween => Some(RareEnemyEvent::Halloween), - ShipEvent::Christmas => Some(RareEnemyEvent::Christmas), - _ => None, - } - } -} - #[derive(Debug)] @@ -391,8 +326,8 @@ pub struct ShipServerStateBuilder { ip: Option, port: Option, auth_token: Option, - event: Option, - map_builder: Option) -> Maps + Send + Sync>>, + event: Option, + map_builder: Option Maps + Send + Sync>>, drop_table_builder: Option DropTable + Send + Sync>>, num_blocks: usize, } @@ -445,13 +380,13 @@ 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 } @@ -479,7 +414,7 @@ impl ShipServerStateBuilder { port: self.port.unwrap_or(SHIP_PORT), shops: ItemShops::default(), blocks: Blocks(blocks), - event: self.event.unwrap_or(ShipEvent::None), + event: self.event.unwrap_or(Holiday::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))), @@ -520,7 +455,7 @@ pub struct ShipServerState { pub(crate) item_state: items::state::ItemState, shops: ItemShops, pub blocks: Blocks, - event: ShipEvent, + event: Holiday, ip: Ipv4Addr, port: u16, @@ -529,7 +464,7 @@ pub struct ShipServerState { ship_list: Arc>>, shipgate_sender: Option>, trades: TradeState, - map_builder: Arc) -> Maps + Send + Sync>>, + map_builder: Arc Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, } diff --git a/tests/common.rs b/tests/common.rs index 6c8b577..1c11777 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -1,10 +1,10 @@ #![allow(dead_code)] -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::EntityGateway; use entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; use entity::character::{CharacterEntity, NewCharacterEntity}; -use entity::item::{Meseta, BankName, BankIdentifier}; +use entity::item::{Meseta, BankIdentifier}; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; use maps::room::Difficulty; diff --git a/tests/test_bank.rs b/tests/test_bank.rs index 227e043..c7d7f20 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -1,5 +1,5 @@ use std::collections::BTreeSet; -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; diff --git a/tests/test_character.rs b/tests/test_character.rs index 9ea3c93..9052c74 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -1,4 +1,4 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 6cecb60..13a0eca 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -1,8 +1,7 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::common::leveltable::CharacterLevelTable; +use stats::leveltable::CharacterLevelTable; use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; -use elseware::ship::location::RoomId; use maps::variant::{MapVariant, MapVariantMode}; use maps::maps::Maps; use maps::area::MapArea; diff --git a/tests/test_item_actions.rs b/tests/test_item_actions.rs index d840cab..9964bd6 100644 --- a/tests/test_item_actions.rs +++ b/tests/test_item_actions.rs @@ -1,4 +1,4 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; use entity::item; diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs index 3f2f55a..20b6a98 100644 --- a/tests/test_item_drop.rs +++ b/tests/test_item_drop.rs @@ -1,13 +1,9 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use entity::gateway::{EntityGateway, InMemoryGateway}; -use entity::character::SectionID; -use elseware::common::leveltable::CharacterLevelTable; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::InMemoryGateway; use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; -use maps::room::{Episode, Difficulty}; use maps::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 drops::{DropTable, MonsterDropStats, MonsterDropType}; +use drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; use maps::maps::Maps; use maps::area::MapArea; use maps::variant::{MapVariant, MapVariantMode}; diff --git a/tests/test_item_id.rs b/tests/test_item_id.rs index 0d8d70e..06ec3b4 100644 --- a/tests/test_item_id.rs +++ b/tests/test_item_id.rs @@ -1,9 +1,7 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use entity::character::TechLevel; -//use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; use libpso::packet::ship::*; use libpso::packet::messages::*; diff --git a/tests/test_item_pickup.rs b/tests/test_item_pickup.rs index ca1b118..fd38cb1 100644 --- a/tests/test_item_pickup.rs +++ b/tests/test_item_pickup.rs @@ -1,4 +1,4 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; diff --git a/tests/test_item_use.rs b/tests/test_item_use.rs index fab748b..67a29b2 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -1,9 +1,8 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; use entity::character::TechLevel; -//use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; use libpso::packet::ship::*; use libpso::packet::messages::*; diff --git a/tests/test_mags.rs b/tests/test_mags.rs index fe098d9..68adbcd 100644 --- a/tests/test_mags.rs +++ b/tests/test_mags.rs @@ -1,4 +1,4 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index 73c2a77..cb10dfb 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -1,8 +1,6 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; -use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; -use elseware::ship::location::RoomId; use libpso::packet::ship::*; //use libpso::packet::messages::*; diff --git a/tests/test_shops.rs b/tests/test_shops.rs index 6a94a04..c54d907 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -1,9 +1,9 @@ -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; +use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; use maps::room::Difficulty; -use elseware::ship::items::state::ItemStateError; +use items::state::ItemStateError; use libpso::packet::ship::*; use libpso::packet::messages::*; diff --git a/tests/test_trade.rs b/tests/test_trade.rs index a895ed4..9799156 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -1,5 +1,5 @@ use std::convert::TryInto; -use elseware::common::serverstate::{ClientId, ServerState}; +use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; diff --git a/trade/Cargo.toml b/trade/Cargo.toml new file mode 100644 index 0000000..9d588b4 --- /dev/null +++ b/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/trade/src/lib.rs b/trade/src/lib.rs new file mode 100644 index 0000000..2629bda --- /dev/null +++ b/trade/src/lib.rs @@ -0,0 +1,4 @@ +pub mod trade; + + +pub use trade::*; diff --git a/src/ship/trade.rs b/trade/src/trade.rs similarity index 79% rename from src/ship/trade.rs rename to trade/src/trade.rs index abe1cd2..a6a7b18 100644 --- a/src/ship/trade.rs +++ b/trade/src/trade.rs @@ -1,45 +1,9 @@ use std::collections::HashMap; -use crate::common::serverstate::ClientId; -use crate::ship::items; +use networking::serverstate::ClientId; +use items; 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 { From 9cff5ad0884b40cf9bb63b4cfd86dc75de74a2e6 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 14:41:00 -0700 Subject: [PATCH 13/29] clippy cleanup --- client/src/client.rs | 6 +++--- items/src/actions.rs | 6 +----- items/src/tasks.rs | 2 ++ room/Cargo.toml | 2 +- room/src/room.rs | 8 ++++---- src/bin/main.rs | 2 +- src/ship/mod.rs | 12 ------------ 7 files changed, 12 insertions(+), 26 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index 21b2281..e75ceaa 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -52,7 +52,7 @@ impl Clients { .await; let client = clients .get(&client_id) - .ok_or_else(|| ClientError::NotFound(client_id))? + .ok_or(ClientError::NotFound(client_id))? .read() .await; @@ -75,7 +75,7 @@ impl Clients { for (cindex, client_id) in client_ids.iter().enumerate() { let c = clients .get(client_id) - .ok_or_else(|| ClientError::NotFound(*client_id))? + .ok_or(ClientError::NotFound(*client_id))? .read() .await; client_states[cindex].write(c); @@ -101,7 +101,7 @@ impl Clients { .await; let mut client = clients .get(&client_id) - .ok_or_else(|| ClientError::NotFound(client_id))? + .ok_or(ClientError::NotFound(client_id))? .write() .await; diff --git a/items/src/actions.rs b/items/src/actions.rs index 873e735..0b55d6d 100644 --- a/items/src/actions.rs +++ b/items/src/actions.rs @@ -8,7 +8,6 @@ use std::pin::Pin; use std::iter::IntoIterator; use anyhow::Context; -use libpso::packet::{ship::Message, messages::GameMessage}; use entity::character::{CharacterEntity, CharacterEntityId}; use entity::gateway::{EntityGateway, EntityGatewayTransaction}; use entity::item::{ItemDetail, NewItemEntity, TradeId, ItemModifier}; @@ -22,7 +21,6 @@ use crate::floor::{FloorItem, FloorItemDetail}; use crate::apply_item::{apply_item, ApplyItemAction}; use shops::ShopItem; use drops::{ItemDrop, ItemDropType}; -//use crate::ship::packet::builder; use location::AreaClient; use maps::monster::MonsterType; @@ -1166,8 +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.clone(), 1); + let create_item = CreateItem::Stacked(area_client, item_id, tool, 1); let item_detail = StackedItemDetail { entity_ids: vec![new_item.id], tool @@ -1179,7 +1176,6 @@ 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) }; diff --git a/items/src/tasks.rs b/items/src/tasks.rs index 8a7a307..cf313fc 100644 --- a/items/src/tasks.rs +++ b/items/src/tasks.rs @@ -371,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/room/Cargo.toml b/room/Cargo.toml index 361b597..d081284 100644 --- a/room/Cargo.toml +++ b/room/Cargo.toml @@ -10,7 +10,7 @@ quests = { workspace = true } location = { workspace = true } drops = { workspace = true } -rand= { workspace = true } +rand = { workspace = true } async-std = { workspace = true } futures = { workspace = true } anyhow = { workspace = true } diff --git a/room/src/room.rs b/room/src/room.rs index a065d55..5110d22 100644 --- a/room/src/room.rs +++ b/room/src/room.rs @@ -40,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(|| RoomError::Invalid(room_id.0 as u32))? + .ok_or(RoomError::Invalid(room_id.0 as u32))? .write() .await = Some(room); Ok(()) @@ -73,7 +73,7 @@ impl Rooms { { let room = self.0 .get(room_id.0) - .ok_or_else(|| RoomError::Invalid(room_id.0 as u32))? + .ok_or(RoomError::Invalid(room_id.0 as u32))? .read() .await; if let Some(room) = room.as_ref() { @@ -91,7 +91,7 @@ impl Rooms { { let mut room = self.0 .get(room_id.0) - .ok_or_else(|| RoomError::Invalid(room_id.0 as u32))? + .ok_or(RoomError::Invalid(room_id.0 as u32))? .write() .await; @@ -221,7 +221,7 @@ impl RoomState { } } - #[allow(clippy::too_many_arguments)] + #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub fn new (room_id: RoomEntityId, mode: RoomEntityMode, episode: Episode, diff --git a/src/bin/main.rs b/src/bin/main.rs index 34e5793..18fdfbd 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -8,7 +8,7 @@ use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, use elseware::ship::ship::ShipServerStateBuilder; use maps::Holiday; -use entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; +use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use entity::character::NewCharacterEntity; use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; diff --git a/src/ship/mod.rs b/src/ship/mod.rs index f6ada33..cf2a804 100644 --- a/src/ship/mod.rs +++ b/src/ship/mod.rs @@ -1,16 +1,4 @@ #[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; From 2570749fbb54daec91a173b295c14b254f349d9c Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 15:18:21 -0700 Subject: [PATCH 14/29] remove another ci cache --- .drone.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.drone.yml b/.drone.yml index a8f5ce2..ac685b1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -9,23 +9,14 @@ concurrency: steps: - name: build image: rustlang/rust:nightly - volumes: - - name: cache - path: /usr/local/cargo commands: - cargo build - name: clippy! image: rustlang/rust:nightly - volumes: - - name: cache - path: /usr/local/cargo commands: - cargo clippy -- --deny warnings - name: test image: rustlang/rust:nightly - volumes: - - name: cache - path: /usr/local/cargo commands: - cargo test --jobs 1 From 402667d6271038d41a3009c2002e63b580121ec2 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 15:20:43 -0700 Subject: [PATCH 15/29] remove some redundant files --- client/src/client.rs | 178 ---------- client/src/lib.rs | 179 ++++++++++- location/src/lib.rs | 677 ++++++++++++++++++++++++++++++++++++++- location/src/location.rs | 676 -------------------------------------- quests/src/lib.rs | 328 ++++++++++++++++++- quests/src/quests.rs | 328 ------------------- room/src/lib.rs | 273 +++++++++++++++- room/src/room.rs | 272 ---------------- trade/src/lib.rs | 132 +++++++- trade/src/trade.rs | 132 -------- 10 files changed, 1579 insertions(+), 1596 deletions(-) delete mode 100644 client/src/client.rs delete mode 100644 location/src/location.rs delete mode 100644 quests/src/quests.rs delete mode 100644 room/src/room.rs delete mode 100644 trade/src/trade.rs diff --git a/client/src/client.rs b/client/src/client.rs deleted file mode 100644 index e75ceaa..0000000 --- a/client/src/client.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::collections::HashMap; -use async_std::sync::{Arc, RwLock, RwLockReadGuard}; - -use futures::future::BoxFuture; - -use libpso::packet::ship::*; -use libpso::packet::login::Session; - -use networking::serverstate::ClientId; -use entity::account::{UserAccountEntity, UserSettingsEntity}; -use entity::character::CharacterEntity; -use entity::item; - -use items; -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)] -pub struct Clients(Arc>>>); - -impl Clients { - pub async fn add(&mut self, client_id: ClientId, client_state: ClientState) { - self.0 - .write() - .await - .insert(client_id, RwLock::new(client_state)); - } - - pub async fn remove(&mut self, client_id: &ClientId) -> Option { - Some(self.0 - .write() - .await - .remove(client_id)? - .into_inner()) - } - - pub async fn with<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result - where - T: Send, - F: for<'b> FnOnce(&'b ClientState) -> BoxFuture<'b, T> + Send + 'a, - { - let clients = self.0 - .read() - .await; - let client = clients - .get(&client_id) - .ok_or(ClientError::NotFound(client_id))? - .read() - .await; - - Ok(func(&client).await) - } - - pub async fn with_many<'a, T, F, const N: usize>(&'a self, client_ids: [ClientId; N], func: F) -> Result - where - T: Send, - F: for<'b> FnOnce([RwLockReadGuard<'b, ClientState>; N]) -> BoxFuture<'b, T> + Send + 'a, - { - let clients = self.0 - .read() - .await; - - let mut client_states: [std::mem::MaybeUninit>; N] = unsafe { - std::mem::MaybeUninit::uninit().assume_init() - }; - - for (cindex, client_id) in client_ids.iter().enumerate() { - let c = clients - .get(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) - }; - - Ok(func(client_states).await) - } - - pub async fn with_mut<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result - where - T: Send, - F: for<'b> FnOnce(&'b mut ClientState) -> BoxFuture<'b, T> + Send + 'a, - { - let clients = self.0 - .read() - .await; - let mut client = clients - .get(&client_id) - .ok_or(ClientError::NotFound(client_id))? - .write() - .await; - - Ok(func(&mut client).await) - } -} - - -#[derive(Debug, Clone, Copy)] -pub struct ItemDropLocation { - pub map_area: MapArea, - pub x: f32, - pub z: f32, - pub item_id: items::ClientItemId, -} - -pub struct LoadingQuest { - pub header_bin: Option, - pub header_dat: Option, -} - - -pub struct ClientState { - pub user: UserAccountEntity, - pub settings: UserSettingsEntity, - pub character: CharacterEntity, - _session: Session, - //guildcard: GuildCard, - pub block: usize, - pub item_drop_location: Option, - pub done_loading_quest: bool, - pub area: Option, - pub x: f32, - pub y: f32, - pub z: f32, - pub weapon_shop: Vec, - pub tool_shop: Vec, - pub armor_shop: Vec, - pub tek: Option<(items::ClientItemId, item::weapon::TekSpecialModifier, item::weapon::TekPercentModifier, i32)>, - pub character_playtime: chrono::Duration, - pub log_on_time: chrono::DateTime, -} - -impl ClientState { - pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, session: Session) -> ClientState { - let character_playtime = chrono::Duration::seconds(character.playtime as i64); - ClientState { - user, - settings, - character, - _session: session, - block: 0, - item_drop_location: None, - done_loading_quest: false, - area: None, - x: 0.0, - y: 0.0, - z: 0.0, - weapon_shop: Vec::new(), - tool_shop: Vec::new(), - armor_shop: Vec::new(), - tek: None, - character_playtime, - log_on_time: chrono::Utc::now(), - } - } - - pub fn update_playtime(&mut self) { - let additional_playtime = chrono::Utc::now() - self.log_on_time; - self.character.playtime = (self.character_playtime + additional_playtime).num_seconds() as u32; - } -} - - diff --git a/client/src/lib.rs b/client/src/lib.rs index c8ab57b..e75ceaa 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -1,3 +1,178 @@ -pub mod client; +use std::collections::HashMap; +use async_std::sync::{Arc, RwLock, RwLockReadGuard}; + +use futures::future::BoxFuture; + +use libpso::packet::ship::*; +use libpso::packet::login::Session; + +use networking::serverstate::ClientId; +use entity::account::{UserAccountEntity, UserSettingsEntity}; +use entity::character::CharacterEntity; +use entity::item; + +use items; +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)] +pub struct Clients(Arc>>>); + +impl Clients { + pub async fn add(&mut self, client_id: ClientId, client_state: ClientState) { + self.0 + .write() + .await + .insert(client_id, RwLock::new(client_state)); + } + + pub async fn remove(&mut self, client_id: &ClientId) -> Option { + Some(self.0 + .write() + .await + .remove(client_id)? + .into_inner()) + } + + pub async fn with<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b ClientState) -> BoxFuture<'b, T> + Send + 'a, + { + let clients = self.0 + .read() + .await; + let client = clients + .get(&client_id) + .ok_or(ClientError::NotFound(client_id))? + .read() + .await; + + Ok(func(&client).await) + } + + pub async fn with_many<'a, T, F, const N: usize>(&'a self, client_ids: [ClientId; N], func: F) -> Result + where + T: Send, + F: for<'b> FnOnce([RwLockReadGuard<'b, ClientState>; N]) -> BoxFuture<'b, T> + Send + 'a, + { + let clients = self.0 + .read() + .await; + + let mut client_states: [std::mem::MaybeUninit>; N] = unsafe { + std::mem::MaybeUninit::uninit().assume_init() + }; + + for (cindex, client_id) in client_ids.iter().enumerate() { + let c = clients + .get(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) + }; + + Ok(func(client_states).await) + } + + pub async fn with_mut<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b mut ClientState) -> BoxFuture<'b, T> + Send + 'a, + { + let clients = self.0 + .read() + .await; + let mut client = clients + .get(&client_id) + .ok_or(ClientError::NotFound(client_id))? + .write() + .await; + + Ok(func(&mut client).await) + } +} + + +#[derive(Debug, Clone, Copy)] +pub struct ItemDropLocation { + pub map_area: MapArea, + pub x: f32, + pub z: f32, + pub item_id: items::ClientItemId, +} + +pub struct LoadingQuest { + pub header_bin: Option, + pub header_dat: Option, +} + + +pub struct ClientState { + pub user: UserAccountEntity, + pub settings: UserSettingsEntity, + pub character: CharacterEntity, + _session: Session, + //guildcard: GuildCard, + pub block: usize, + pub item_drop_location: Option, + pub done_loading_quest: bool, + pub area: Option, + pub x: f32, + pub y: f32, + pub z: f32, + pub weapon_shop: Vec, + pub tool_shop: Vec, + pub armor_shop: Vec, + pub tek: Option<(items::ClientItemId, item::weapon::TekSpecialModifier, item::weapon::TekPercentModifier, i32)>, + pub character_playtime: chrono::Duration, + pub log_on_time: chrono::DateTime, +} + +impl ClientState { + pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, session: Session) -> ClientState { + let character_playtime = chrono::Duration::seconds(character.playtime as i64); + ClientState { + user, + settings, + character, + _session: session, + block: 0, + item_drop_location: None, + done_loading_quest: false, + area: None, + x: 0.0, + y: 0.0, + z: 0.0, + weapon_shop: Vec::new(), + tool_shop: Vec::new(), + armor_shop: Vec::new(), + tek: None, + character_playtime, + log_on_time: chrono::Utc::now(), + } + } + + pub fn update_playtime(&mut self) { + let additional_playtime = chrono::Utc::now() - self.log_on_time; + self.character.playtime = (self.character_playtime + additional_playtime).num_seconds() as u32; + } +} + -pub use client::*; diff --git a/location/src/lib.rs b/location/src/lib.rs index dd9bd1e..3dd0b2b 100644 --- a/location/src/lib.rs +++ b/location/src/lib.rs @@ -1,3 +1,676 @@ -pub mod location; +#![allow(dead_code, unused_must_use)] +use std::collections::HashMap; +use std::time::SystemTime; +use thiserror::Error; +use networking::serverstate::ClientId; -pub use location::*; +use async_std::sync::{Arc, RwLock}; +use futures::{stream, StreamExt}; +use std::pin::pin; + +pub const MAX_ROOMS: usize = 128; + +pub enum AreaType { + Room, + Lobby, +} + + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct LobbyId(pub usize); + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] +pub struct RoomId(pub usize); + +impl LobbyId { + pub fn id(&self) -> u8 { + self.0 as u8 + } +} + + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum CreateRoomError { + #[error("no open slots")] + NoOpenSlots, + #[error("client already in area")] + ClientInAreaAlready, + #[error("join error")] + JoinError, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum JoinRoomError { + #[error("room does not exist")] + RoomDoesNotExist, + #[error("room is full")] + RoomFull, + #[error("client already in area")] + ClientInAreaAlready, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum JoinLobbyError { + #[error("lobby does not exist")] + LobbyDoesNotExist, + #[error("lobby is full")] + LobbyFull, + #[error("client already in area")] + ClientInAreaAlready, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum GetAreaError { + #[error("not in a room")] + NotInRoom, + #[error("not in a lobby")] + NotInLobby, + #[error("get area: invalid client")] + InvalidClient, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum ClientRemovalError { + #[error("client removal: client not in area")] + ClientNotInArea, + #[error("client removal: invalid area")] + InvalidArea, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum GetClientsError { + #[error("invalid client")] + InvalidClient, + #[error("invalid area")] + InvalidArea, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum GetNeighborError { + #[error("get neighbor: invalid client")] + InvalidClient, + #[error("get neighbor: invalid area")] + InvalidArea, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum GetLeaderError { + #[error("get leader: invalid client")] + InvalidClient, + #[error("get leader: invalid area")] + InvalidArea, + #[error("get leader: client not in area")] + NoClientInArea, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum ClientLocationError { + #[error("create room error {0}")] + CreateRoomError(#[from] CreateRoomError), + #[error("join room error {0}")] + JoinRoomError(#[from] JoinRoomError), + #[error("join lobby error {0}")] + JoinLobbyError(#[from] JoinLobbyError), + #[error("get area error {0}")] + GetAreaError(#[from] GetAreaError), + #[error("client removal error {0}")] + ClientRemovalError(#[from] ClientRemovalError), + #[error("get clients error {0}")] + GetClientsError(#[from] GetClientsError), + #[error("get neighbor error {0}")] + GetNeighborError(#[from] GetNeighborError), + #[error("get leader error {0}")] + GetLeaderError(#[from] GetLeaderError) +} + + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct LocalClientId(usize); + +impl LocalClientId { + pub fn id(&self) -> u8 { + self.0 as u8 + } +} + +impl PartialEq for LocalClientId { + fn eq(&self, other: &u8) -> bool { + self.0 == *other as usize + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct AreaClient { + pub client: ClientId, + pub local_client: LocalClientId, + time_join: SystemTime, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Lobby([Option; 12]); +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Room([Option; 4]); + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum RoomLobby { + Room(RoomId), + Lobby(LobbyId), +} + +#[derive(Clone, Debug)] +pub struct ClientLocation { + lobbies: [Arc>; 15], + rooms: [Arc>>; MAX_ROOMS], + client_location: Arc>>, +} + +impl Default for ClientLocation { + fn default() -> ClientLocation { + ClientLocation { + lobbies: core::array::from_fn(|_| Arc::new(RwLock::new(Lobby([None; 12])))), + rooms: core::array::from_fn(|_| Arc::new(RwLock::new(None))), + client_location: Arc::new(RwLock::new(HashMap::new())), + } + } +} + + +impl ClientLocation { + pub async fn add_client_to_lobby(&self, id: ClientId, lobby_id: LobbyId) -> Result<(), JoinLobbyError> { + { + let lobby = self.lobbies + .get(lobby_id.0) + .ok_or(JoinLobbyError::LobbyDoesNotExist)? + .read() + .await; + if lobby.0.iter().all(|c| c.is_some()) { + return Err(JoinLobbyError::LobbyFull); + } + } + self.remove_client_from_area(id).await; + + let mut lobby = self.lobbies + .get(lobby_id.0) + .ok_or(JoinLobbyError::LobbyDoesNotExist)? + .write() + .await; + let (index, empty_slot) = lobby.0.iter_mut() + .enumerate() + .find(|(_, k)| k.is_none()) + .ok_or(JoinLobbyError::LobbyFull)?; + *empty_slot = Some(AreaClient { + client: id, + local_client: LocalClientId(index), + time_join: SystemTime::now(), + }); + self.client_location + .write() + .await + .insert(id, RoomLobby::Lobby(lobby_id)); + Ok(()) + } + + pub async fn add_client_to_next_available_lobby(&self, id: ClientId, lobby: LobbyId) -> Result { + pin!(stream::iter(0..15) + .filter_map(|lobby_index| async move { + let new_lobby = LobbyId((lobby.0 + lobby_index) % 15); + Some((new_lobby, self.add_client_to_lobby(id, new_lobby).await.ok()?)) + })) + .next() + .await + .map(|l| l.0) + .ok_or(JoinLobbyError::LobbyFull) + } + + pub async fn create_new_room(&mut self, id: ClientId) -> Result { + let (index, empty_slot) = Box::pin(stream::iter(self.rooms.iter()) + .enumerate() + .filter(|(_, r)| async {r.read().await.is_none()})) + .next() + .await + .ok_or(CreateRoomError::NoOpenSlots)?; + *empty_slot.write().await = Some(Room([None; 4])); + self.add_client_to_room(id, RoomId(index)) + .await + .map_err(|_err| CreateRoomError::JoinError)?; + Ok(RoomId(index)) + } + + pub async fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> { + let mut r = self.rooms.get(room.0) + .ok_or(JoinRoomError::RoomDoesNotExist)? + .as_ref() + .write() + .await; + let r = r.as_mut() + .ok_or(JoinRoomError::RoomDoesNotExist)?; + let (index, empty_slot) = r.0.iter_mut() + .enumerate() + .find(|(_, k)| k.is_none()) + .ok_or(JoinRoomError::RoomFull)?; + *empty_slot = Some(AreaClient { + client: id, + local_client: LocalClientId(index), + time_join: SystemTime::now(), + }); + self.remove_client_from_area(id).await; + self.client_location + .write() + .await + .insert(id, RoomLobby::Room(room)); + Ok(()) + } + + pub async fn get_all_clients_by_client(&self, id: ClientId) -> Result, GetNeighborError> { + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(GetNeighborError::InvalidClient)?; + match area { + RoomLobby::Room(room) => { + Ok(self.get_clients_in_room(*room).await.map_err(|_| GetNeighborError::InvalidArea)? + .into_iter() + .collect()) + }, + RoomLobby::Lobby(lobby) => { + Ok(self.get_clients_in_lobby(*lobby).await.map_err(|_| GetNeighborError::InvalidArea)? + .into_iter() + .collect()) + } + } + } + + pub async fn get_client_neighbors(&self, id: ClientId) -> Result, GetNeighborError> { + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(GetNeighborError::InvalidClient)?; + match area { + RoomLobby::Room(room) => { + Ok(self.get_clients_in_room(*room).await.map_err(|_| GetNeighborError::InvalidArea)? + .into_iter() + .filter(|c| c.client != id) + .collect()) + }, + RoomLobby::Lobby(lobby) => { + Ok(self.get_clients_in_lobby(*lobby).await.map_err(|_| GetNeighborError::InvalidArea)? + .into_iter() + .filter(|c| c.client != id) + .collect()) + } + } + } + + pub async fn get_room_leader(&self, room: RoomId) -> Result { + let r = self.rooms[room.0] + .as_ref() + .read() + .await + .ok_or(GetLeaderError::InvalidArea)?; + let mut r = r + .0 + .iter() + .flatten() + .collect::>(); + r.sort_by_key(|k| k.time_join); + let c = r.get(0) + .ok_or(GetLeaderError::NoClientInArea)?; + Ok(**c) + } + + pub async fn get_lobby_leader(&self, lobby: LobbyId) -> Result { + let l = self.lobbies[lobby.0] + .read() + .await; + let mut l = l + .0 + .iter() + .flatten() + .collect::>(); + l.sort_by_key(|k| k.time_join); + let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?; + Ok(**c) + } + + pub async fn get_area_leader(&self, roomlobby: RoomLobby) -> Result { + match roomlobby { + RoomLobby::Room(room) => { + self.get_room_leader(room).await + }, + RoomLobby::Lobby(lobby) => { + self.get_lobby_leader(lobby).await + } + } + } + + pub async fn get_leader_by_client(&self, id: ClientId) -> Result { + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(GetLeaderError::InvalidClient)?; + match area { + RoomLobby::Room(room) => { + self.get_room_leader(*room).await + }, + RoomLobby::Lobby(lobby) => { + self.get_lobby_leader(*lobby).await + } + } + } + + pub async fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result, GetClientsError> { + Ok(self.lobbies + .get(lobby.0) + .ok_or(GetClientsError::InvalidArea)? + .read() + .await + .0 + .iter() + .filter_map(|client| { + client.map(|c| { + c + }) + }).collect()) + } + + pub async fn get_clients_in_room(&self, room: RoomId) -> Result, GetClientsError> { + Ok(self.rooms.get(room.0) + .ok_or(GetClientsError::InvalidArea)? + .as_ref() + .read() + .await + .ok_or(GetClientsError::InvalidArea)? + .0 + .iter() + .filter_map(|client| { + client.map(|c| { + c + }) + }).collect()) + } + + pub async fn get_local_client(&self, id: ClientId) -> Result { + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(GetClientsError::InvalidClient)?; + match area { + RoomLobby::Room(room) => { + self.get_clients_in_room(*room) + .await + .map_err(|_| GetClientsError::InvalidArea)? + .into_iter() + .find(|c| c.client == id) + .ok_or(GetClientsError::InvalidClient) + }, + RoomLobby::Lobby(lobby) => { + self.get_clients_in_lobby(*lobby) + .await + .map_err(|_| GetClientsError::InvalidArea)? + .into_iter() + .find(|c| c.client == id) + .ok_or(GetClientsError::InvalidClient) + } + } + } + + pub async fn get_area(&self, id: ClientId) -> Result { + self.client_location + .read() + .await + .get(&id) + .ok_or(GetAreaError::InvalidClient) + .map(Clone::clone) + } + + pub async fn get_room(&self, id: ClientId) -> Result { + if let RoomLobby::Room(room) = self.client_location.read().await.get(&id).ok_or(GetAreaError::InvalidClient)? { + Ok(*room) + } + else { + Err(GetAreaError::NotInRoom) + } + } + + pub async fn get_lobby(&self, id: ClientId) -> Result { + if let RoomLobby::Lobby(lobby) = self.client_location.read().await.get(&id).ok_or(GetAreaError::InvalidClient)? { + Ok(*lobby) + } + else { + Err(GetAreaError::NotInLobby) + } + } + + pub async fn remove_client_from_area(&self, id: ClientId) -> Result<(), ClientRemovalError> { + fn remove_client(id: ClientId, client_list : &mut [Option; N]) { + client_list + .iter_mut() + .filter(|client| { + client.map_or(false, |c| { + c.client == id + }) + }) + .for_each(|client| { + *client = None + }); + } + + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(ClientRemovalError::ClientNotInArea)?; + match area { + RoomLobby::Room(room) => { + let mut r = self.rooms.get(room.0) + .ok_or(ClientRemovalError::InvalidArea)? + .as_ref() + .write() + .await; + if let Some(r) = r.as_mut() { + remove_client(id, &mut r.0) + } + else { + return Err(ClientRemovalError::InvalidArea) + } + }, + RoomLobby::Lobby(lobby) => { + remove_client(id, &mut self.lobbies[lobby.0].write().await.0) + } + }; + + Ok(()) + } +} + + + + + + + + +#[cfg(test)] +mod test { + use super::*; + + #[async_std::test] + async fn test_add_client_to_lobby() { + let cl = ClientLocation::default(); + cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await.unwrap(); + cl.add_client_to_lobby(ClientId(13), LobbyId(1)).await.unwrap(); + cl.add_client_to_lobby(ClientId(14), LobbyId(0)).await.unwrap(); + + assert!(cl.get_clients_in_lobby(LobbyId(0)).await.into_iter().flatten().map(|c| (c.client, c.local_client)).collect::>() == vec![ + (ClientId(12), LocalClientId(0)), + (ClientId(14), LocalClientId(1)), + ]); + } + + #[async_std::test] + async fn test_add_client_to_full_lobby() { + let cl = ClientLocation::default(); + for i in 0..12 { + cl.add_client_to_lobby(ClientId(i), LobbyId(0)).await.unwrap(); + } + assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)).await == Err(JoinLobbyError::LobbyFull)); + } + + #[async_std::test] + async fn test_add_client_to_next_available_lobby() { + let cl = ClientLocation::default(); + for lobby in 1..4 { + for i in 0..12 { + cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)).await.unwrap(); + } + } + assert!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)).await == Ok(LobbyId(4))); + } + + #[async_std::test] + async fn test_add_to_lobby_when_all_are_full() { + let cl = ClientLocation::default(); + for lobby in 0..15 { + for i in 0..12 { + cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)).await.unwrap(); + } + } + assert_eq!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)).await, Err(JoinLobbyError::LobbyFull)); + } + + #[async_std::test] + async fn test_new_room() { + let mut cl = ClientLocation::default(); + assert!(cl.create_new_room(ClientId(12)).await == Ok(RoomId(0))); + } + + #[async_std::test] + async fn test_add_client_to_room() { + let mut cl = ClientLocation::default(); + let room = cl.create_new_room(ClientId(12)).await.unwrap(); + assert!(cl.add_client_to_room(ClientId(234), room).await == Ok(())); + assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + (ClientId(12), LocalClientId(0)), + (ClientId(234), LocalClientId(1)), + ]); + } + + #[async_std::test] + async fn test_no_new_room_slots() { + let mut cl = ClientLocation::default(); + for i in 0..128 { + cl.create_new_room(ClientId(i)).await; + } + assert!(cl.create_new_room(ClientId(234)).await == Err(CreateRoomError::NoOpenSlots)); + } + + #[async_std::test] + async fn test_joining_full_room() { + let mut cl = ClientLocation::default(); + let room = cl.create_new_room(ClientId(0)).await.unwrap(); + assert!(cl.add_client_to_room(ClientId(1), room).await == Ok(())); + assert!(cl.add_client_to_room(ClientId(2), room).await == Ok(())); + assert!(cl.add_client_to_room(ClientId(3), room).await == Ok(())); + assert!(cl.add_client_to_room(ClientId(234), room).await == Err(JoinRoomError::RoomFull)); + } + + #[async_std::test] + async fn test_adding_client_to_room_removes_from_lobby() { + let mut cl = ClientLocation::default(); + cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await; + + let room = cl.create_new_room(ClientId(51)).await.unwrap(); + assert!(cl.add_client_to_room(ClientId(93), room).await == Ok(())); + assert!(cl.get_clients_in_lobby(LobbyId(0)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + (ClientId(23), LocalClientId(1)), + (ClientId(12), LocalClientId(3)), + ]); + assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + (ClientId(51), LocalClientId(0)), + (ClientId(93), LocalClientId(1)), + ]); + } + + #[async_std::test] + async fn test_getting_neighbors() { + let cl = ClientLocation::default(); + cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await.unwrap(); + cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await.unwrap(); + cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await.unwrap(); + cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await.unwrap(); + + assert!(cl.get_client_neighbors(ClientId(23)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + (ClientId(93), LocalClientId(0)), + (ClientId(51), LocalClientId(2)), + (ClientId(12), LocalClientId(3)), + ]); + } + + #[async_std::test] + async fn test_failing_to_join_lobby_does_not_remove_from_current_area() { + let cl = ClientLocation::default(); + for i in 0..12 { + cl.add_client_to_lobby(ClientId(i), LobbyId(0)).await.unwrap(); + } + assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(1)).await.is_ok()); + assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)).await.is_err()); + assert_eq!(cl.get_clients_in_lobby(LobbyId(0)).await.unwrap().len(), 12); + assert_eq!( + cl.get_clients_in_lobby(LobbyId(1)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>(), + vec![(ClientId(99), LocalClientId(0))] + ); + } + + #[async_std::test] + async fn test_get_leader() { + let cl = ClientLocation::default(); + cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await; + + assert!(cl.get_leader_by_client(ClientId(51)).await.map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(0)))); + } + + #[async_std::test] + async fn test_remove_client_from_room() { + let mut cl = ClientLocation::default(); + let room = cl.create_new_room(ClientId(51)).await.unwrap(); + cl.add_client_to_room(ClientId(93), room).await; + cl.add_client_to_room(ClientId(23), room).await; + cl.remove_client_from_area(ClientId(51)).await; + cl.add_client_to_room(ClientId(12), room).await; + + assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + (ClientId(12), LocalClientId(0)), + (ClientId(93), LocalClientId(1)), + (ClientId(23), LocalClientId(2)), + ]); + } + + #[async_std::test] + async fn test_leader_changes_on_leader_leaving() { + let mut cl = ClientLocation::default(); + let room = cl.create_new_room(ClientId(51)).await.unwrap(); + cl.add_client_to_room(ClientId(93), room).await.unwrap(); + cl.add_client_to_room(ClientId(23), room).await.unwrap(); + cl.remove_client_from_area(ClientId(51)).await.unwrap(); + cl.add_client_to_room(ClientId(12), room).await.unwrap(); + cl.remove_client_from_area(ClientId(23)).await.unwrap(); + cl.add_client_to_room(ClientId(99), room).await.unwrap(); + + assert!(cl.get_leader_by_client(ClientId(12)).await.map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(1)))); + } +} diff --git a/location/src/location.rs b/location/src/location.rs deleted file mode 100644 index 3dd0b2b..0000000 --- a/location/src/location.rs +++ /dev/null @@ -1,676 +0,0 @@ -#![allow(dead_code, unused_must_use)] -use std::collections::HashMap; -use std::time::SystemTime; -use thiserror::Error; -use networking::serverstate::ClientId; - -use async_std::sync::{Arc, RwLock}; -use futures::{stream, StreamExt}; -use std::pin::pin; - -pub const MAX_ROOMS: usize = 128; - -pub enum AreaType { - Room, - Lobby, -} - - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct LobbyId(pub usize); - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] -pub struct RoomId(pub usize); - -impl LobbyId { - pub fn id(&self) -> u8 { - self.0 as u8 - } -} - - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum CreateRoomError { - #[error("no open slots")] - NoOpenSlots, - #[error("client already in area")] - ClientInAreaAlready, - #[error("join error")] - JoinError, -} - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum JoinRoomError { - #[error("room does not exist")] - RoomDoesNotExist, - #[error("room is full")] - RoomFull, - #[error("client already in area")] - ClientInAreaAlready, -} - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum JoinLobbyError { - #[error("lobby does not exist")] - LobbyDoesNotExist, - #[error("lobby is full")] - LobbyFull, - #[error("client already in area")] - ClientInAreaAlready, -} - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum GetAreaError { - #[error("not in a room")] - NotInRoom, - #[error("not in a lobby")] - NotInLobby, - #[error("get area: invalid client")] - InvalidClient, -} - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum ClientRemovalError { - #[error("client removal: client not in area")] - ClientNotInArea, - #[error("client removal: invalid area")] - InvalidArea, -} - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum GetClientsError { - #[error("invalid client")] - InvalidClient, - #[error("invalid area")] - InvalidArea, -} - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum GetNeighborError { - #[error("get neighbor: invalid client")] - InvalidClient, - #[error("get neighbor: invalid area")] - InvalidArea, -} - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum GetLeaderError { - #[error("get leader: invalid client")] - InvalidClient, - #[error("get leader: invalid area")] - InvalidArea, - #[error("get leader: client not in area")] - NoClientInArea, -} - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum ClientLocationError { - #[error("create room error {0}")] - CreateRoomError(#[from] CreateRoomError), - #[error("join room error {0}")] - JoinRoomError(#[from] JoinRoomError), - #[error("join lobby error {0}")] - JoinLobbyError(#[from] JoinLobbyError), - #[error("get area error {0}")] - GetAreaError(#[from] GetAreaError), - #[error("client removal error {0}")] - ClientRemovalError(#[from] ClientRemovalError), - #[error("get clients error {0}")] - GetClientsError(#[from] GetClientsError), - #[error("get neighbor error {0}")] - GetNeighborError(#[from] GetNeighborError), - #[error("get leader error {0}")] - GetLeaderError(#[from] GetLeaderError) -} - - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct LocalClientId(usize); - -impl LocalClientId { - pub fn id(&self) -> u8 { - self.0 as u8 - } -} - -impl PartialEq for LocalClientId { - fn eq(&self, other: &u8) -> bool { - self.0 == *other as usize - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct AreaClient { - pub client: ClientId, - pub local_client: LocalClientId, - time_join: SystemTime, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -struct Lobby([Option; 12]); -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -struct Room([Option; 4]); - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum RoomLobby { - Room(RoomId), - Lobby(LobbyId), -} - -#[derive(Clone, Debug)] -pub struct ClientLocation { - lobbies: [Arc>; 15], - rooms: [Arc>>; MAX_ROOMS], - client_location: Arc>>, -} - -impl Default for ClientLocation { - fn default() -> ClientLocation { - ClientLocation { - lobbies: core::array::from_fn(|_| Arc::new(RwLock::new(Lobby([None; 12])))), - rooms: core::array::from_fn(|_| Arc::new(RwLock::new(None))), - client_location: Arc::new(RwLock::new(HashMap::new())), - } - } -} - - -impl ClientLocation { - pub async fn add_client_to_lobby(&self, id: ClientId, lobby_id: LobbyId) -> Result<(), JoinLobbyError> { - { - let lobby = self.lobbies - .get(lobby_id.0) - .ok_or(JoinLobbyError::LobbyDoesNotExist)? - .read() - .await; - if lobby.0.iter().all(|c| c.is_some()) { - return Err(JoinLobbyError::LobbyFull); - } - } - self.remove_client_from_area(id).await; - - let mut lobby = self.lobbies - .get(lobby_id.0) - .ok_or(JoinLobbyError::LobbyDoesNotExist)? - .write() - .await; - let (index, empty_slot) = lobby.0.iter_mut() - .enumerate() - .find(|(_, k)| k.is_none()) - .ok_or(JoinLobbyError::LobbyFull)?; - *empty_slot = Some(AreaClient { - client: id, - local_client: LocalClientId(index), - time_join: SystemTime::now(), - }); - self.client_location - .write() - .await - .insert(id, RoomLobby::Lobby(lobby_id)); - Ok(()) - } - - pub async fn add_client_to_next_available_lobby(&self, id: ClientId, lobby: LobbyId) -> Result { - pin!(stream::iter(0..15) - .filter_map(|lobby_index| async move { - let new_lobby = LobbyId((lobby.0 + lobby_index) % 15); - Some((new_lobby, self.add_client_to_lobby(id, new_lobby).await.ok()?)) - })) - .next() - .await - .map(|l| l.0) - .ok_or(JoinLobbyError::LobbyFull) - } - - pub async fn create_new_room(&mut self, id: ClientId) -> Result { - let (index, empty_slot) = Box::pin(stream::iter(self.rooms.iter()) - .enumerate() - .filter(|(_, r)| async {r.read().await.is_none()})) - .next() - .await - .ok_or(CreateRoomError::NoOpenSlots)?; - *empty_slot.write().await = Some(Room([None; 4])); - self.add_client_to_room(id, RoomId(index)) - .await - .map_err(|_err| CreateRoomError::JoinError)?; - Ok(RoomId(index)) - } - - pub async fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> { - let mut r = self.rooms.get(room.0) - .ok_or(JoinRoomError::RoomDoesNotExist)? - .as_ref() - .write() - .await; - let r = r.as_mut() - .ok_or(JoinRoomError::RoomDoesNotExist)?; - let (index, empty_slot) = r.0.iter_mut() - .enumerate() - .find(|(_, k)| k.is_none()) - .ok_or(JoinRoomError::RoomFull)?; - *empty_slot = Some(AreaClient { - client: id, - local_client: LocalClientId(index), - time_join: SystemTime::now(), - }); - self.remove_client_from_area(id).await; - self.client_location - .write() - .await - .insert(id, RoomLobby::Room(room)); - Ok(()) - } - - pub async fn get_all_clients_by_client(&self, id: ClientId) -> Result, GetNeighborError> { - let area = self.client_location - .read() - .await; - let area = area - .get(&id) - .ok_or(GetNeighborError::InvalidClient)?; - match area { - RoomLobby::Room(room) => { - Ok(self.get_clients_in_room(*room).await.map_err(|_| GetNeighborError::InvalidArea)? - .into_iter() - .collect()) - }, - RoomLobby::Lobby(lobby) => { - Ok(self.get_clients_in_lobby(*lobby).await.map_err(|_| GetNeighborError::InvalidArea)? - .into_iter() - .collect()) - } - } - } - - pub async fn get_client_neighbors(&self, id: ClientId) -> Result, GetNeighborError> { - let area = self.client_location - .read() - .await; - let area = area - .get(&id) - .ok_or(GetNeighborError::InvalidClient)?; - match area { - RoomLobby::Room(room) => { - Ok(self.get_clients_in_room(*room).await.map_err(|_| GetNeighborError::InvalidArea)? - .into_iter() - .filter(|c| c.client != id) - .collect()) - }, - RoomLobby::Lobby(lobby) => { - Ok(self.get_clients_in_lobby(*lobby).await.map_err(|_| GetNeighborError::InvalidArea)? - .into_iter() - .filter(|c| c.client != id) - .collect()) - } - } - } - - pub async fn get_room_leader(&self, room: RoomId) -> Result { - let r = self.rooms[room.0] - .as_ref() - .read() - .await - .ok_or(GetLeaderError::InvalidArea)?; - let mut r = r - .0 - .iter() - .flatten() - .collect::>(); - r.sort_by_key(|k| k.time_join); - let c = r.get(0) - .ok_or(GetLeaderError::NoClientInArea)?; - Ok(**c) - } - - pub async fn get_lobby_leader(&self, lobby: LobbyId) -> Result { - let l = self.lobbies[lobby.0] - .read() - .await; - let mut l = l - .0 - .iter() - .flatten() - .collect::>(); - l.sort_by_key(|k| k.time_join); - let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?; - Ok(**c) - } - - pub async fn get_area_leader(&self, roomlobby: RoomLobby) -> Result { - match roomlobby { - RoomLobby::Room(room) => { - self.get_room_leader(room).await - }, - RoomLobby::Lobby(lobby) => { - self.get_lobby_leader(lobby).await - } - } - } - - pub async fn get_leader_by_client(&self, id: ClientId) -> Result { - let area = self.client_location - .read() - .await; - let area = area - .get(&id) - .ok_or(GetLeaderError::InvalidClient)?; - match area { - RoomLobby::Room(room) => { - self.get_room_leader(*room).await - }, - RoomLobby::Lobby(lobby) => { - self.get_lobby_leader(*lobby).await - } - } - } - - pub async fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result, GetClientsError> { - Ok(self.lobbies - .get(lobby.0) - .ok_or(GetClientsError::InvalidArea)? - .read() - .await - .0 - .iter() - .filter_map(|client| { - client.map(|c| { - c - }) - }).collect()) - } - - pub async fn get_clients_in_room(&self, room: RoomId) -> Result, GetClientsError> { - Ok(self.rooms.get(room.0) - .ok_or(GetClientsError::InvalidArea)? - .as_ref() - .read() - .await - .ok_or(GetClientsError::InvalidArea)? - .0 - .iter() - .filter_map(|client| { - client.map(|c| { - c - }) - }).collect()) - } - - pub async fn get_local_client(&self, id: ClientId) -> Result { - let area = self.client_location - .read() - .await; - let area = area - .get(&id) - .ok_or(GetClientsError::InvalidClient)?; - match area { - RoomLobby::Room(room) => { - self.get_clients_in_room(*room) - .await - .map_err(|_| GetClientsError::InvalidArea)? - .into_iter() - .find(|c| c.client == id) - .ok_or(GetClientsError::InvalidClient) - }, - RoomLobby::Lobby(lobby) => { - self.get_clients_in_lobby(*lobby) - .await - .map_err(|_| GetClientsError::InvalidArea)? - .into_iter() - .find(|c| c.client == id) - .ok_or(GetClientsError::InvalidClient) - } - } - } - - pub async fn get_area(&self, id: ClientId) -> Result { - self.client_location - .read() - .await - .get(&id) - .ok_or(GetAreaError::InvalidClient) - .map(Clone::clone) - } - - pub async fn get_room(&self, id: ClientId) -> Result { - if let RoomLobby::Room(room) = self.client_location.read().await.get(&id).ok_or(GetAreaError::InvalidClient)? { - Ok(*room) - } - else { - Err(GetAreaError::NotInRoom) - } - } - - pub async fn get_lobby(&self, id: ClientId) -> Result { - if let RoomLobby::Lobby(lobby) = self.client_location.read().await.get(&id).ok_or(GetAreaError::InvalidClient)? { - Ok(*lobby) - } - else { - Err(GetAreaError::NotInLobby) - } - } - - pub async fn remove_client_from_area(&self, id: ClientId) -> Result<(), ClientRemovalError> { - fn remove_client(id: ClientId, client_list : &mut [Option; N]) { - client_list - .iter_mut() - .filter(|client| { - client.map_or(false, |c| { - c.client == id - }) - }) - .for_each(|client| { - *client = None - }); - } - - let area = self.client_location - .read() - .await; - let area = area - .get(&id) - .ok_or(ClientRemovalError::ClientNotInArea)?; - match area { - RoomLobby::Room(room) => { - let mut r = self.rooms.get(room.0) - .ok_or(ClientRemovalError::InvalidArea)? - .as_ref() - .write() - .await; - if let Some(r) = r.as_mut() { - remove_client(id, &mut r.0) - } - else { - return Err(ClientRemovalError::InvalidArea) - } - }, - RoomLobby::Lobby(lobby) => { - remove_client(id, &mut self.lobbies[lobby.0].write().await.0) - } - }; - - Ok(()) - } -} - - - - - - - - -#[cfg(test)] -mod test { - use super::*; - - #[async_std::test] - async fn test_add_client_to_lobby() { - let cl = ClientLocation::default(); - cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await.unwrap(); - cl.add_client_to_lobby(ClientId(13), LobbyId(1)).await.unwrap(); - cl.add_client_to_lobby(ClientId(14), LobbyId(0)).await.unwrap(); - - assert!(cl.get_clients_in_lobby(LobbyId(0)).await.into_iter().flatten().map(|c| (c.client, c.local_client)).collect::>() == vec![ - (ClientId(12), LocalClientId(0)), - (ClientId(14), LocalClientId(1)), - ]); - } - - #[async_std::test] - async fn test_add_client_to_full_lobby() { - let cl = ClientLocation::default(); - for i in 0..12 { - cl.add_client_to_lobby(ClientId(i), LobbyId(0)).await.unwrap(); - } - assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)).await == Err(JoinLobbyError::LobbyFull)); - } - - #[async_std::test] - async fn test_add_client_to_next_available_lobby() { - let cl = ClientLocation::default(); - for lobby in 1..4 { - for i in 0..12 { - cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)).await.unwrap(); - } - } - assert!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)).await == Ok(LobbyId(4))); - } - - #[async_std::test] - async fn test_add_to_lobby_when_all_are_full() { - let cl = ClientLocation::default(); - for lobby in 0..15 { - for i in 0..12 { - cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)).await.unwrap(); - } - } - assert_eq!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)).await, Err(JoinLobbyError::LobbyFull)); - } - - #[async_std::test] - async fn test_new_room() { - let mut cl = ClientLocation::default(); - assert!(cl.create_new_room(ClientId(12)).await == Ok(RoomId(0))); - } - - #[async_std::test] - async fn test_add_client_to_room() { - let mut cl = ClientLocation::default(); - let room = cl.create_new_room(ClientId(12)).await.unwrap(); - assert!(cl.add_client_to_room(ClientId(234), room).await == Ok(())); - assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ - (ClientId(12), LocalClientId(0)), - (ClientId(234), LocalClientId(1)), - ]); - } - - #[async_std::test] - async fn test_no_new_room_slots() { - let mut cl = ClientLocation::default(); - for i in 0..128 { - cl.create_new_room(ClientId(i)).await; - } - assert!(cl.create_new_room(ClientId(234)).await == Err(CreateRoomError::NoOpenSlots)); - } - - #[async_std::test] - async fn test_joining_full_room() { - let mut cl = ClientLocation::default(); - let room = cl.create_new_room(ClientId(0)).await.unwrap(); - assert!(cl.add_client_to_room(ClientId(1), room).await == Ok(())); - assert!(cl.add_client_to_room(ClientId(2), room).await == Ok(())); - assert!(cl.add_client_to_room(ClientId(3), room).await == Ok(())); - assert!(cl.add_client_to_room(ClientId(234), room).await == Err(JoinRoomError::RoomFull)); - } - - #[async_std::test] - async fn test_adding_client_to_room_removes_from_lobby() { - let mut cl = ClientLocation::default(); - cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await; - cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await; - cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await; - cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await; - - let room = cl.create_new_room(ClientId(51)).await.unwrap(); - assert!(cl.add_client_to_room(ClientId(93), room).await == Ok(())); - assert!(cl.get_clients_in_lobby(LobbyId(0)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ - (ClientId(23), LocalClientId(1)), - (ClientId(12), LocalClientId(3)), - ]); - assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ - (ClientId(51), LocalClientId(0)), - (ClientId(93), LocalClientId(1)), - ]); - } - - #[async_std::test] - async fn test_getting_neighbors() { - let cl = ClientLocation::default(); - cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await.unwrap(); - cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await.unwrap(); - cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await.unwrap(); - cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await.unwrap(); - - assert!(cl.get_client_neighbors(ClientId(23)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ - (ClientId(93), LocalClientId(0)), - (ClientId(51), LocalClientId(2)), - (ClientId(12), LocalClientId(3)), - ]); - } - - #[async_std::test] - async fn test_failing_to_join_lobby_does_not_remove_from_current_area() { - let cl = ClientLocation::default(); - for i in 0..12 { - cl.add_client_to_lobby(ClientId(i), LobbyId(0)).await.unwrap(); - } - assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(1)).await.is_ok()); - assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)).await.is_err()); - assert_eq!(cl.get_clients_in_lobby(LobbyId(0)).await.unwrap().len(), 12); - assert_eq!( - cl.get_clients_in_lobby(LobbyId(1)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>(), - vec![(ClientId(99), LocalClientId(0))] - ); - } - - #[async_std::test] - async fn test_get_leader() { - let cl = ClientLocation::default(); - cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await; - cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await; - cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await; - cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await; - - assert!(cl.get_leader_by_client(ClientId(51)).await.map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(0)))); - } - - #[async_std::test] - async fn test_remove_client_from_room() { - let mut cl = ClientLocation::default(); - let room = cl.create_new_room(ClientId(51)).await.unwrap(); - cl.add_client_to_room(ClientId(93), room).await; - cl.add_client_to_room(ClientId(23), room).await; - cl.remove_client_from_area(ClientId(51)).await; - cl.add_client_to_room(ClientId(12), room).await; - - assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ - (ClientId(12), LocalClientId(0)), - (ClientId(93), LocalClientId(1)), - (ClientId(23), LocalClientId(2)), - ]); - } - - #[async_std::test] - async fn test_leader_changes_on_leader_leaving() { - let mut cl = ClientLocation::default(); - let room = cl.create_new_room(ClientId(51)).await.unwrap(); - cl.add_client_to_room(ClientId(93), room).await.unwrap(); - cl.add_client_to_room(ClientId(23), room).await.unwrap(); - cl.remove_client_from_area(ClientId(51)).await.unwrap(); - cl.add_client_to_room(ClientId(12), room).await.unwrap(); - cl.remove_client_from_area(ClientId(23)).await.unwrap(); - cl.add_client_to_room(ClientId(99), room).await.unwrap(); - - assert!(cl.get_leader_by_client(ClientId(12)).await.map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(1)))); - } -} diff --git a/quests/src/lib.rs b/quests/src/lib.rs index de40457..91e5d4d 100644 --- a/quests/src/lib.rs +++ b/quests/src/lib.rs @@ -1,4 +1,328 @@ -pub mod quests; +use log::warn; +use std::collections::{HashMap, BTreeMap, BTreeSet}; +use std::fs::File; +use std::io::{Read, Write, Cursor, Seek, SeekFrom}; +use std::path::PathBuf; +use std::convert::TryInto; +use async_std::sync::Arc; +use thiserror::Error; +use serde::{Serialize, Deserialize}; +use ages_prs::{LegacyPrsDecoder, LegacyPrsEncoder}; +use byteorder::{LittleEndian, ReadBytesExt}; +use libpso::util::array_to_utf16; +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}; -pub use quests::*; +#[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct QuestCategory { + index: usize, + pub name: String, + pub description: String, +} + + +#[derive(Debug, Serialize, Deserialize, Hash)] +struct QuestListEntry { + bin: String, + dat: String, +} + +#[derive(Debug, Serialize, Deserialize, Hash)] +struct QuestListCategory { + list_order: usize, + description: String, + quests: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +struct QuestListConfig { + questlist: HashMap>, +} + +#[derive(Error, Debug)] +#[error("")] +pub enum ParseDatError { + IoError(#[from] std::io::Error), + MapError(#[from] MapAreaError), + UnknownDatHeader(u32), + CouldNotDetermineEpisode, + InvalidMapAreaId(u16), +} + +const DAT_OBJECT_HEADER_ID: u32 = 1; +const DAT_ENEMY_HEADER_ID: u32 = 2; +const DAT_WAVE_HEADER_ID: u32 = 3; + +enum DatBlock { + Object(Vec>), + Enemy(Vec>), + Wave, +} + + +fn read_dat_section_header(cursor: &mut T, episode: &Episode, map_areas: &MapAreaLookup) -> Result { + let header = cursor.read_u32::()?; + let _offset = cursor.read_u32::()?; + let area = cursor.read_u16::()?; + let _unknown1 = cursor.read_u16::()?; + let length = cursor.read_u32::()?; + + let map_area = map_areas.get_area_map(area).map_err(|_| ParseDatError::InvalidMapAreaId(area))?; + + match header { + DAT_OBJECT_HEADER_ID => { + let mut obj_data = vec![0u8; length as usize]; + cursor.read_exact(&mut obj_data)?; + let mut obj_cursor = Cursor::new(obj_data); + + let objects = objects_from_stream(&mut obj_cursor, episode, &map_area); + Ok(DatBlock::Object(objects)) + }, + DAT_ENEMY_HEADER_ID => { + let mut enemy_data = vec![0u8; length as usize]; + cursor.read_exact(&mut enemy_data)?; + let mut enemy_cursor = Cursor::new(enemy_data); + + let enemies = enemy_data_from_stream(&mut enemy_cursor, &map_area, episode); + + Ok(DatBlock::Enemy(enemies)) + }, + DAT_WAVE_HEADER_ID => { + cursor.seek(SeekFrom::Current(length as i64))?; + Ok(DatBlock::Wave) + }, + _ => Err(ParseDatError::UnknownDatHeader(header)) + } +} + +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]) + } + } + None +} + +fn map_area_mappings(bin: &[u8]) -> MapAreaLookup { + let mut map_areas = MapAreaLookupBuilder::default(); + for bytes in bin.windows(4) { + // BB_Map_Designate + if bytes[0] == 0xF9 && bytes[1] == 0x51 { + //return Some(Episode::from_quest(bytes[2]).ok()?) + let floor_value = bytes[2] as u16; + if let Some(map_area) = MapArea::from_bb_map_designate(bytes[3]) { + map_areas = map_areas.add(floor_value, map_area); + } + } + } + map_areas.build() +} + +#[allow(clippy::type_complexity)] +fn parse_dat(dat: &[u8], episode: &Episode, map_areas: &MapAreaLookup) -> Result<(Vec>, Vec>), ParseDatError> { + let mut cursor = Cursor::new(dat); + + let header_iter = std::iter::from_fn(move || { + match read_dat_section_header(&mut cursor, episode, map_areas) { + Ok(dat_block) => Some(dat_block), + Err(err) => { + warn!("unknown header in dat: {:?}", err); + None + } + } + }); + + Ok(header_iter.fold((Vec::new(), Vec::new()), |(mut enemies, mut objects), dat_block| { + match dat_block { + DatBlock::Object(mut objs) => { + objects.append(&mut objs) + }, + DatBlock::Enemy(mut enemy) => { + enemies.append(&mut enemy) + }, + _ => {} + } + + (enemies, objects) + })) +} + +#[derive(Error, Debug)] +pub enum QuestLoadError { + #[error("io error {0}")] + IoError(#[from] std::io::Error), + #[error("parse dat error {0}")] + ParseDatError(#[from] ParseDatError), + #[error("could not read metadata")] + CouldNotReadMetadata, + #[error("could not load config file")] + CouldNotLoadConfigFile, +} + +#[derive(Debug, Clone)] +pub struct Quest { + pub name: String, + pub description: String, + pub full_description: String, + pub language: u16, + pub id: u16, + pub bin_blob: Arc>, + pub dat_blob: Arc>, + pub enemies: Vec>, // TODO: Arc? + pub objects: Vec>, // TODO: Arc? + pub map_areas: MapAreaLookup, // TODO: Arc? +} + +impl Quest { + fn from_bin_dat(bin: Vec, dat: Vec) -> Result { + let id = u16::from_le_bytes(bin[16..18].try_into().map_err(|_| QuestLoadError::CouldNotReadMetadata)?); + let language = u16::from_le_bytes(bin[18..20].try_into().map_err(|_| QuestLoadError::CouldNotReadMetadata)?); + let name = array_to_utf16(&bin[24..88]); + let description = array_to_utf16(&bin[88..334]); + let full_description = array_to_utf16(&bin[334..920]); + + let episode = quest_episode(&bin).ok_or(ParseDatError::CouldNotDetermineEpisode)?; + let map_areas = map_area_mappings(&bin); + let (enemies, objects) = parse_dat(&dat, &episode, &map_areas)?; + + let mut prs_bin = LegacyPrsEncoder::new(Vec::new()); + prs_bin.write_all(&bin)?; + let mut prs_dat = LegacyPrsEncoder::new(Vec::new()); + prs_dat.write_all(&dat)?; + + Ok(Quest { + name, + description, + full_description, + id, + language, + bin_blob: Arc::new(prs_bin.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?), + dat_blob: Arc::new(prs_dat.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?), + enemies, + objects, + map_areas, + }) + } +} + +// QuestCollection +pub type QuestList = BTreeMap>; + +pub fn load_quest(bin_path: PathBuf, dat_path: PathBuf, quest_path: PathBuf) -> Option { + let dat_file = File::open(quest_path.join(dat_path.clone())) + .map_err(|err| { + warn!("could not load quest file {:?}: {:?}", dat_path, err) + }).ok()?; + let bin_file = File::open(quest_path.join(bin_path.clone())) + .map_err(|err| { + warn!("could not load quest file {:?}: {:?}", bin_path, err) + }).ok()?; + let mut dat_prs = LegacyPrsDecoder::new(dat_file); + let mut bin_prs = LegacyPrsDecoder::new(bin_file); + + let mut dat = Vec::new(); + let mut bin = Vec::new(); + dat_prs.read_to_end(&mut dat).ok()?; + bin_prs.read_to_end(&mut bin).ok()?; + + let quest = Quest::from_bin_dat(bin, dat).map_err(|err| { + warn!("could not parse quest file {:?}/{:?}: {:?}", bin_path, dat_path, err) + }).ok()?; + Some(quest) +} + + +pub fn load_quests_path(mut quest_path: PathBuf) -> Result { + let mut f = File::open(quest_path.clone()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; + let mut s = String::new(); + f.read_to_string(&mut s)?; + quest_path.pop(); // remove quests.toml from the path + let mut used_quest_ids = BTreeSet::new(); + let ql: BTreeMap = toml::from_str(s.as_str()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; + + Ok(ql.into_iter().map(|(category, category_details)| { + ( + QuestCategory { + index: category_details.list_order, + name: category, + description: category_details.description, + }, + category_details.quests + .into_iter() + .filter_map(|quest| { + load_quest(quest.bin.into(), quest.dat.into(), quest_path.to_path_buf()) + .and_then(|quest | { + if used_quest_ids.contains(&quest.id) { + warn!("quest id already exists: {}", quest.id); + return None; + } + used_quest_ids.insert(quest.id); + Some(quest) + }) + }) + .collect() + ) + }).collect()) +} + +pub fn load_standard_quests(mode: RoomMode) -> Result { + match mode { + RoomMode::Single {episode, .. } => { + load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "single", "quests.toml"])) + }, + RoomMode::Multi {episode, .. } => { + load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "multi", "quests.toml"])) + }, + _ => { + Ok(BTreeMap::new()) + } + } +} + + +pub fn load_government_quests(mode: RoomMode) -> Result { + match mode { + RoomMode::Single {episode, .. } => { + load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "government", "quests.toml"])) + }, + RoomMode::Multi {episode, .. } => { + load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "government", "quests.toml"])) + }, + _ => { + Ok(BTreeMap::new()) + } + } +} + + + + + + +#[cfg(test)] +mod tests { + use super::*; + + // the quest phantasmal world 4 uses the tower map twice, to do this it had to remap + // one of the other maps to be a second tower + #[test] + fn test_quest_with_remapped_floors() { + let pw4 = load_quest("q236-ext-bb.bin".into(), "q236-ext-bb.dat".into(), "data/quests/bb/ep2/multi".into()).unwrap(); + let enemies_not_in_tower = pw4.enemies.iter() + .filter(|enemy| { + enemy.is_some() + }) + .filter(|enemy| { + enemy.unwrap().map_area != MapArea::Tower + }); + assert!(enemies_not_in_tower.count() == 0); + + } +} diff --git a/quests/src/quests.rs b/quests/src/quests.rs deleted file mode 100644 index 91e5d4d..0000000 --- a/quests/src/quests.rs +++ /dev/null @@ -1,328 +0,0 @@ -use log::warn; -use std::collections::{HashMap, BTreeMap, BTreeSet}; -use std::fs::File; -use std::io::{Read, Write, Cursor, Seek, SeekFrom}; -use std::path::PathBuf; -use std::convert::TryInto; -use async_std::sync::Arc; -use thiserror::Error; -use serde::{Serialize, Deserialize}; -use ages_prs::{LegacyPrsDecoder, LegacyPrsEncoder}; -use byteorder::{LittleEndian, ReadBytesExt}; -use libpso::util::array_to_utf16; -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)] -pub struct QuestCategory { - index: usize, - pub name: String, - pub description: String, -} - - -#[derive(Debug, Serialize, Deserialize, Hash)] -struct QuestListEntry { - bin: String, - dat: String, -} - -#[derive(Debug, Serialize, Deserialize, Hash)] -struct QuestListCategory { - list_order: usize, - description: String, - quests: Vec, -} - -#[derive(Debug, Serialize, Deserialize)] -struct QuestListConfig { - questlist: HashMap>, -} - -#[derive(Error, Debug)] -#[error("")] -pub enum ParseDatError { - IoError(#[from] std::io::Error), - MapError(#[from] MapAreaError), - UnknownDatHeader(u32), - CouldNotDetermineEpisode, - InvalidMapAreaId(u16), -} - -const DAT_OBJECT_HEADER_ID: u32 = 1; -const DAT_ENEMY_HEADER_ID: u32 = 2; -const DAT_WAVE_HEADER_ID: u32 = 3; - -enum DatBlock { - Object(Vec>), - Enemy(Vec>), - Wave, -} - - -fn read_dat_section_header(cursor: &mut T, episode: &Episode, map_areas: &MapAreaLookup) -> Result { - let header = cursor.read_u32::()?; - let _offset = cursor.read_u32::()?; - let area = cursor.read_u16::()?; - let _unknown1 = cursor.read_u16::()?; - let length = cursor.read_u32::()?; - - let map_area = map_areas.get_area_map(area).map_err(|_| ParseDatError::InvalidMapAreaId(area))?; - - match header { - DAT_OBJECT_HEADER_ID => { - let mut obj_data = vec![0u8; length as usize]; - cursor.read_exact(&mut obj_data)?; - let mut obj_cursor = Cursor::new(obj_data); - - let objects = objects_from_stream(&mut obj_cursor, episode, &map_area); - Ok(DatBlock::Object(objects)) - }, - DAT_ENEMY_HEADER_ID => { - let mut enemy_data = vec![0u8; length as usize]; - cursor.read_exact(&mut enemy_data)?; - let mut enemy_cursor = Cursor::new(enemy_data); - - let enemies = enemy_data_from_stream(&mut enemy_cursor, &map_area, episode); - - Ok(DatBlock::Enemy(enemies)) - }, - DAT_WAVE_HEADER_ID => { - cursor.seek(SeekFrom::Current(length as i64))?; - Ok(DatBlock::Wave) - }, - _ => Err(ParseDatError::UnknownDatHeader(header)) - } -} - -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]) - } - } - None -} - -fn map_area_mappings(bin: &[u8]) -> MapAreaLookup { - let mut map_areas = MapAreaLookupBuilder::default(); - for bytes in bin.windows(4) { - // BB_Map_Designate - if bytes[0] == 0xF9 && bytes[1] == 0x51 { - //return Some(Episode::from_quest(bytes[2]).ok()?) - let floor_value = bytes[2] as u16; - if let Some(map_area) = MapArea::from_bb_map_designate(bytes[3]) { - map_areas = map_areas.add(floor_value, map_area); - } - } - } - map_areas.build() -} - -#[allow(clippy::type_complexity)] -fn parse_dat(dat: &[u8], episode: &Episode, map_areas: &MapAreaLookup) -> Result<(Vec>, Vec>), ParseDatError> { - let mut cursor = Cursor::new(dat); - - let header_iter = std::iter::from_fn(move || { - match read_dat_section_header(&mut cursor, episode, map_areas) { - Ok(dat_block) => Some(dat_block), - Err(err) => { - warn!("unknown header in dat: {:?}", err); - None - } - } - }); - - Ok(header_iter.fold((Vec::new(), Vec::new()), |(mut enemies, mut objects), dat_block| { - match dat_block { - DatBlock::Object(mut objs) => { - objects.append(&mut objs) - }, - DatBlock::Enemy(mut enemy) => { - enemies.append(&mut enemy) - }, - _ => {} - } - - (enemies, objects) - })) -} - -#[derive(Error, Debug)] -pub enum QuestLoadError { - #[error("io error {0}")] - IoError(#[from] std::io::Error), - #[error("parse dat error {0}")] - ParseDatError(#[from] ParseDatError), - #[error("could not read metadata")] - CouldNotReadMetadata, - #[error("could not load config file")] - CouldNotLoadConfigFile, -} - -#[derive(Debug, Clone)] -pub struct Quest { - pub name: String, - pub description: String, - pub full_description: String, - pub language: u16, - pub id: u16, - pub bin_blob: Arc>, - pub dat_blob: Arc>, - pub enemies: Vec>, // TODO: Arc? - pub objects: Vec>, // TODO: Arc? - pub map_areas: MapAreaLookup, // TODO: Arc? -} - -impl Quest { - fn from_bin_dat(bin: Vec, dat: Vec) -> Result { - let id = u16::from_le_bytes(bin[16..18].try_into().map_err(|_| QuestLoadError::CouldNotReadMetadata)?); - let language = u16::from_le_bytes(bin[18..20].try_into().map_err(|_| QuestLoadError::CouldNotReadMetadata)?); - let name = array_to_utf16(&bin[24..88]); - let description = array_to_utf16(&bin[88..334]); - let full_description = array_to_utf16(&bin[334..920]); - - let episode = quest_episode(&bin).ok_or(ParseDatError::CouldNotDetermineEpisode)?; - let map_areas = map_area_mappings(&bin); - let (enemies, objects) = parse_dat(&dat, &episode, &map_areas)?; - - let mut prs_bin = LegacyPrsEncoder::new(Vec::new()); - prs_bin.write_all(&bin)?; - let mut prs_dat = LegacyPrsEncoder::new(Vec::new()); - prs_dat.write_all(&dat)?; - - Ok(Quest { - name, - description, - full_description, - id, - language, - bin_blob: Arc::new(prs_bin.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?), - dat_blob: Arc::new(prs_dat.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?), - enemies, - objects, - map_areas, - }) - } -} - -// QuestCollection -pub type QuestList = BTreeMap>; - -pub fn load_quest(bin_path: PathBuf, dat_path: PathBuf, quest_path: PathBuf) -> Option { - let dat_file = File::open(quest_path.join(dat_path.clone())) - .map_err(|err| { - warn!("could not load quest file {:?}: {:?}", dat_path, err) - }).ok()?; - let bin_file = File::open(quest_path.join(bin_path.clone())) - .map_err(|err| { - warn!("could not load quest file {:?}: {:?}", bin_path, err) - }).ok()?; - let mut dat_prs = LegacyPrsDecoder::new(dat_file); - let mut bin_prs = LegacyPrsDecoder::new(bin_file); - - let mut dat = Vec::new(); - let mut bin = Vec::new(); - dat_prs.read_to_end(&mut dat).ok()?; - bin_prs.read_to_end(&mut bin).ok()?; - - let quest = Quest::from_bin_dat(bin, dat).map_err(|err| { - warn!("could not parse quest file {:?}/{:?}: {:?}", bin_path, dat_path, err) - }).ok()?; - Some(quest) -} - - -pub fn load_quests_path(mut quest_path: PathBuf) -> Result { - let mut f = File::open(quest_path.clone()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; - let mut s = String::new(); - f.read_to_string(&mut s)?; - quest_path.pop(); // remove quests.toml from the path - let mut used_quest_ids = BTreeSet::new(); - let ql: BTreeMap = toml::from_str(s.as_str()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; - - Ok(ql.into_iter().map(|(category, category_details)| { - ( - QuestCategory { - index: category_details.list_order, - name: category, - description: category_details.description, - }, - category_details.quests - .into_iter() - .filter_map(|quest| { - load_quest(quest.bin.into(), quest.dat.into(), quest_path.to_path_buf()) - .and_then(|quest | { - if used_quest_ids.contains(&quest.id) { - warn!("quest id already exists: {}", quest.id); - return None; - } - used_quest_ids.insert(quest.id); - Some(quest) - }) - }) - .collect() - ) - }).collect()) -} - -pub fn load_standard_quests(mode: RoomMode) -> Result { - match mode { - RoomMode::Single {episode, .. } => { - load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "single", "quests.toml"])) - }, - RoomMode::Multi {episode, .. } => { - load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "multi", "quests.toml"])) - }, - _ => { - Ok(BTreeMap::new()) - } - } -} - - -pub fn load_government_quests(mode: RoomMode) -> Result { - match mode { - RoomMode::Single {episode, .. } => { - load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "government", "quests.toml"])) - }, - RoomMode::Multi {episode, .. } => { - load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "government", "quests.toml"])) - }, - _ => { - Ok(BTreeMap::new()) - } - } -} - - - - - - -#[cfg(test)] -mod tests { - use super::*; - - // the quest phantasmal world 4 uses the tower map twice, to do this it had to remap - // one of the other maps to be a second tower - #[test] - fn test_quest_with_remapped_floors() { - let pw4 = load_quest("q236-ext-bb.bin".into(), "q236-ext-bb.dat".into(), "data/quests/bb/ep2/multi".into()).unwrap(); - let enemies_not_in_tower = pw4.enemies.iter() - .filter(|enemy| { - enemy.is_some() - }) - .filter(|enemy| { - enemy.unwrap().map_area != MapArea::Tower - }); - assert!(enemies_not_in_tower.count() == 0); - - } -} diff --git a/room/src/lib.rs b/room/src/lib.rs index 4f8d063..5110d22 100644 --- a/room/src/lib.rs +++ b/room/src/lib.rs @@ -1,3 +1,272 @@ -pub mod room; +use std::collections::HashMap; +use std::convert::{From, Into}; +use async_std::sync::{Arc, RwLock, RwLockReadGuard}; +use futures::future::BoxFuture; +use futures::stream::{FuturesOrdered, Stream}; -pub use room::*; +use thiserror::Error; +use rand::Rng; + +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 quests; +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)))) + } +} + +impl Rooms { + pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), anyhow::Error> { + *self.0 + .get(room_id.0) + .ok_or(RoomError::Invalid(room_id.0 as u32))? + .write() + .await = Some(room); + Ok(()) + } + + pub async fn remove(&self, room_id: RoomId) { + if let Some(room) = self.0.get(room_id.0) { + *room + .write() + .await = None; + } + } + + pub async fn exists(&self, room_id: RoomId) -> bool { + match self.0.get(room_id.0) { + Some(room) => { + room + .read() + .await + .is_some() + }, + None => false, + } + } + + pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b RoomState) -> BoxFuture<'b, T> + Send + 'a + { + let room = self.0 + .get(room_id.0) + .ok_or(RoomError::Invalid(room_id.0 as u32))? + .read() + .await; + if let Some(room) = room.as_ref() { + Ok(func(room).await) + } + else { + Err(RoomError::Invalid(room_id.0 as u32).into()) + } + } + + pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b mut RoomState) -> BoxFuture<'b, T> + Send + 'a + { + let mut room = self.0 + .get(room_id.0) + .ok_or(RoomError::Invalid(room_id.0 as u32))? + .write() + .await; + + if let Some(room) = room.as_mut() { + Ok(func(room).await) + } + else { + Err(RoomError::Invalid(room_id.0 as u32).into()) + } + } + + pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard> { + self.0 + .get(room_id.0) + .unwrap() + .read() + .await + } + + pub fn stream(&self) -> impl Stream>> { + self.0 + .iter() + .map(|room| async move { + room + .read() + .await + }) + .collect::>() + } +} + +#[derive(Debug, Error)] +#[error("")] +pub enum RoomCreationError { + InvalidMode, + InvalidEpisode(u8), + InvalidDifficulty(u8), + CouldNotLoadMonsterStats(RoomMode), + CouldNotLoadQuests, +} + + +pub enum QuestCategoryType { + Standard, + Government, +} + +impl From for QuestCategoryType { + fn from(f: usize) -> QuestCategoryType { + match f { + 0 => QuestCategoryType::Standard, + _ => QuestCategoryType::Government, + } + } +} +impl From for QuestCategoryType { + fn from(f: u32) -> QuestCategoryType { + match f { + 0 => QuestCategoryType::Standard, + _ => QuestCategoryType::Government, + } + } +} + +impl QuestCategoryType { + pub fn value(&self) -> usize { + match self { + QuestCategoryType::Standard => 0, + QuestCategoryType::Government => 1, + } + } +} + +pub struct RoomState { + pub room_id: RoomEntityId, + pub mode: RoomMode, + pub name: String, + pub password: [u16; 16], + pub maps: Maps, + 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, + // enemy info +} + +impl RoomState { + pub fn get_flags_for_room_list(&self) -> u8 { + let mut flags = 0u8; + + match self.mode { + RoomMode::Single {..} => {flags += 0x04} + RoomMode::Battle {..} => {flags += 0x10}, + RoomMode::Challenge {..} => {flags += 0x20}, + _ => {flags += 0x40}, + }; + + if self.password[0] > 0 { + flags += 0x02; + } + flags + } + + pub fn get_episode_for_room_list(&self) -> u8 { + let episode: u8 = self.mode.episode().into(); + + match self.mode { + RoomMode::Single {..} => episode + 0x10, + _ => episode + 0x40, + } + } + + pub fn get_difficulty_for_room_list(&self) -> u8 { + let difficulty: u8 = self.mode.difficulty().into(); + difficulty + 0x22 + } + + pub fn quests(&self) -> &quests::QuestList { + match self.quest_group { + QuestCategoryType::Standard => &self.standard_quests, + QuestCategoryType::Government => &self.government_quests, + } + } + + #[allow(clippy::too_many_arguments, clippy::type_complexity)] + pub fn new (room_id: RoomEntityId, + mode: RoomEntityMode, + episode: Episode, + difficulty: Difficulty, + section_id: SectionID, + name: String, + password: [u16; 16], + event: Holiday, + map_builder: Arc Maps + Send + Sync>>, + drop_table_builder: Arc DropTable + Send + Sync>>, + ) -> Result { + let mode = match mode { + RoomEntityMode::Single => RoomMode::Single { + episode, + difficulty, + }, + RoomEntityMode::Multi => RoomMode::Multi { + episode, + difficulty, + }, + RoomEntityMode::Challenge => RoomMode::Challenge { + episode, + }, + RoomEntityMode::Battle => RoomMode::Battle { + episode, + difficulty, + }, + }; + + Ok(RoomState { + room_id, + monster_stats: Box::new(load_monster_stats_table(&mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(mode))?), + mode, + random_seed: rand::thread_rng().gen(), + name, + password, + maps: map_builder(mode, event), + section_id, + drop_table: Box::new(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)?, + }) + + } +} diff --git a/room/src/room.rs b/room/src/room.rs deleted file mode 100644 index 5110d22..0000000 --- a/room/src/room.rs +++ /dev/null @@ -1,272 +0,0 @@ -use std::collections::HashMap; -use std::convert::{From, Into}; -use async_std::sync::{Arc, RwLock, RwLockReadGuard}; -use futures::future::BoxFuture; -use futures::stream::{FuturesOrdered, Stream}; - -use thiserror::Error; -use rand::Rng; - -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 quests; -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)))) - } -} - -impl Rooms { - pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), anyhow::Error> { - *self.0 - .get(room_id.0) - .ok_or(RoomError::Invalid(room_id.0 as u32))? - .write() - .await = Some(room); - Ok(()) - } - - pub async fn remove(&self, room_id: RoomId) { - if let Some(room) = self.0.get(room_id.0) { - *room - .write() - .await = None; - } - } - - pub async fn exists(&self, room_id: RoomId) -> bool { - match self.0.get(room_id.0) { - Some(room) => { - room - .read() - .await - .is_some() - }, - None => false, - } - } - - pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result - where - T: Send, - F: for<'b> FnOnce(&'b RoomState) -> BoxFuture<'b, T> + Send + 'a - { - let room = self.0 - .get(room_id.0) - .ok_or(RoomError::Invalid(room_id.0 as u32))? - .read() - .await; - if let Some(room) = room.as_ref() { - Ok(func(room).await) - } - else { - Err(RoomError::Invalid(room_id.0 as u32).into()) - } - } - - pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result - where - T: Send, - F: for<'b> FnOnce(&'b mut RoomState) -> BoxFuture<'b, T> + Send + 'a - { - let mut room = self.0 - .get(room_id.0) - .ok_or(RoomError::Invalid(room_id.0 as u32))? - .write() - .await; - - if let Some(room) = room.as_mut() { - Ok(func(room).await) - } - else { - Err(RoomError::Invalid(room_id.0 as u32).into()) - } - } - - pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard> { - self.0 - .get(room_id.0) - .unwrap() - .read() - .await - } - - pub fn stream(&self) -> impl Stream>> { - self.0 - .iter() - .map(|room| async move { - room - .read() - .await - }) - .collect::>() - } -} - -#[derive(Debug, Error)] -#[error("")] -pub enum RoomCreationError { - InvalidMode, - InvalidEpisode(u8), - InvalidDifficulty(u8), - CouldNotLoadMonsterStats(RoomMode), - CouldNotLoadQuests, -} - - -pub enum QuestCategoryType { - Standard, - Government, -} - -impl From for QuestCategoryType { - fn from(f: usize) -> QuestCategoryType { - match f { - 0 => QuestCategoryType::Standard, - _ => QuestCategoryType::Government, - } - } -} -impl From for QuestCategoryType { - fn from(f: u32) -> QuestCategoryType { - match f { - 0 => QuestCategoryType::Standard, - _ => QuestCategoryType::Government, - } - } -} - -impl QuestCategoryType { - pub fn value(&self) -> usize { - match self { - QuestCategoryType::Standard => 0, - QuestCategoryType::Government => 1, - } - } -} - -pub struct RoomState { - pub room_id: RoomEntityId, - pub mode: RoomMode, - pub name: String, - pub password: [u16; 16], - pub maps: Maps, - 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, - // enemy info -} - -impl RoomState { - pub fn get_flags_for_room_list(&self) -> u8 { - let mut flags = 0u8; - - match self.mode { - RoomMode::Single {..} => {flags += 0x04} - RoomMode::Battle {..} => {flags += 0x10}, - RoomMode::Challenge {..} => {flags += 0x20}, - _ => {flags += 0x40}, - }; - - if self.password[0] > 0 { - flags += 0x02; - } - flags - } - - pub fn get_episode_for_room_list(&self) -> u8 { - let episode: u8 = self.mode.episode().into(); - - match self.mode { - RoomMode::Single {..} => episode + 0x10, - _ => episode + 0x40, - } - } - - pub fn get_difficulty_for_room_list(&self) -> u8 { - let difficulty: u8 = self.mode.difficulty().into(); - difficulty + 0x22 - } - - pub fn quests(&self) -> &quests::QuestList { - match self.quest_group { - QuestCategoryType::Standard => &self.standard_quests, - QuestCategoryType::Government => &self.government_quests, - } - } - - #[allow(clippy::too_many_arguments, clippy::type_complexity)] - pub fn new (room_id: RoomEntityId, - mode: RoomEntityMode, - episode: Episode, - difficulty: Difficulty, - section_id: SectionID, - name: String, - password: [u16; 16], - event: Holiday, - map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, - ) -> Result { - let mode = match mode { - RoomEntityMode::Single => RoomMode::Single { - episode, - difficulty, - }, - RoomEntityMode::Multi => RoomMode::Multi { - episode, - difficulty, - }, - RoomEntityMode::Challenge => RoomMode::Challenge { - episode, - }, - RoomEntityMode::Battle => RoomMode::Battle { - episode, - difficulty, - }, - }; - - Ok(RoomState { - room_id, - monster_stats: Box::new(load_monster_stats_table(&mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(mode))?), - mode, - random_seed: rand::thread_rng().gen(), - name, - password, - maps: map_builder(mode, event), - section_id, - drop_table: Box::new(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)?, - }) - - } -} diff --git a/trade/src/lib.rs b/trade/src/lib.rs index 2629bda..a6a7b18 100644 --- a/trade/src/lib.rs +++ b/trade/src/lib.rs @@ -1,4 +1,132 @@ -pub mod trade; +use std::collections::HashMap; +use networking::serverstate::ClientId; +use items; +use async_std::sync::{Arc, Mutex, MutexGuard}; +use futures::future::{Future, OptionFuture}; +use items::trade::TradeItem; +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum TradeStatus { + SentRequest, + ReceivedRequest, + Trading, + Confirmed, + FinalConfirm, + ItemsChecked, + TradeComplete, +} -pub use trade::*; + +#[derive(Debug, Clone)] +pub struct ClientTradeState { + client: ClientId, + other_client: ClientId, + pub items: Vec, + pub meseta: usize, + pub status: TradeStatus, +} + + +impl ClientTradeState { + pub fn client(&self) -> ClientId { + self.client + } + + pub fn other_client(&self) -> ClientId { + self.other_client + } +} + +#[derive(thiserror::Error, Debug)] +pub enum TradeStateError { + #[error("client not in trade {0}")] + ClientNotInTrade(ClientId), + #[error("mismatched trade {0} {1}")] + MismatchedTrade(ClientId, ClientId), +} + +#[derive(Default, Debug, Clone)] +pub struct TradeState { + trades: HashMap>>, +} + +impl TradeState { + pub fn new_trade(&mut self, sender: &ClientId, receiver: &ClientId) { + let state = ClientTradeState { + client: *sender, + other_client: *receiver, + items: Default::default(), + meseta: 0, + status: TradeStatus::SentRequest, + }; + self.trades.insert(*sender, Arc::new(Mutex::new(state))); + + let state = ClientTradeState { + client: *receiver, + other_client: *sender, + items: Default::default(), + meseta: 0, + status: TradeStatus::ReceivedRequest, + }; + self.trades.insert(*receiver, Arc::new(Mutex::new(state))); + } + + pub fn in_trade(&self, client: &ClientId) -> bool { + self.trades.contains_key(client) + } + + /* + pub async fn with<'a, T, F, Fut> (&'a self, client: &ClientId, func: F) -> Result + where + F: FnOnce(MutexGuard<'a, ClientTradeState>, MutexGuard<'a, ClientTradeState>) -> Fut + 'a, + Fut: Future + { + let c1 = self.trades.get(client).ok_or(TradeStateError::ClientNotInTrade(*client))?.lock().await; + let c2 = self.trades.get(&c1.other_client).ok_or(TradeStateError::ClientNotInTrade(c1.other_client))?.lock().await; + + // sanity check + if c1.client != c2.other_client { + return Err(TradeStateError::MismatchedTrade(c1.client, c2.client)); + } + Ok(func(c1, c2).await) + } + */ + pub async fn with<'a, T, F, Fut> (&'a self, client: &ClientId, func: F) -> Result + where + T: Send, + //F: for<'b> FnOnce(&'b mut ClientTradeState, &'b mut ClientTradeState) -> BoxFuture<'b, T> + Send + 'a + //F: for<'b> FnOnce(&'b mut ClientTradeState, &'b mut ClientTradeState) -> Fut + Send + 'a, + F: FnOnce(MutexGuard<'a, ClientTradeState>, MutexGuard<'a, ClientTradeState>) -> Fut + 'a, + Fut: Future, + { + let c1 = self.trades + .get(client) + .ok_or(TradeStateError::ClientNotInTrade(*client))? + .lock() + .await; + let c2 = self.trades + .get(&c1.other_client) + .ok_or(TradeStateError::ClientNotInTrade(c1.other_client))? + .lock() + .await; + + if c1.client != c2.other_client { + return Err(TradeStateError::MismatchedTrade(c1.client, c2.client)); + } + + Ok(func(c1, c2).await) + } + + // TODO: is it possible for this to not return Options? + pub async fn remove_trade(&mut self, client: &ClientId) -> (Option, Option) { + let c1 = OptionFuture::from(self.trades.remove(client).map(|c| async move {c.lock().await.clone()} )).await; + let c2 = if let Some(ref state) = c1 { + OptionFuture::from(self.trades.remove(&state.other_client).map(|c| async move {c.lock().await.clone()})).await + } + else { + None + }; + + (c1, c2) + } +} diff --git a/trade/src/trade.rs b/trade/src/trade.rs deleted file mode 100644 index a6a7b18..0000000 --- a/trade/src/trade.rs +++ /dev/null @@ -1,132 +0,0 @@ -use std::collections::HashMap; -use networking::serverstate::ClientId; -use items; -use async_std::sync::{Arc, Mutex, MutexGuard}; -use futures::future::{Future, OptionFuture}; -use items::trade::TradeItem; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum TradeStatus { - SentRequest, - ReceivedRequest, - Trading, - Confirmed, - FinalConfirm, - ItemsChecked, - TradeComplete, -} - - -#[derive(Debug, Clone)] -pub struct ClientTradeState { - client: ClientId, - other_client: ClientId, - pub items: Vec, - pub meseta: usize, - pub status: TradeStatus, -} - - -impl ClientTradeState { - pub fn client(&self) -> ClientId { - self.client - } - - pub fn other_client(&self) -> ClientId { - self.other_client - } -} - -#[derive(thiserror::Error, Debug)] -pub enum TradeStateError { - #[error("client not in trade {0}")] - ClientNotInTrade(ClientId), - #[error("mismatched trade {0} {1}")] - MismatchedTrade(ClientId, ClientId), -} - -#[derive(Default, Debug, Clone)] -pub struct TradeState { - trades: HashMap>>, -} - -impl TradeState { - pub fn new_trade(&mut self, sender: &ClientId, receiver: &ClientId) { - let state = ClientTradeState { - client: *sender, - other_client: *receiver, - items: Default::default(), - meseta: 0, - status: TradeStatus::SentRequest, - }; - self.trades.insert(*sender, Arc::new(Mutex::new(state))); - - let state = ClientTradeState { - client: *receiver, - other_client: *sender, - items: Default::default(), - meseta: 0, - status: TradeStatus::ReceivedRequest, - }; - self.trades.insert(*receiver, Arc::new(Mutex::new(state))); - } - - pub fn in_trade(&self, client: &ClientId) -> bool { - self.trades.contains_key(client) - } - - /* - pub async fn with<'a, T, F, Fut> (&'a self, client: &ClientId, func: F) -> Result - where - F: FnOnce(MutexGuard<'a, ClientTradeState>, MutexGuard<'a, ClientTradeState>) -> Fut + 'a, - Fut: Future - { - let c1 = self.trades.get(client).ok_or(TradeStateError::ClientNotInTrade(*client))?.lock().await; - let c2 = self.trades.get(&c1.other_client).ok_or(TradeStateError::ClientNotInTrade(c1.other_client))?.lock().await; - - // sanity check - if c1.client != c2.other_client { - return Err(TradeStateError::MismatchedTrade(c1.client, c2.client)); - } - Ok(func(c1, c2).await) - } - */ - pub async fn with<'a, T, F, Fut> (&'a self, client: &ClientId, func: F) -> Result - where - T: Send, - //F: for<'b> FnOnce(&'b mut ClientTradeState, &'b mut ClientTradeState) -> BoxFuture<'b, T> + Send + 'a - //F: for<'b> FnOnce(&'b mut ClientTradeState, &'b mut ClientTradeState) -> Fut + Send + 'a, - F: FnOnce(MutexGuard<'a, ClientTradeState>, MutexGuard<'a, ClientTradeState>) -> Fut + 'a, - Fut: Future, - { - let c1 = self.trades - .get(client) - .ok_or(TradeStateError::ClientNotInTrade(*client))? - .lock() - .await; - let c2 = self.trades - .get(&c1.other_client) - .ok_or(TradeStateError::ClientNotInTrade(c1.other_client))? - .lock() - .await; - - if c1.client != c2.other_client { - return Err(TradeStateError::MismatchedTrade(c1.client, c2.client)); - } - - Ok(func(c1, c2).await) - } - - // TODO: is it possible for this to not return Options? - pub async fn remove_trade(&mut self, client: &ClientId) -> (Option, Option) { - let c1 = OptionFuture::from(self.trades.remove(client).map(|c| async move {c.lock().await.clone()} )).await; - let c2 = if let Some(ref state) = c1 { - OptionFuture::from(self.trades.remove(&state.other_client).map(|c| async move {c.lock().await.clone()})).await - } - else { - None - }; - - (c1, c2) - } -} From 3dc48e9d4388d47a39298547cf0425983992c274 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 16:18:20 -0700 Subject: [PATCH 16/29] clippy --- client/src/lib.rs | 1 - room/src/lib.rs | 1 - trade/src/lib.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index e75ceaa..43c7a0f 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -11,7 +11,6 @@ use entity::account::{UserAccountEntity, UserSettingsEntity}; use entity::character::CharacterEntity; use entity::item; -use items; use maps::area::MapArea; use shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; diff --git a/room/src/lib.rs b/room/src/lib.rs index 5110d22..897c20f 100644 --- a/room/src/lib.rs +++ b/room/src/lib.rs @@ -13,7 +13,6 @@ use entity::character::SectionID; use entity::room::{RoomEntityId, RoomEntityMode}; use maps::monster::{load_monster_stats_table, MonsterType, MonsterStats}; use maps::area::MapAreaLookup; -use quests; use maps::Holiday; use location::{MAX_ROOMS, RoomId}; diff --git a/trade/src/lib.rs b/trade/src/lib.rs index a6a7b18..319652c 100644 --- a/trade/src/lib.rs +++ b/trade/src/lib.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use networking::serverstate::ClientId; -use items; use async_std::sync::{Arc, Mutex, MutexGuard}; use futures::future::{Future, OptionFuture}; use items::trade::TradeItem; From 7afe44a52033bf91bee017ede919e879ec843a60 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 16:21:35 -0700 Subject: [PATCH 17/29] remove redundant patch.rs --- src/bin/main.rs | 2 +- src/bin/patch.rs | 2 +- src/patch/mod.rs | 434 ++++++++++++++++++++++++++++++++++++++++++++- src/patch/patch.rs | 432 -------------------------------------------- 4 files changed, 434 insertions(+), 436 deletions(-) delete mode 100644 src/patch/patch.rs diff --git a/src/bin/main.rs b/src/bin/main.rs index 18fdfbd..e50db30 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -4,7 +4,7 @@ use log::{info}; use networking::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::patch::{PatchServerState, generate_patch_tree, load_config, load_motd}; use elseware::ship::ship::ShipServerStateBuilder; use maps::Holiday; diff --git a/src/bin/patch.rs b/src/bin/patch.rs index fc9eff8..a9fb839 100644 --- a/src/bin/patch.rs +++ b/src/bin/patch.rs @@ -1,4 +1,4 @@ -use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config_env, load_motd}; +use elseware::patch::{PatchServerState, generate_patch_tree, load_config_env, load_motd}; use log::info; fn main() { diff --git a/src/patch/mod.rs b/src/patch/mod.rs index 323a777..565530d 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -1,2 +1,432 @@ -#[allow(clippy::module_inception)] -pub mod patch; +use std::collections::{HashMap, HashSet}; +use std::fs; +use std::io; +use std::io::{Read}; +use std::path::{Path, PathBuf}; +use rand::Rng; +use crc::{crc32, Hasher32}; +use libpso::{PacketParseError, PSOPacket}; +use libpso::packet::patch::*; +use libpso::crypto::pc::PSOPCCipher; +use ron::de::from_str; +use serde::Deserialize; + +use networking::mainloop::{NetworkError}; +use networking::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId}; + +#[derive(Debug)] +pub enum PatchError { + NetworkError(NetworkError), + IOError(std::io::Error), +} + +impl From for PatchError { + fn from(err: NetworkError) -> PatchError { + PatchError::NetworkError(err) + } +} + +impl From for PatchError { + fn from(err: std::io::Error) -> PatchError { + PatchError::IOError(err) + } +} + + +#[derive(Debug, Clone)] +pub struct PatchFile { + path: PathBuf, + checksum: u32, + size: u32, +} + +pub enum PatchTreeIterItem { + Directory(PathBuf), + File(PathBuf, u32), + UpDirectory, +} + +#[derive(Debug, Clone)] +pub enum PatchFileTree { + Directory(PathBuf, Vec), + File(PathBuf, u32), // file_id +} + +impl PatchFileTree { + fn iter_dir(tree: &PatchFileTree) -> Vec { + let mut v = Vec::new(); + + match tree { + PatchFileTree::Directory(dir, files) => { + v.push(PatchTreeIterItem::Directory(dir.clone())); + for file in files { + v.append(&mut PatchFileTree::iter_dir(file)); + } + v.push(PatchTreeIterItem::UpDirectory); + }, + PatchFileTree::File(path, id) => { + v.push(PatchTreeIterItem::File(path.clone(), *id)); + } + } + + v + } + + pub fn flatten(&self) -> Vec { + PatchFileTree::iter_dir(self) + } +} + + +#[derive(Debug)] +pub enum RecvPatchPacket { + PatchWelcomeReply(PatchWelcomeReply), + LoginReply(LoginReply), + FileInfoReply(FileInfoReply), + FileInfoListEnd(FileInfoListEnd), +} + +impl RecvServerPacket for RecvPatchPacket { + fn from_bytes(data: &[u8]) -> Result { + match data[2] { + 0x02 => Ok(RecvPatchPacket::PatchWelcomeReply(PatchWelcomeReply::from_bytes(data)?)), + 0x04 => Ok(RecvPatchPacket::LoginReply(LoginReply::from_bytes(data)?)), + 0x0F => Ok(RecvPatchPacket::FileInfoReply(FileInfoReply::from_bytes(data)?)), + 0x10 => Ok(RecvPatchPacket::FileInfoListEnd(FileInfoListEnd::from_bytes(data)?)), + _ => Err(PacketParseError::WrongPacketForServerType(u16::from_le_bytes([data[2], data[3]]), data.to_vec())) + } + } +} + +#[derive(Debug)] +pub enum SendPatchPacket { + ChangeDirectory(ChangeDirectory), + EndFileSend(EndFileSend), + FileInfo(FileInfo), + FileSend(Box), + FilesToPatchMetadata(FilesToPatchMetadata), + FinalizePatching(FinalizePatching), + Message(Message), + PatchEndList(PatchEndList), + PatchStartList(PatchStartList), + PatchWelcome(PatchWelcome), + RequestLogin(RequestLogin), + StartFileSend(StartFileSend), + UpOneDirectory(UpOneDirectory), +} + +impl SendServerPacket for SendPatchPacket { + fn as_bytes(&self) -> Vec { + match self { + SendPatchPacket::ChangeDirectory(pkt) => pkt.as_bytes(), + SendPatchPacket::EndFileSend(pkt) => pkt.as_bytes(), + SendPatchPacket::FileInfo(pkt) => pkt.as_bytes(), + SendPatchPacket::FileSend(pkt) => pkt.as_bytes(), + SendPatchPacket::FilesToPatchMetadata(pkt) => pkt.as_bytes(), + SendPatchPacket::FinalizePatching(pkt) => pkt.as_bytes(), + SendPatchPacket::Message(pkt) => pkt.as_bytes(), + SendPatchPacket::PatchEndList(pkt) => pkt.as_bytes(), + SendPatchPacket::PatchStartList(pkt) => pkt.as_bytes(), + SendPatchPacket::PatchWelcome(pkt) => pkt.as_bytes(), + SendPatchPacket::RequestLogin(pkt) => pkt.as_bytes(), + SendPatchPacket::StartFileSend(pkt) => pkt.as_bytes(), + SendPatchPacket::UpOneDirectory(pkt) => pkt.as_bytes(), + } + } +} + + +#[derive(Clone)] +pub struct PatchServerState { + patch_file_tree: PatchFileTree, + patch_file_lookup: HashMap, + patch_file_info: Vec, + patch_motd: String, +} + +impl PatchServerState { + pub fn new(patch_file_tree: PatchFileTree, patch_file_lookup: HashMap, patch_motd: String) -> PatchServerState { + PatchServerState { + patch_file_tree, + patch_file_lookup, + patch_file_info: Vec::new(), + patch_motd, + } + } +} + +#[async_trait::async_trait] +impl ServerState for PatchServerState { + type SendPacket = SendPatchPacket; + type RecvPacket = RecvPatchPacket; + type Cipher = PSOPCCipher; + type PacketError = PatchError; + + async fn on_connect(&mut self, _id: ClientId) -> Result>, PatchError> { + let mut rng = rand::thread_rng(); + let key_in: u32 = rng.gen(); + let key_out: u32 = rng.gen(); + + Ok(vec![OnConnect::Packet(SendPatchPacket::PatchWelcome(PatchWelcome::new(key_out, key_in))), + OnConnect::Cipher(PSOPCCipher::new(key_in), PSOPCCipher::new(key_out)) + ]) + } + + async fn handle(&mut self, id: ClientId, pkt: RecvPatchPacket) -> Result, PatchError> { + Ok(match pkt { + RecvPatchPacket::PatchWelcomeReply(_pkt) => { + vec![SendPatchPacket::RequestLogin(RequestLogin {})] + .into_iter() + .map(move |pkt| (id, pkt)) + .collect() + }, + RecvPatchPacket::LoginReply(_pkt) => { + let mut pkts = vec![SendPatchPacket::Message(Message::new(self.patch_motd.clone()))]; + pkts.append(&mut get_file_list_packets(&self.patch_file_tree)); + pkts.push(SendPatchPacket::PatchEndList(PatchEndList {})); + pkts + .into_iter() + .map(move |pkt| (id, pkt)) + .collect() + }, + RecvPatchPacket::FileInfoReply(pkt) => { + self.patch_file_info.push(pkt); + Vec::new() + }, + RecvPatchPacket::FileInfoListEnd(_pkt) => { + let need_update = self.patch_file_info.iter() + .filter(|file_info| does_file_need_updating(file_info, &self.patch_file_lookup)) + .collect::>(); + + let total_size = need_update.iter().fold(0, |a, file_info| a + file_info.size); + let total_files = need_update.len() as u32; + + vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)), + SendPatchPacket::PatchStartList(PatchStartList {})] + .into_iter() + .chain(SendFileIterator::new(self)) + .map(move |pkt| (id, pkt)) + .collect() + } + }) + } + + async fn on_disconnect(&mut self, _id: ClientId) -> Result, PatchError> { + Ok(Vec::new()) + } +} + +fn load_patch_dir(basedir: &str, patchbase: &str, file_ids: &mut HashMap) -> PatchFileTree { + let paths = fs::read_dir(basedir).expect("could not read directory"); + + let mut files = Vec::new(); + let mut dirs = Vec::new(); + for p in paths { + let path = p.expect("not a real path").path(); + let patch_path = path.strip_prefix(basedir).unwrap(); + if path.is_dir() { + dirs.push(load_patch_dir(path.to_str().unwrap(), patch_path.to_str().unwrap(), file_ids)); + } + else { + files.push(PatchFileTree::File(patch_path.to_path_buf(), file_ids.len() as u32)); + let (checksum, size) = get_checksum_and_size(&path).unwrap(); + file_ids.insert(file_ids.len() as u32, PatchFile { + path, + checksum, + size, + }); + } + } + + files.append(&mut dirs); + + PatchFileTree::Directory(PathBuf::from(patchbase), files) +} + +pub fn generate_patch_tree(basedir: &str) -> (PatchFileTree, HashMap) { + let mut file_ids = HashMap::new(); + + let patch_tree = load_patch_dir(basedir, "", &mut file_ids); + + (patch_tree, file_ids) +} + + +fn get_file_list_packets(patch_file_tree: &PatchFileTree) -> Vec { + let mut pkts = Vec::new(); + + for item in patch_file_tree.flatten() { + match item { + PatchTreeIterItem::Directory(path) => { + pkts.push(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap()))); + }, + PatchTreeIterItem::File(path, id) => { + pkts.push(SendPatchPacket::FileInfo(FileInfo::new(path.to_str().unwrap(), id))); + }, + PatchTreeIterItem::UpDirectory => { + pkts.push(SendPatchPacket::UpOneDirectory(UpOneDirectory {})); + } + } + } + + pkts +} + +fn get_checksum_and_size(path: &Path) -> Result<(u32, u32), PatchError> { + let file = fs::File::open(path)?; + let size = file.metadata().unwrap().len(); + let mut crc = crc32::Digest::new(crc32::IEEE); + let mut buf = [0u8; 1024 * 32]; + let mut reader = io::BufReader::new(file); + while let Ok(len) = reader.read(&mut buf) { + if len == 0 { + break; + } + crc.write(&buf[0..len]); + } + + Ok((crc.sum32(), size as u32)) +} + +fn does_file_need_updating(file_info: &FileInfoReply, patch_file_lookup: &HashMap) -> bool { + let patch_file = patch_file_lookup.get(&file_info.id).unwrap(); + patch_file.checksum != file_info.checksum || patch_file.size != file_info.size +} + + +struct SendFileIterator { + done: bool, + file_iter: Box + Send>, + patch_file_lookup: HashMap, + current_file: Option>, + chunk_num: u32, +} + +impl SendFileIterator { + fn new(state: &PatchServerState) -> SendFileIterator { + let file_ids_to_update = state.patch_file_info.iter() + .filter(|file_info| does_file_need_updating(file_info, &state.patch_file_lookup)) + .map(|k| k.id) + .collect::>(); + + SendFileIterator { + done: false, + patch_file_lookup: state.patch_file_lookup.clone(), + file_iter: Box::new(state.patch_file_tree.flatten().into_iter().filter(move |file| { + match file { + PatchTreeIterItem::File(_path, id) => { + file_ids_to_update.contains(id) + }, + _ => true, + } + })), + current_file: None, + chunk_num: 0, + } + } +} + +impl Iterator for SendFileIterator { + type Item = SendPatchPacket; + + fn next(&mut self) -> Option { + if self.done { + return None; + } + + match self.current_file { + Some(ref mut file) => { + let mut buf = [0u8; PATCH_FILE_CHUNK_SIZE as usize]; + let len = file.read(&mut buf).unwrap(); + if len == 0 { + self.current_file = None; + self.chunk_num = 0; + Some(SendPatchPacket::EndFileSend(EndFileSend::new())) + } + else { + let mut crc = crc32::Digest::new(crc32::IEEE); + crc.write(&buf[0..len]); + let pkt = SendPatchPacket::FileSend(Box::new(FileSend { + chunk_num: self.chunk_num, + checksum: crc.sum32(), + chunk_size: len as u32, + buffer: buf, + })); + self.chunk_num += 1; + Some(pkt) + } + }, + None => { + match self.file_iter.next() { + Some(next_file) => { + match next_file { + PatchTreeIterItem::Directory(path) => { + Some(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap()))) + }, + PatchTreeIterItem::File(path, id) => { + let patch_file = self.patch_file_lookup.get(&id).unwrap(); + let file = fs::File::open(&patch_file.path).unwrap(); + let size = file.metadata().unwrap().len(); + self.current_file = Some(io::BufReader::new(file)); + Some(SendPatchPacket::StartFileSend(StartFileSend::new(path.to_str().unwrap(), size as u32, id))) + }, + PatchTreeIterItem::UpDirectory => { + Some(SendPatchPacket::UpOneDirectory(UpOneDirectory {})) + }, + } + }, + None => { + self.current_file = None; + self.done = true; + Some(SendPatchPacket::FinalizePatching(FinalizePatching {})) + } + } + } + } + } +} + +#[derive(Debug, Deserialize)] +pub struct PatchConfig { + pub path: String, + pub ip: String, // TODO: this does nothing + pub port: u16, +} + +pub fn load_config() -> PatchConfig { + let ini_file = match fs::File::open(std::path::Path::new("patch.ron")) { + Err(err) => panic!("Failed to open patch.ron config file. \n{err}"), + Ok(ini_file) => ini_file, + }; + + let mut s = String::new(); + if let Err(err) = (&ini_file).read_to_string(&mut s) { + panic!("Failed to read patch.ron config file. \n{err}"); + } + + let config: PatchConfig = match from_str(s.as_str()) { + Ok(config) => config, + Err(err) => panic!("Failed to load values from patch.ron \n{err}"), + }; + config +} + +pub fn load_config_env() -> PatchConfig { + let patch_path = std::env::var("PATCHFILE_DIR").unwrap(); + let patch_port = std::env::var("PATCH_PORT").unwrap().parse().unwrap(); + + PatchConfig { + path: patch_path, + ip: "127.0.0.1".into(), + port: patch_port, + } +} + +pub fn load_motd() -> String { + if let Ok(m) = fs::read_to_string("patch.motd") { + m + } + else { + "Welcome to Elseware!".to_string() + } +} diff --git a/src/patch/patch.rs b/src/patch/patch.rs deleted file mode 100644 index 565530d..0000000 --- a/src/patch/patch.rs +++ /dev/null @@ -1,432 +0,0 @@ -use std::collections::{HashMap, HashSet}; -use std::fs; -use std::io; -use std::io::{Read}; -use std::path::{Path, PathBuf}; -use rand::Rng; -use crc::{crc32, Hasher32}; -use libpso::{PacketParseError, PSOPacket}; -use libpso::packet::patch::*; -use libpso::crypto::pc::PSOPCCipher; -use ron::de::from_str; -use serde::Deserialize; - -use networking::mainloop::{NetworkError}; -use networking::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId}; - -#[derive(Debug)] -pub enum PatchError { - NetworkError(NetworkError), - IOError(std::io::Error), -} - -impl From for PatchError { - fn from(err: NetworkError) -> PatchError { - PatchError::NetworkError(err) - } -} - -impl From for PatchError { - fn from(err: std::io::Error) -> PatchError { - PatchError::IOError(err) - } -} - - -#[derive(Debug, Clone)] -pub struct PatchFile { - path: PathBuf, - checksum: u32, - size: u32, -} - -pub enum PatchTreeIterItem { - Directory(PathBuf), - File(PathBuf, u32), - UpDirectory, -} - -#[derive(Debug, Clone)] -pub enum PatchFileTree { - Directory(PathBuf, Vec), - File(PathBuf, u32), // file_id -} - -impl PatchFileTree { - fn iter_dir(tree: &PatchFileTree) -> Vec { - let mut v = Vec::new(); - - match tree { - PatchFileTree::Directory(dir, files) => { - v.push(PatchTreeIterItem::Directory(dir.clone())); - for file in files { - v.append(&mut PatchFileTree::iter_dir(file)); - } - v.push(PatchTreeIterItem::UpDirectory); - }, - PatchFileTree::File(path, id) => { - v.push(PatchTreeIterItem::File(path.clone(), *id)); - } - } - - v - } - - pub fn flatten(&self) -> Vec { - PatchFileTree::iter_dir(self) - } -} - - -#[derive(Debug)] -pub enum RecvPatchPacket { - PatchWelcomeReply(PatchWelcomeReply), - LoginReply(LoginReply), - FileInfoReply(FileInfoReply), - FileInfoListEnd(FileInfoListEnd), -} - -impl RecvServerPacket for RecvPatchPacket { - fn from_bytes(data: &[u8]) -> Result { - match data[2] { - 0x02 => Ok(RecvPatchPacket::PatchWelcomeReply(PatchWelcomeReply::from_bytes(data)?)), - 0x04 => Ok(RecvPatchPacket::LoginReply(LoginReply::from_bytes(data)?)), - 0x0F => Ok(RecvPatchPacket::FileInfoReply(FileInfoReply::from_bytes(data)?)), - 0x10 => Ok(RecvPatchPacket::FileInfoListEnd(FileInfoListEnd::from_bytes(data)?)), - _ => Err(PacketParseError::WrongPacketForServerType(u16::from_le_bytes([data[2], data[3]]), data.to_vec())) - } - } -} - -#[derive(Debug)] -pub enum SendPatchPacket { - ChangeDirectory(ChangeDirectory), - EndFileSend(EndFileSend), - FileInfo(FileInfo), - FileSend(Box), - FilesToPatchMetadata(FilesToPatchMetadata), - FinalizePatching(FinalizePatching), - Message(Message), - PatchEndList(PatchEndList), - PatchStartList(PatchStartList), - PatchWelcome(PatchWelcome), - RequestLogin(RequestLogin), - StartFileSend(StartFileSend), - UpOneDirectory(UpOneDirectory), -} - -impl SendServerPacket for SendPatchPacket { - fn as_bytes(&self) -> Vec { - match self { - SendPatchPacket::ChangeDirectory(pkt) => pkt.as_bytes(), - SendPatchPacket::EndFileSend(pkt) => pkt.as_bytes(), - SendPatchPacket::FileInfo(pkt) => pkt.as_bytes(), - SendPatchPacket::FileSend(pkt) => pkt.as_bytes(), - SendPatchPacket::FilesToPatchMetadata(pkt) => pkt.as_bytes(), - SendPatchPacket::FinalizePatching(pkt) => pkt.as_bytes(), - SendPatchPacket::Message(pkt) => pkt.as_bytes(), - SendPatchPacket::PatchEndList(pkt) => pkt.as_bytes(), - SendPatchPacket::PatchStartList(pkt) => pkt.as_bytes(), - SendPatchPacket::PatchWelcome(pkt) => pkt.as_bytes(), - SendPatchPacket::RequestLogin(pkt) => pkt.as_bytes(), - SendPatchPacket::StartFileSend(pkt) => pkt.as_bytes(), - SendPatchPacket::UpOneDirectory(pkt) => pkt.as_bytes(), - } - } -} - - -#[derive(Clone)] -pub struct PatchServerState { - patch_file_tree: PatchFileTree, - patch_file_lookup: HashMap, - patch_file_info: Vec, - patch_motd: String, -} - -impl PatchServerState { - pub fn new(patch_file_tree: PatchFileTree, patch_file_lookup: HashMap, patch_motd: String) -> PatchServerState { - PatchServerState { - patch_file_tree, - patch_file_lookup, - patch_file_info: Vec::new(), - patch_motd, - } - } -} - -#[async_trait::async_trait] -impl ServerState for PatchServerState { - type SendPacket = SendPatchPacket; - type RecvPacket = RecvPatchPacket; - type Cipher = PSOPCCipher; - type PacketError = PatchError; - - async fn on_connect(&mut self, _id: ClientId) -> Result>, PatchError> { - let mut rng = rand::thread_rng(); - let key_in: u32 = rng.gen(); - let key_out: u32 = rng.gen(); - - Ok(vec![OnConnect::Packet(SendPatchPacket::PatchWelcome(PatchWelcome::new(key_out, key_in))), - OnConnect::Cipher(PSOPCCipher::new(key_in), PSOPCCipher::new(key_out)) - ]) - } - - async fn handle(&mut self, id: ClientId, pkt: RecvPatchPacket) -> Result, PatchError> { - Ok(match pkt { - RecvPatchPacket::PatchWelcomeReply(_pkt) => { - vec![SendPatchPacket::RequestLogin(RequestLogin {})] - .into_iter() - .map(move |pkt| (id, pkt)) - .collect() - }, - RecvPatchPacket::LoginReply(_pkt) => { - let mut pkts = vec![SendPatchPacket::Message(Message::new(self.patch_motd.clone()))]; - pkts.append(&mut get_file_list_packets(&self.patch_file_tree)); - pkts.push(SendPatchPacket::PatchEndList(PatchEndList {})); - pkts - .into_iter() - .map(move |pkt| (id, pkt)) - .collect() - }, - RecvPatchPacket::FileInfoReply(pkt) => { - self.patch_file_info.push(pkt); - Vec::new() - }, - RecvPatchPacket::FileInfoListEnd(_pkt) => { - let need_update = self.patch_file_info.iter() - .filter(|file_info| does_file_need_updating(file_info, &self.patch_file_lookup)) - .collect::>(); - - let total_size = need_update.iter().fold(0, |a, file_info| a + file_info.size); - let total_files = need_update.len() as u32; - - vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)), - SendPatchPacket::PatchStartList(PatchStartList {})] - .into_iter() - .chain(SendFileIterator::new(self)) - .map(move |pkt| (id, pkt)) - .collect() - } - }) - } - - async fn on_disconnect(&mut self, _id: ClientId) -> Result, PatchError> { - Ok(Vec::new()) - } -} - -fn load_patch_dir(basedir: &str, patchbase: &str, file_ids: &mut HashMap) -> PatchFileTree { - let paths = fs::read_dir(basedir).expect("could not read directory"); - - let mut files = Vec::new(); - let mut dirs = Vec::new(); - for p in paths { - let path = p.expect("not a real path").path(); - let patch_path = path.strip_prefix(basedir).unwrap(); - if path.is_dir() { - dirs.push(load_patch_dir(path.to_str().unwrap(), patch_path.to_str().unwrap(), file_ids)); - } - else { - files.push(PatchFileTree::File(patch_path.to_path_buf(), file_ids.len() as u32)); - let (checksum, size) = get_checksum_and_size(&path).unwrap(); - file_ids.insert(file_ids.len() as u32, PatchFile { - path, - checksum, - size, - }); - } - } - - files.append(&mut dirs); - - PatchFileTree::Directory(PathBuf::from(patchbase), files) -} - -pub fn generate_patch_tree(basedir: &str) -> (PatchFileTree, HashMap) { - let mut file_ids = HashMap::new(); - - let patch_tree = load_patch_dir(basedir, "", &mut file_ids); - - (patch_tree, file_ids) -} - - -fn get_file_list_packets(patch_file_tree: &PatchFileTree) -> Vec { - let mut pkts = Vec::new(); - - for item in patch_file_tree.flatten() { - match item { - PatchTreeIterItem::Directory(path) => { - pkts.push(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap()))); - }, - PatchTreeIterItem::File(path, id) => { - pkts.push(SendPatchPacket::FileInfo(FileInfo::new(path.to_str().unwrap(), id))); - }, - PatchTreeIterItem::UpDirectory => { - pkts.push(SendPatchPacket::UpOneDirectory(UpOneDirectory {})); - } - } - } - - pkts -} - -fn get_checksum_and_size(path: &Path) -> Result<(u32, u32), PatchError> { - let file = fs::File::open(path)?; - let size = file.metadata().unwrap().len(); - let mut crc = crc32::Digest::new(crc32::IEEE); - let mut buf = [0u8; 1024 * 32]; - let mut reader = io::BufReader::new(file); - while let Ok(len) = reader.read(&mut buf) { - if len == 0 { - break; - } - crc.write(&buf[0..len]); - } - - Ok((crc.sum32(), size as u32)) -} - -fn does_file_need_updating(file_info: &FileInfoReply, patch_file_lookup: &HashMap) -> bool { - let patch_file = patch_file_lookup.get(&file_info.id).unwrap(); - patch_file.checksum != file_info.checksum || patch_file.size != file_info.size -} - - -struct SendFileIterator { - done: bool, - file_iter: Box + Send>, - patch_file_lookup: HashMap, - current_file: Option>, - chunk_num: u32, -} - -impl SendFileIterator { - fn new(state: &PatchServerState) -> SendFileIterator { - let file_ids_to_update = state.patch_file_info.iter() - .filter(|file_info| does_file_need_updating(file_info, &state.patch_file_lookup)) - .map(|k| k.id) - .collect::>(); - - SendFileIterator { - done: false, - patch_file_lookup: state.patch_file_lookup.clone(), - file_iter: Box::new(state.patch_file_tree.flatten().into_iter().filter(move |file| { - match file { - PatchTreeIterItem::File(_path, id) => { - file_ids_to_update.contains(id) - }, - _ => true, - } - })), - current_file: None, - chunk_num: 0, - } - } -} - -impl Iterator for SendFileIterator { - type Item = SendPatchPacket; - - fn next(&mut self) -> Option { - if self.done { - return None; - } - - match self.current_file { - Some(ref mut file) => { - let mut buf = [0u8; PATCH_FILE_CHUNK_SIZE as usize]; - let len = file.read(&mut buf).unwrap(); - if len == 0 { - self.current_file = None; - self.chunk_num = 0; - Some(SendPatchPacket::EndFileSend(EndFileSend::new())) - } - else { - let mut crc = crc32::Digest::new(crc32::IEEE); - crc.write(&buf[0..len]); - let pkt = SendPatchPacket::FileSend(Box::new(FileSend { - chunk_num: self.chunk_num, - checksum: crc.sum32(), - chunk_size: len as u32, - buffer: buf, - })); - self.chunk_num += 1; - Some(pkt) - } - }, - None => { - match self.file_iter.next() { - Some(next_file) => { - match next_file { - PatchTreeIterItem::Directory(path) => { - Some(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap()))) - }, - PatchTreeIterItem::File(path, id) => { - let patch_file = self.patch_file_lookup.get(&id).unwrap(); - let file = fs::File::open(&patch_file.path).unwrap(); - let size = file.metadata().unwrap().len(); - self.current_file = Some(io::BufReader::new(file)); - Some(SendPatchPacket::StartFileSend(StartFileSend::new(path.to_str().unwrap(), size as u32, id))) - }, - PatchTreeIterItem::UpDirectory => { - Some(SendPatchPacket::UpOneDirectory(UpOneDirectory {})) - }, - } - }, - None => { - self.current_file = None; - self.done = true; - Some(SendPatchPacket::FinalizePatching(FinalizePatching {})) - } - } - } - } - } -} - -#[derive(Debug, Deserialize)] -pub struct PatchConfig { - pub path: String, - pub ip: String, // TODO: this does nothing - pub port: u16, -} - -pub fn load_config() -> PatchConfig { - let ini_file = match fs::File::open(std::path::Path::new("patch.ron")) { - Err(err) => panic!("Failed to open patch.ron config file. \n{err}"), - Ok(ini_file) => ini_file, - }; - - let mut s = String::new(); - if let Err(err) = (&ini_file).read_to_string(&mut s) { - panic!("Failed to read patch.ron config file. \n{err}"); - } - - let config: PatchConfig = match from_str(s.as_str()) { - Ok(config) => config, - Err(err) => panic!("Failed to load values from patch.ron \n{err}"), - }; - config -} - -pub fn load_config_env() -> PatchConfig { - let patch_path = std::env::var("PATCHFILE_DIR").unwrap(); - let patch_port = std::env::var("PATCH_PORT").unwrap().parse().unwrap(); - - PatchConfig { - path: patch_path, - ip: "127.0.0.1".into(), - port: patch_port, - } -} - -pub fn load_motd() -> String { - if let Ok(m) = fs::read_to_string("patch.motd") { - m - } - else { - "Welcome to Elseware!".to_string() - } -} From 183fba9afe90c29c2ec44e3eed134184ac2d492f Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 17:11:55 -0700 Subject: [PATCH 18/29] speed up tests by not loading quests every time --- room/src/lib.rs | 13 ++++++---- src/bin/main.rs | 6 +++++ src/bin/ship.rs | 2 ++ src/ship/packet/handler/room.rs | 5 +++- src/ship/ship.rs | 42 ++++++++++++++++++++++++++------- tests/test_rooms.rs | 4 ++++ 6 files changed, 57 insertions(+), 15 deletions(-) diff --git a/room/src/lib.rs b/room/src/lib.rs index 897c20f..3f19b0b 100644 --- a/room/src/lib.rs +++ b/room/src/lib.rs @@ -7,6 +7,7 @@ use futures::stream::{FuturesOrdered, Stream}; use thiserror::Error; use rand::Rng; +use quests::{QuestList, QuestLoadError}; use maps::maps::Maps; use drops::DropTable; use entity::character::SectionID; @@ -177,8 +178,8 @@ pub struct RoomState { 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 } @@ -213,7 +214,7 @@ 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, @@ -231,6 +232,8 @@ impl RoomState { event: Holiday, map_builder: Arc Maps + Send + Sync>>, drop_table_builder: Arc DropTable + 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 { @@ -263,8 +266,8 @@ impl RoomState { 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/bin/main.rs b/src/bin/main.rs index e50db30..a4f0eb0 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -365,6 +365,8 @@ fn main() { .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT) .event(Holiday::Halloween) + .standard_quest_builder(Box::new(quests::load_standard_quests)) + .government_quest_builder(Box::new(quests::load_government_quests)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); @@ -381,6 +383,8 @@ fn main() { .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT+2000) .event(Holiday::Christmas) + .standard_quest_builder(Box::new(quests::load_standard_quests)) + .government_quest_builder(Box::new(quests::load_government_quests)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); @@ -396,6 +400,8 @@ fn main() { .name("JP/Thalarion".into()) .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT+3000) + .standard_quest_builder(Box::new(quests::load_standard_quests)) + .government_quest_builder(Box::new(quests::load_government_quests)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); diff --git a/src/bin/ship.rs b/src/bin/ship.rs index c021601..f6122f7 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -43,6 +43,8 @@ fn main() { .port(elseware::ship::ship::SHIP_PORT) .gateway(entity_gateway) .auth_token(AuthToken(shipgate_token)) + .standard_quest_builder(Box::new(quests::load_standard_quests)) + .government_quest_builder(Box::new(quests::load_government_quests)) .build(); let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap(); diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 26e98b4..8ec8e3a 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -20,6 +20,7 @@ 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, @@ -31,6 +32,8 @@ pub async fn create_room(id: ClientId, rooms: &Rooms, map_builder: Arc Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, + standard_quest_builder: Arc Result + Send + Sync>>, + government_quest_builder: Arc Result + Send + Sync>>, event: Holiday) -> Result, anyhow::Error> where @@ -91,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??; diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 33e8aa6..4fb4126 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -25,6 +25,9 @@ use location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; use drops::DropTable; use items; use room; +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}; @@ -293,14 +296,14 @@ impl SendServerPacket for SendShipPacket { #[derive(Clone)] pub struct ItemShops { - pub weapon_shop: HashMap<(maps::room::Difficulty, SectionID), Arc>>>, + pub weapon_shop: HashMap<(Difficulty, SectionID), Arc>>>, pub tool_shop: Arc>>, pub armor_shop: Arc>>, } impl Default for ItemShops { fn default() -> ItemShops { - let difficulty = [maps::room::Difficulty::Normal, maps::room::Difficulty::Hard, maps::room::Difficulty::VeryHard, maps::room::Difficulty::Ultimate]; + 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]; @@ -327,8 +330,10 @@ pub struct ShipServerStateBuilder { port: Option, auth_token: Option, event: Option, - map_builder: Option Maps + Send + Sync>>, - drop_table_builder: Option DropTable + Send + Sync>>, + map_builder: Option Maps + Send + Sync>>, + drop_table_builder: Option DropTable + Send + Sync>>, + standard_quest_builder: Option Result + Send + Sync>>, + government_quest_builder: Option Result + Send + Sync>>, num_blocks: usize, } @@ -343,6 +348,8 @@ impl Default for ShipServerStateBuilder event: None, map_builder: None, drop_table_builder: None, + standard_quest_builder: None, + government_quest_builder: None, num_blocks: 2, } } @@ -386,17 +393,29 @@ impl ShipServerStateBuilder { } #[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 DropTable + 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 blocks(mut self, num_blocks: usize) -> ShipServerStateBuilder { self.num_blocks = num_blocks; @@ -417,6 +436,8 @@ impl ShipServerStateBuilder { event: self.event.unwrap_or(Holiday::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))), + standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), + government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), ship_list: Arc::new(RwLock::new(Vec::new())), @@ -464,8 +485,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 DropTable + Send + Sync>>, + standard_quest_builder: Arc Result + Send + Sync>>, + government_quest_builder: Arc Result + Send + Sync>>, } impl ShipServerState { @@ -707,7 +730,8 @@ impl ServerState for ShipServerState { 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? + &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?; diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index cb10dfb..4a4f300 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -16,6 +16,8 @@ async fn test_set_valid_quest_group() { let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; let mut ship = Box::new(ShipServerState::builder() .gateway(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; @@ -36,6 +38,8 @@ async fn test_set_invalid_quest_group() { let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; let mut ship = Box::new(ShipServerState::builder() .gateway(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; From af629695a545df182ddd3b0fc905bd38b7e7b157 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 18:17:18 -0700 Subject: [PATCH 19/29] further speed up tests by not loading drop charts by default --- drops/src/lib.rs | 47 ++++++++++++++++++++++++--------- room/src/lib.rs | 6 ++--- src/bin/main.rs | 4 +++ src/bin/ship.rs | 2 ++ src/ship/packet/handler/room.rs | 2 +- src/ship/ship.rs | 10 +++---- tests/test_item_drop.rs | 8 +++--- 7 files changed, 53 insertions(+), 26 deletions(-) diff --git a/drops/src/lib.rs b/drops/src/lib.rs index bccffd4..c7c76d0 100644 --- a/drops/src/lib.rs +++ b/drops/src/lib.rs @@ -98,7 +98,7 @@ impl ItemDropType { .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()?)), @@ -121,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, @@ -133,11 +138,11 @@ pub struct DropTable { rng: rand_chacha::ChaCha20Rng, } -impl DropTable { - pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable { +impl StandardDropTable { + 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), @@ -147,7 +152,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 { @@ -177,8 +182,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); @@ -191,7 +198,7 @@ impl DropTable { } let drop_type = self.rng.gen_range(0, 3); - + match drop_type { 0 => { self.generate_meseta(&monster_stat) @@ -206,7 +213,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) } } @@ -253,8 +260,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() @@ -267,10 +274,24 @@ 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), - } + }) } } +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(_episode: Episode, _difficult: Difficulty, _section_id: SectionID) -> Box { + Box::new(NullDropTable) +} #[cfg(test)] mod test { diff --git a/room/src/lib.rs b/room/src/lib.rs index 3f19b0b..fca3669 100644 --- a/room/src/lib.rs +++ b/room/src/lib.rs @@ -171,7 +171,7 @@ 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, @@ -231,7 +231,7 @@ impl RoomState { password: [u16; 16], event: Holiday, map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, + drop_table_builder: Arc Box + Send + Sync>>, standard_quest_builder: Arc Result + Send + Sync>>, government_quest_builder: Arc Result + Send + Sync>>, ) -> Result { @@ -262,7 +262,7 @@ 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, diff --git a/src/bin/main.rs b/src/bin/main.rs index a4f0eb0..caebcc5 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -13,6 +13,7 @@ use entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use entity::character::NewCharacterEntity; use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; use entity::item; +use drops::{DropTable, StandardDropTable}; fn setup_logger() { let colors = fern::colors::ColoredLevelConfig::new() @@ -367,6 +368,7 @@ fn main() { .event(Holiday::Halloween) .standard_quest_builder(Box::new(quests::load_standard_quests)) .government_quest_builder(Box::new(quests::load_government_quests)) + .drop_table_builder(Box::new(StandardDropTable::new)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); @@ -385,6 +387,7 @@ fn main() { .event(Holiday::Christmas) .standard_quest_builder(Box::new(quests::load_standard_quests)) .government_quest_builder(Box::new(quests::load_government_quests)) + .drop_table_builder(Box::new(StandardDropTable::new)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); @@ -402,6 +405,7 @@ fn main() { .port(elseware::ship::ship::SHIP_PORT+3000) .standard_quest_builder(Box::new(quests::load_standard_quests)) .government_quest_builder(Box::new(quests::load_government_quests)) + .drop_table_builder(Box::new(StandardDropTable::new)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); diff --git a/src/bin/ship.rs b/src/bin/ship.rs index f6122f7..f5fff5d 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -2,6 +2,7 @@ use log::info; use entity::gateway::postgres::PostgresGateway; use elseware::ship::ship::ShipServerStateBuilder; use networking::interserver::AuthToken; +use drops::{DropTable, StandardDropTable}; fn main() { let colors = fern::colors::ColoredLevelConfig::new() @@ -45,6 +46,7 @@ fn main() { .auth_token(AuthToken(shipgate_token)) .standard_quest_builder(Box::new(quests::load_standard_quests)) .government_quest_builder(Box::new(quests::load_government_quests)) + .drop_table_builder(Box::new(StandardDropTable::new)) .build(); let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap(); diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 8ec8e3a..563385d 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -31,7 +31,7 @@ pub async fn create_room(id: ClientId, item_state: &mut ItemState, rooms: &Rooms, map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + 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) diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 4fb4126..5d8beea 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -22,7 +22,7 @@ use entity::gateway::{EntityGateway, GatewayError}; use entity::character::SectionID; use entity::room::RoomNote; use location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; -use drops::DropTable; +use drops::{DropTable, null_drop_table}; use items; use room; use maps::room::{RoomMode, Episode, Difficulty}; @@ -331,7 +331,7 @@ pub struct ShipServerStateBuilder { auth_token: Option, event: Option, map_builder: Option Maps + Send + Sync>>, - drop_table_builder: Option DropTable + 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, @@ -399,7 +399,7 @@ impl ShipServerStateBuilder { } #[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 } @@ -435,7 +435,7 @@ impl ShipServerStateBuilder { blocks: Blocks(blocks), event: self.event.unwrap_or(Holiday::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))), + drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(null_drop_table))), standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), @@ -486,7 +486,7 @@ pub struct ShipServerState { shipgate_sender: Option>, trades: TradeState, map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, + drop_table_builder: Arc Box + Send + Sync>>, standard_quest_builder: Arc Result + Send + Sync>>, government_quest_builder: Arc Result + Send + Sync>>, } diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs index 20b6a98..029e0ef 100644 --- a/tests/test_item_drop.rs +++ b/tests/test_item_drop.rs @@ -2,7 +2,7 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::InMemoryGateway; use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; use maps::monster::MonsterType; -use drops::{DropTable, MonsterDropStats, MonsterDropType}; +use drops::{StandardDropTable, MonsterDropStats, MonsterDropType}; use drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; use maps::maps::Maps; use maps::area::MapArea; @@ -32,7 +32,7 @@ async fn test_enemy_drops_item() { ) })) .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() + StandardDropTable::builder() .monster_stat(MonsterType::Hildebear, MonsterDropStats { dar: 100, drop_type: MonsterDropType::Weapon, @@ -88,7 +88,7 @@ async fn test_enemy_drops_item_for_two_players() { ) })) .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() + StandardDropTable::builder() .monster_stat(MonsterType::Hildebear, MonsterDropStats { dar: 100, drop_type: MonsterDropType::Weapon, @@ -156,7 +156,7 @@ async fn test_enemy_drops_item_for_two_players_and_pick_up() { ) })) .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() + StandardDropTable::builder() .monster_stat(MonsterType::Hildebear, MonsterDropStats { dar: 100, drop_type: MonsterDropType::Weapon, From 7b26fdc28d60bb2b70459080a514705c7d3734b3 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 19:05:12 -0700 Subject: [PATCH 20/29] clippy --- drops/src/lib.rs | 1 + src/bin/main.rs | 2 +- src/bin/ship.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drops/src/lib.rs b/drops/src/lib.rs index c7c76d0..1a2cca7 100644 --- a/drops/src/lib.rs +++ b/drops/src/lib.rs @@ -139,6 +139,7 @@ pub struct StandardDropTable { } 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"); diff --git a/src/bin/main.rs b/src/bin/main.rs index caebcc5..126cbb1 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -13,7 +13,7 @@ use entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use entity::character::NewCharacterEntity; use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; use entity::item; -use drops::{DropTable, StandardDropTable}; +use drops::StandardDropTable; fn setup_logger() { let colors = fern::colors::ColoredLevelConfig::new() diff --git a/src/bin/ship.rs b/src/bin/ship.rs index f5fff5d..7204925 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -2,7 +2,7 @@ use log::info; use entity::gateway::postgres::PostgresGateway; use elseware::ship::ship::ShipServerStateBuilder; use networking::interserver::AuthToken; -use drops::{DropTable, StandardDropTable}; +use drops::StandardDropTable; fn main() { let colors = fern::colors::ColoredLevelConfig::new() From d0866f5e83bde05ee6936de2cf4baf17534766c5 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 19:58:12 -0700 Subject: [PATCH 21/29] maybe this will work for keeping the ci from filling the disk and making everyone sad --- .drone.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.drone.yml b/.drone.yml index ac685b1..c57acb0 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,16 +7,40 @@ concurrency: limit: 1 steps: +- name: clean cache + image: rustlang/rust:nightly + volumes: + - name: cache + path: /usr/local/cargo + - name: target-cache + path: /drone/src/target + commands: + - cargo sweep --maxsize 12GiB - name: build image: rustlang/rust:nightly + volumes: + - name: cache + path: /usr/local/cargo + - name: target-cache + path: /drone/src/target commands: - cargo build - name: clippy! image: rustlang/rust:nightly + volumes: + - name: cache + path: /usr/local/cargo + - name: target-cache + path: /drone/src/target commands: - cargo clippy -- --deny warnings - name: test image: rustlang/rust:nightly + volumes: + - name: cache + path: /usr/local/cargo + - name: target-cache + path: /drone/src/target commands: - cargo test --jobs 1 From 3cd4e9db10afd3a9f69c3eeda4f63f6c8dc073df Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 21:25:06 -0700 Subject: [PATCH 22/29] null free roam maps by default --- maps/src/maps.rs | 9 +++++++++ src/bin/main.rs | 4 ++++ src/bin/ship.rs | 2 ++ src/ship/ship.rs | 4 ++-- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/maps/src/maps.rs b/maps/src/maps.rs index 4ca76d9..2ed7961 100644 --- a/maps/src/maps.rs +++ b/maps/src/maps.rs @@ -376,3 +376,12 @@ pub fn generate_free_roam_maps(room_mode: RoomMode, event: Holiday) -> 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/bin/main.rs b/src/bin/main.rs index 126cbb1..afeb79f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -8,6 +8,7 @@ use elseware::patch::{PatchServerState, generate_patch_tree, load_config, load_m use elseware::ship::ship::ShipServerStateBuilder; use maps::Holiday; +use maps::maps::generate_free_roam_maps; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use entity::character::NewCharacterEntity; @@ -369,6 +370,7 @@ fn main() { .standard_quest_builder(Box::new(quests::load_standard_quests)) .government_quest_builder(Box::new(quests::load_government_quests)) .drop_table_builder(Box::new(StandardDropTable::new)) + .map_builder(Box::new(generate_free_roam_maps)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); @@ -388,6 +390,7 @@ fn main() { .standard_quest_builder(Box::new(quests::load_standard_quests)) .government_quest_builder(Box::new(quests::load_government_quests)) .drop_table_builder(Box::new(StandardDropTable::new)) + .map_builder(Box::new(generate_free_roam_maps)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); @@ -406,6 +409,7 @@ fn main() { .standard_quest_builder(Box::new(quests::load_standard_quests)) .government_quest_builder(Box::new(quests::load_government_quests)) .drop_table_builder(Box::new(StandardDropTable::new)) + .map_builder(Box::new(generate_free_roam_maps)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); diff --git a/src/bin/ship.rs b/src/bin/ship.rs index 7204925..b39f504 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -3,6 +3,7 @@ use entity::gateway::postgres::PostgresGateway; use elseware::ship::ship::ShipServerStateBuilder; use networking::interserver::AuthToken; use drops::StandardDropTable; +use maps::maps::generate_free_roam_maps; fn main() { let colors = fern::colors::ColoredLevelConfig::new() @@ -47,6 +48,7 @@ fn main() { .standard_quest_builder(Box::new(quests::load_standard_quests)) .government_quest_builder(Box::new(quests::load_government_quests)) .drop_table_builder(Box::new(StandardDropTable::new)) + .map_builder(Box::new(generate_free_roam_maps)) .build(); let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap(); diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 5d8beea..b584ad5 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -30,7 +30,7 @@ use maps::room::{RoomMode, Episode, Difficulty}; use quests::{QuestList, QuestLoadError}; use maps::Holiday; use maps::area::MapAreaError; -use maps::maps::{Maps, MapsError, generate_free_roam_maps}; +use maps::maps::{Maps, MapsError, null_free_roam_maps}; use crate::ship::packet::handler; use shops::{WeaponShop, ToolShop, ArmorShop}; use trade::TradeState; @@ -434,7 +434,7 @@ impl ShipServerStateBuilder { shops: ItemShops::default(), blocks: Blocks(blocks), event: self.event.unwrap_or(Holiday::None), - map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(generate_free_roam_maps))), + map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(null_free_roam_maps))), drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(null_drop_table))), standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), From 1be61556ab27d2fca3a3fab88b7c6751bde7a813 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 22:02:36 -0700 Subject: [PATCH 23/29] default to useful things, tests null things out on their own --- drops/src/lib.rs | 15 ---- src/bin/main.rs | 12 --- src/bin/ship.rs | 4 - src/ship/ship.rs | 14 ++-- tests/common.rs | 49 +++++++++++- tests/test_bank.rs | 124 ++++++++---------------------- tests/test_character.rs | 8 +- tests/test_exp_gain.rs | 76 +++++++++--------- tests/test_item_actions.rs | 12 +-- tests/test_item_drop.rs | 153 ++++++++++++++++++------------------- tests/test_item_id.rs | 12 +-- tests/test_item_pickup.rs | 44 +++-------- tests/test_item_use.rs | 32 ++------ tests/test_mags.rs | 12 +-- tests/test_rooms.rs | 22 ++---- tests/test_shops.rs | 108 +++++++------------------- tests/test_trade.rs | 152 +++++++++--------------------------- 17 files changed, 297 insertions(+), 552 deletions(-) diff --git a/drops/src/lib.rs b/drops/src/lib.rs index 1a2cca7..32a14db 100644 --- a/drops/src/lib.rs +++ b/drops/src/lib.rs @@ -279,21 +279,6 @@ impl DropTableBuilder { } } -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(_episode: Episode, _difficult: Difficulty, _section_id: SectionID) -> Box { - Box::new(NullDropTable) -} - #[cfg(test)] mod test { use super::*; diff --git a/src/bin/main.rs b/src/bin/main.rs index afeb79f..79f95be 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -367,10 +367,6 @@ fn main() { .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT) .event(Holiday::Halloween) - .standard_quest_builder(Box::new(quests::load_standard_quests)) - .government_quest_builder(Box::new(quests::load_government_quests)) - .drop_table_builder(Box::new(StandardDropTable::new)) - .map_builder(Box::new(generate_free_roam_maps)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); @@ -387,10 +383,6 @@ fn main() { .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT+2000) .event(Holiday::Christmas) - .standard_quest_builder(Box::new(quests::load_standard_quests)) - .government_quest_builder(Box::new(quests::load_government_quests)) - .drop_table_builder(Box::new(StandardDropTable::new)) - .map_builder(Box::new(generate_free_roam_maps)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); @@ -406,10 +398,6 @@ fn main() { .name("JP/Thalarion".into()) .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT+3000) - .standard_quest_builder(Box::new(quests::load_standard_quests)) - .government_quest_builder(Box::new(quests::load_government_quests)) - .drop_table_builder(Box::new(StandardDropTable::new)) - .map_builder(Box::new(generate_free_roam_maps)) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); diff --git a/src/bin/ship.rs b/src/bin/ship.rs index b39f504..baf87c6 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -45,10 +45,6 @@ fn main() { .port(elseware::ship::ship::SHIP_PORT) .gateway(entity_gateway) .auth_token(AuthToken(shipgate_token)) - .standard_quest_builder(Box::new(quests::load_standard_quests)) - .government_quest_builder(Box::new(quests::load_government_quests)) - .drop_table_builder(Box::new(StandardDropTable::new)) - .map_builder(Box::new(generate_free_roam_maps)) .build(); let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap(); diff --git a/src/ship/ship.rs b/src/ship/ship.rs index b584ad5..c920376 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -22,15 +22,15 @@ use entity::gateway::{EntityGateway, GatewayError}; use entity::character::SectionID; use entity::room::RoomNote; use location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; -use drops::{DropTable, null_drop_table}; +use drops::{DropTable, StandardDropTable}; use items; use room; use maps::room::{RoomMode, Episode, Difficulty}; -//use quests::{load_standard_quests, load_government_quests}; +use quests::{load_standard_quests, load_government_quests}; use quests::{QuestList, QuestLoadError}; use maps::Holiday; use maps::area::MapAreaError; -use maps::maps::{Maps, MapsError, null_free_roam_maps}; +use maps::maps::{Maps, MapsError, generate_free_roam_maps}; use crate::ship::packet::handler; use shops::{WeaponShop, ToolShop, ArmorShop}; use trade::TradeState; @@ -434,10 +434,10 @@ impl ShipServerStateBuilder { shops: ItemShops::default(), blocks: Blocks(blocks), event: self.event.unwrap_or(Holiday::None), - map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(null_free_roam_maps))), - drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(null_drop_table))), - standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), - government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), + 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(StandardDropTable::new))), + standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or(Box::new(load_standard_quests))), + government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or(Box::new(load_government_quests))), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), ship_list: Arc::new(RwLock::new(Vec::new())), diff --git a/tests/common.rs b/tests/common.rs index 1c11777..f28d318 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -3,10 +3,16 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::EntityGateway; use entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; -use entity::character::{CharacterEntity, NewCharacterEntity}; +use entity::character::{CharacterEntity, NewCharacterEntity, SectionID}; use entity::item::{Meseta, BankIdentifier}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use maps::room::Difficulty; +use elseware::ship::ship::{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 entity::item; @@ -14,6 +20,43 @@ use libpso::packet::ship::*; use libpso::packet::login::{Login, Session}; use libpso::{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) +} + +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)) +} + +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)) + .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) { diff --git a/tests/test_bank.rs b/tests/test_bank.rs index c7d7f20..2a97d6b 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -33,9 +33,7 @@ async fn test_bank_items_sent_in_character_login() { 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 { @@ -71,9 +69,7 @@ async fn test_request_bank_items() { 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; @@ -115,9 +111,7 @@ async fn test_request_stacked_bank_items() { 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; @@ -180,9 +174,7 @@ async fn test_request_bank_items_sorted() { 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; @@ -237,9 +229,7 @@ async fn test_deposit_individual_item() { 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; @@ -303,9 +293,7 @@ async fn test_deposit_stacked_item() { 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; @@ -364,9 +352,7 @@ async fn test_deposit_partial_stacked_item() { 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; @@ -445,9 +431,7 @@ async fn test_deposit_stacked_item_with_stack_already_in_bank() { 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; @@ -518,9 +502,7 @@ async fn test_deposit_stacked_item_with_full_stack_in_bank() { 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; @@ -596,9 +578,7 @@ async fn test_deposit_individual_item_in_full_bank() { 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; @@ -668,9 +648,7 @@ async fn test_deposit_stacked_item_in_full_bank() { 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; @@ -754,9 +732,7 @@ async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { 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; @@ -794,9 +770,7 @@ async fn test_deposit_meseta() { let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).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; @@ -831,9 +805,7 @@ async fn test_deposit_too_much_meseta() { 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; @@ -870,9 +842,7 @@ async fn test_deposit_meseta_when_bank_is_maxed() { 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; @@ -925,9 +895,7 @@ async fn test_withdraw_individual_item() { 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; @@ -985,9 +953,7 @@ async fn test_withdraw_stacked_item() { 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; @@ -1044,9 +1010,7 @@ async fn test_withdraw_partial_stacked_item() { } 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; @@ -1122,9 +1086,7 @@ async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { 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; @@ -1197,9 +1159,7 @@ async fn test_withdraw_stacked_item_with_full_stack_in_inventory() { 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; @@ -1275,9 +1235,7 @@ async fn test_withdraw_individual_item_in_full_inventory() { 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; @@ -1343,9 +1301,7 @@ async fn test_withdraw_stacked_item_in_full_inventory() { 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; @@ -1430,9 +1386,7 @@ async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { 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; @@ -1473,9 +1427,7 @@ async fn test_withdraw_meseta() { let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).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; @@ -1510,9 +1462,7 @@ async fn test_withdraw_too_much_meseta() { 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; @@ -1549,9 +1499,7 @@ async fn test_withdraw_meseta_inventory_is_maxed() { 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; @@ -1590,9 +1538,7 @@ async fn test_withdraw_meseta_and_buy_a_few_monomates_with_it() { 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(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; @@ -1649,9 +1595,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; @@ -1765,9 +1709,7 @@ async fn test_deposit_meseta_into_shared_banks() { let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).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; @@ -1852,9 +1794,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; @@ -1956,9 +1896,7 @@ async fn test_withdraw_meseta_from_shared_banks() { 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 9052c74..ee78434 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -15,9 +15,7 @@ async fn test_save_options() { 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 mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -37,9 +35,7 @@ async fn test_change_keyboard_mappings() { let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 2).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 13a0eca..5e4bcf9 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -21,16 +21,15 @@ async fn test_character_gains_exp() { 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 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; @@ -57,16 +56,15 @@ async fn test_character_levels_up() { 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; @@ -94,16 +92,15 @@ async fn test_character_levels_up_multiple_times() { 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 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; @@ -131,16 +128,15 @@ async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { 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 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 9964bd6..0212d08 100644 --- a/tests/test_item_actions.rs +++ b/tests/test_item_actions.rs @@ -56,9 +56,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; @@ -133,9 +131,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; @@ -193,9 +189,7 @@ async fn test_sort_items() { 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; diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs index 029e0ef..bac45ac 100644 --- a/tests/test_item_drop.rs +++ b/tests/test_item_drop.rs @@ -22,32 +22,31 @@ 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| { - 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()); + 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; @@ -78,32 +77,31 @@ async fn test_enemy_drops_item_for_two_players() { 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| { - 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()); + 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; @@ -146,32 +144,31 @@ async fn test_enemy_drops_item_for_two_players_and_pick_up() { 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| { - 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()); + 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 06ec3b4..ff8f4ad 100644 --- a/tests/test_item_id.rs +++ b/tests/test_item_id.rs @@ -53,9 +53,7 @@ async fn test_use_monomate_after_leaving_and_rejoining_room() { 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; @@ -167,9 +165,7 @@ async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins } 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; @@ -330,9 +326,7 @@ async fn test_depositing_a_full_stack_then_withdrawing_part() { } 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 fd38cb1..d1ba62e 100644 --- a/tests/test_item_pickup.rs +++ b/tests/test_item_pickup.rs @@ -34,9 +34,7 @@ async fn test_pick_up_individual_item() { 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; @@ -117,9 +115,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; @@ -176,9 +172,7 @@ async fn test_pick_up_item_stack_of_items_not_already_held() { 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; @@ -242,9 +236,7 @@ async fn test_pick_up_meseta_when_inventory_full() { 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; @@ -334,9 +326,7 @@ async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_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(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; @@ -412,9 +402,7 @@ async fn test_can_not_pick_up_item_when_inventory_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; @@ -470,9 +458,7 @@ async fn test_can_not_drop_more_meseta_than_is_held() { 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; @@ -535,9 +521,7 @@ async fn test_pick_up_stack_that_would_exceed_stack_limit() { 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; @@ -586,9 +570,7 @@ async fn test_can_not_pick_up_meseta_when_full() { 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; @@ -641,9 +623,7 @@ async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { 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; @@ -706,9 +686,7 @@ async fn test_player_drops_partial_stack_and_other_player_picks_it_up() { 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 67a29b2..0f28a18 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -36,9 +36,7 @@ async fn test_use_monomate() { 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; @@ -83,9 +81,7 @@ async fn test_use_monomate_twice() { 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; @@ -131,9 +127,7 @@ async fn test_use_last_monomate() { 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; @@ -171,9 +165,7 @@ async fn test_use_nonstackable_tool() { 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; @@ -212,9 +204,7 @@ async fn test_use_materials() { 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; @@ -277,9 +267,7 @@ async fn test_jackolantern() { ])]; 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; @@ -346,9 +334,7 @@ async fn test_use_barta_1() { 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; @@ -417,9 +403,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 68adbcd..963e71a 100644 --- a/tests/test_mags.rs +++ b/tests/test_mags.rs @@ -50,9 +50,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; @@ -105,9 +103,7 @@ async fn test_mag_change_owner() { 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; @@ -191,9 +187,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 4a4f300..ced3e27 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -14,11 +14,10 @@ use common::*; 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()) + 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()); + .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; @@ -36,11 +35,10 @@ async fn test_set_valid_quest_group() { 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()) + 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()); + .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; @@ -63,9 +61,7 @@ async fn test_get_room_info() { _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 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; @@ -84,9 +80,7 @@ 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 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; @@ -106,9 +100,7 @@ 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 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 c54d907..392fa5a 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -20,9 +20,7 @@ async fn test_player_opens_weapon_shop() { 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(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::Ultimate).await; @@ -50,9 +48,7 @@ async fn test_player_opens_tool_shop() { 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(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::Ultimate).await; @@ -80,9 +76,7 @@ async fn test_player_opens_armor_shop() { 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(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::Ultimate).await; @@ -111,9 +105,7 @@ async fn test_player_buys_from_weapon_shop() { 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(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::Ultimate).await; @@ -149,9 +141,7 @@ async fn test_player_buys_from_tool_shop() { 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(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::Ultimate).await; @@ -186,9 +176,7 @@ async fn test_player_buys_multiple_from_tool_shop() { 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(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::Ultimate).await; @@ -227,9 +215,7 @@ async fn test_player_buys_from_armor_shop() { 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(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::Ultimate).await; @@ -280,9 +266,7 @@ async fn test_player_sells_3_attr_weapon_to_shop() { 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; @@ -309,9 +293,7 @@ async fn test_other_clients_see_purchase() { 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(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; @@ -360,9 +342,7 @@ async fn test_other_clients_see_stacked_purchase() { ), }).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; @@ -399,9 +379,7 @@ async fn test_buying_item_without_enough_mseseta() { 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 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; @@ -437,9 +415,7 @@ async fn test_player_double_buys_from_tool_shop() { 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(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::Ultimate).await; @@ -502,9 +478,7 @@ async fn test_techs_disappear_from_shop_when_bought() { 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(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::Ultimate).await; @@ -564,9 +538,7 @@ async fn test_units_disappear_from_shop_when_bought() { 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(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::Ultimate).await; @@ -641,9 +613,7 @@ async fn test_player_sells_untekked_weapon() { 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; @@ -685,9 +655,7 @@ async fn test_player_sells_rare_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; @@ -728,9 +696,7 @@ async fn test_player_sells_partial_photon_drop_stack() { 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; @@ -769,9 +735,7 @@ async fn test_player_sells_basic_frame() { 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; @@ -810,9 +774,7 @@ async fn test_player_sells_max_frame() { 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; @@ -850,9 +812,7 @@ async fn test_player_sells_basic_barrier() { 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; @@ -890,9 +850,7 @@ async fn test_player_sells_max_barrier() { 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; @@ -929,9 +887,7 @@ async fn test_player_sells_1_star_minusminus_unit() { 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; @@ -968,9 +924,7 @@ async fn test_player_sells_5_star_plusplus_unit() { 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; @@ -1009,9 +963,7 @@ async fn test_player_sells_rare_frame() { 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; @@ -1049,9 +1001,7 @@ async fn test_player_sells_rare_barrier() { 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; @@ -1088,9 +1038,7 @@ async fn test_player_sells_rare_unit() { 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; @@ -1128,9 +1076,7 @@ async fn test_player_cant_sell_if_meseta_would_go_over_max() { 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 9799156..ec4fb3c 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -133,9 +133,7 @@ async fn test_trade_one_individual_item() { 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; @@ -234,9 +232,7 @@ async fn test_trade_player2_to_player1() { 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; @@ -335,9 +331,7 @@ async fn test_reverse_trade_ack_order() { 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; @@ -439,9 +433,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; @@ -543,9 +535,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; @@ -660,9 +650,7 @@ async fn test_trade_individual_both() { 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; @@ -832,9 +820,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; @@ -1002,9 +988,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; @@ -1178,9 +1162,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; @@ -1350,9 +1332,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; @@ -1487,9 +1467,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; @@ -1679,9 +1657,7 @@ async fn test_trade_multiple_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; @@ -1950,9 +1926,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; @@ -2195,9 +2169,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; @@ -2313,9 +2285,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; @@ -2425,9 +2395,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; @@ -2506,9 +2474,7 @@ async fn test_trade_meseta() { 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; @@ -2588,9 +2554,7 @@ async fn test_trade_too_much_meseta() { 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; @@ -2640,9 +2604,7 @@ async fn test_trade_invalid_amount_of_meseta() { 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; @@ -2692,9 +2654,7 @@ async fn test_trade_meseta_request_and_items_dont_match() { 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; @@ -2741,9 +2701,7 @@ async fn test_player_declined_trade() { 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 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; @@ -2789,9 +2747,7 @@ async fn test_back_out_of_trade_last_minute() { 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; @@ -2885,9 +2841,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; @@ -3027,9 +2981,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; @@ -3133,9 +3085,7 @@ async fn test_client_tries_to_start_two_trades() { 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 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; @@ -3166,9 +3116,7 @@ async fn test_client_tries_trading_with_client_already_trading() { 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 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; @@ -3223,9 +3171,7 @@ async fn test_add_then_remove_individual_item() { 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; @@ -3354,9 +3300,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; @@ -3489,9 +3433,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; @@ -3578,9 +3520,7 @@ async fn test_add_then_remove_meseta() { 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; @@ -3679,9 +3619,7 @@ async fn test_items_to_trade_data_does_not_match() { 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; @@ -3762,9 +3700,7 @@ async fn test_items_to_trade_id_does_not_match() { 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; @@ -3836,9 +3772,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; @@ -3910,9 +3844,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; @@ -4006,9 +3938,7 @@ async fn test_items_to_trade_count_less_than() { 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; @@ -4110,9 +4040,7 @@ async fn test_items_to_trade_count_greater_than() { 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; @@ -4218,9 +4146,7 @@ async fn test_items_to_trade_count_mismatch_with_meseta() { 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; @@ -4295,9 +4221,7 @@ async fn test_dropping_item_after_trade() { 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; From c8813866a502ca04fa96095571f8e10d516e3322 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 22:05:40 -0700 Subject: [PATCH 24/29] clippy --- src/bin/main.rs | 2 -- src/bin/ship.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 79f95be..e50db30 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -8,13 +8,11 @@ use elseware::patch::{PatchServerState, generate_patch_tree, load_config, load_m use elseware::ship::ship::ShipServerStateBuilder; use maps::Holiday; -use maps::maps::generate_free_roam_maps; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use entity::character::NewCharacterEntity; use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; use entity::item; -use drops::StandardDropTable; fn setup_logger() { let colors = fern::colors::ColoredLevelConfig::new() diff --git a/src/bin/ship.rs b/src/bin/ship.rs index baf87c6..c021601 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -2,8 +2,6 @@ use log::info; use entity::gateway::postgres::PostgresGateway; use elseware::ship::ship::ShipServerStateBuilder; use networking::interserver::AuthToken; -use drops::StandardDropTable; -use maps::maps::generate_free_roam_maps; fn main() { let colors = fern::colors::ColoredLevelConfig::new() From 15c0ac50ee4871d2c366bba2b3aca421b011d315 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 23:03:44 -0700 Subject: [PATCH 25/29] add nullable item shops for faster test runtimes --- shops/Cargo.toml | 4 ++ shops/src/lib.rs | 80 ++++++++++++++++++++++- src/ship/packet/handler/direct_message.rs | 32 +++------ src/ship/ship.rs | 46 ++++--------- tests/common.rs | 20 ++++++ tests/test_bank.rs | 5 +- tests/test_shops.rs | 49 ++++++++++---- 7 files changed, 164 insertions(+), 72 deletions(-) diff --git a/shops/Cargo.toml b/shops/Cargo.toml index 495bf2f..25e3055 100644 --- a/shops/Cargo.toml +++ b/shops/Cargo.toml @@ -8,6 +8,10 @@ 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/shops/src/lib.rs b/shops/src/lib.rs index 7a999b7..94abdec 100644 --- a/shops/src/lib.rs +++ b/shops/src/lib.rs @@ -2,7 +2,16 @@ 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; @@ -10,12 +19,77 @@ pub trait ShopItem { 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 } -pub use weapon::{WeaponShop, WeaponShopItem}; -pub use tool::{ToolShop, ToolShopItem}; -pub use armor::{ArmorShop, ArmorShopItem}; diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 090d77d..c93ae0d 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -1,11 +1,12 @@ use log::warn; +use async_std::sync::Arc; use rand::Rng; use rand::seq::SliceRandom; use libpso::packet::ship::*; use libpso::packet::messages::*; use stats::leveltable::LEVEL_TABLE; use networking::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemShops}; +use crate::ship::ship::{SendShipPacket, ShipError, Clients}; use location::ClientLocation; use drops::ItemDrop; use room::Rooms; @@ -14,7 +15,7 @@ use entity::gateway::EntityGateway; use entity::item; use libpso::utf8_to_utf16_array; use pktbuilder as builder; -use shops::{ShopItem, ToolShopItem, ArmorShopItem}; +use shops::{ItemShops, ShopItem, ToolShopItem, ArmorShopItem}; use items::state::{ItemState, ItemStateError}; use items::floor::{FloorType, FloorItemDetail}; use items::actions::TriggerCreateItem; @@ -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)) }, _ => { diff --git a/src/ship/ship.rs b/src/ship/ship.rs index c920376..85ca6e5 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -1,9 +1,8 @@ #![allow(dead_code, unused_must_use)] 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; @@ -32,7 +31,7 @@ use maps::Holiday; use maps::area::MapAreaError; use maps::maps::{Maps, MapsError, generate_free_roam_maps}; use crate::ship::packet::handler; -use shops::{WeaponShop, ToolShop, ArmorShop}; +use shops::{ItemShops, StandardItemShops}; use trade::TradeState; use crate::ship::chatcommand; use pktbuilder::quest::{QUEST_CATEGORY_MENU_ID, QUEST_SELECT_MENU_ID}; @@ -294,34 +293,6 @@ impl SendServerPacket for SendShipPacket { } } -#[derive(Clone)] -pub struct ItemShops { - pub weapon_shop: HashMap<(Difficulty, SectionID), Arc>>>, - pub tool_shop: Arc>>, - pub armor_shop: Arc>>, -} - -impl Default for ItemShops { - fn default() -> ItemShops { - 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)))); - } - } - - ItemShops { - weapon_shop, - tool_shop: Arc::new(Mutex::new(ToolShop::default())), - armor_shop: Arc::new(Mutex::new(ArmorShop::default())), - } - } -} - pub struct ShipServerStateBuilder { entity_gateway: Option, @@ -330,6 +301,7 @@ pub struct ShipServerStateBuilder { port: Option, auth_token: Option, event: Option, + shops: Option>, map_builder: Option Maps + Send + Sync>>, drop_table_builder: Option Box + Send + Sync>>, standard_quest_builder: Option Result + Send + Sync>>, @@ -346,6 +318,7 @@ impl Default for ShipServerStateBuilder port: None, auth_token: None, event: None, + shops: None, map_builder: None, drop_table_builder: None, standard_quest_builder: None, @@ -416,6 +389,12 @@ impl ShipServerStateBuilder { 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; @@ -431,7 +410,8 @@ 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(), + #[allow(clippy::box_default)] // this lint leads to another which just doesn't work + shops: Arc::new(self.shops.unwrap_or(Box::new(StandardItemShops::default()))), blocks: Blocks(blocks), event: self.event.unwrap_or(Holiday::None), map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(generate_free_roam_maps))), @@ -474,7 +454,7 @@ pub struct ShipServerState { pub clients: Clients, name: String, pub(crate) item_state: items::state::ItemState, - shops: ItemShops, + shops: Arc>, pub blocks: Blocks, event: Holiday, diff --git a/tests/common.rs b/tests/common.rs index f28d318..f446d37 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -13,6 +13,7 @@ use maps::object::MapObject; use maps::monster::MonsterType; use quests::{QuestList, QuestLoadError}; use drops::{DropTable, ItemDropType}; +use shops::{ItemShops, WeaponShopItem, ToolShopItem, ArmorShopItem}; use entity::item; @@ -35,6 +36,23 @@ impl DropTable for 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 null_drop_table_builder(_episode: Episode, _difficult: Difficulty, _section_id: SectionID) -> Box { Box::new(NullDropTable) } @@ -46,6 +64,7 @@ pub fn standard_ship_buildable(gateway: EG) -> ShipS .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 { @@ -55,6 +74,7 @@ pub fn standard_ship(gateway: EG) -> ShipServerState .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() } diff --git a/tests/test_bank.rs b/tests/test_bank.rs index 2a97d6b..07a6ee8 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -3,6 +3,7 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use shops::StandardItemShops; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -1538,7 +1539,9 @@ async fn test_withdraw_meseta_and_buy_a_few_monomates_with_it() { 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 = standard_ship(entity_gateway.clone()); + 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; diff --git a/tests/test_shops.rs b/tests/test_shops.rs index 392fa5a..00d8f5c 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -4,6 +4,7 @@ use entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; use maps::room::Difficulty; use items::state::ItemStateError; +use shops::StandardItemShops; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -20,7 +21,9 @@ async fn test_player_opens_weapon_shop() { char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -48,7 +51,9 @@ async fn test_player_opens_tool_shop() { char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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,7 +81,9 @@ async fn test_player_opens_armor_shop() { char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -105,7 +112,9 @@ async fn test_player_buys_from_weapon_shop() { entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -141,7 +150,9 @@ async fn test_player_buys_from_tool_shop() { entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -176,7 +187,9 @@ async fn test_player_buys_multiple_from_tool_shop() { entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -215,7 +228,9 @@ async fn test_player_buys_from_armor_shop() { entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -293,7 +308,9 @@ async fn test_other_clients_see_purchase() { entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -342,7 +359,9 @@ async fn test_other_clients_see_stacked_purchase() { ), }).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -415,7 +434,9 @@ async fn test_player_double_buys_from_tool_shop() { entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -478,7 +499,9 @@ async fn test_techs_disappear_from_shop_when_bought() { entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; @@ -538,7 +561,9 @@ async fn test_units_disappear_from_shop_when_bought() { entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = standard_ship(entity_gateway.clone()); + 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; From ab0a844c8c20666310df9e1d1ec1ca35d924855a Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 23:11:58 -0700 Subject: [PATCH 26/29] don't load shops for real this time --- src/ship/ship.rs | 11 +++++------ tests/common.rs | 12 +++++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 85ca6e5..5eacf5c 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -410,14 +410,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), - #[allow(clippy::box_default)] // this lint leads to another which just doesn't work - shops: Arc::new(self.shops.unwrap_or(Box::new(StandardItemShops::default()))), + shops: Arc::new(self.shops.unwrap_or_else(|| Box::::default())), blocks: Blocks(blocks), event: self.event.unwrap_or(Holiday::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(StandardDropTable::new))), - standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or(Box::new(load_standard_quests))), - government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or(Box::new(load_government_quests))), + 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())), diff --git a/tests/common.rs b/tests/common.rs index f446d37..36c0d7a 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -36,10 +36,14 @@ impl DropTable for NullDropTable { } } +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 { +impl ItemShops for NullItemShops { async fn generate_weapon_list(&self, _difficulty: Difficulty, _section_id: SectionID, _char_level: usize) -> Option> { Some(Vec::new()) } @@ -51,12 +55,6 @@ impl ItemShops for NullItemShops { } } - - -pub fn null_drop_table_builder(_episode: Episode, _difficult: Difficulty, _section_id: SectionID) -> Box { - Box::new(NullDropTable) -} - pub fn standard_ship_buildable(gateway: EG) -> ShipServerStateBuilder { ShipServerState::builder() .gateway(gateway) From 8360e0343eff27035b7899a75ecca0e120a1c8d6 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 11 Nov 2023 23:28:02 -0700 Subject: [PATCH 27/29] try removing incremental build files to see if it helps ci disk usage --- .drone.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index c57acb0..e6c144b 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,11 +1,14 @@ --- 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 From 2cede0077a0430434217a4ccb054991fcb6aa06a Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 12 Nov 2023 00:08:38 -0700 Subject: [PATCH 28/29] try using cargo-prune instead of cargo-sweep --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index e6c144b..49ef008 100644 --- a/.drone.yml +++ b/.drone.yml @@ -18,7 +18,7 @@ steps: - name: target-cache path: /drone/src/target commands: - - cargo sweep --maxsize 12GiB + - cargo prune - name: build image: rustlang/rust:nightly volumes: From 5fc23cd7cafd05101ad5f82dcfd5a832177fb300 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 12 Nov 2023 00:25:00 -0700 Subject: [PATCH 29/29] fix a few warnings in tests --- tests/common.rs | 2 +- tests/test_bank.rs | 2 +- tests/test_character.rs | 6 +++--- tests/test_exp_gain.rs | 2 +- tests/test_item_actions.rs | 2 +- tests/test_item_drop.rs | 2 +- tests/test_item_id.rs | 2 +- tests/test_item_pickup.rs | 2 +- tests/test_item_use.rs | 2 +- tests/test_mags.rs | 2 +- tests/test_rooms.rs | 3 +-- tests/test_shops.rs | 2 +- tests/test_trade.rs | 2 +- 13 files changed, 15 insertions(+), 16 deletions(-) diff --git a/tests/common.rs b/tests/common.rs index 36c0d7a..db91ab8 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -77,7 +77,7 @@ pub fn standard_ship(gateway: EG) -> ShipServerState } //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, _kb_conf_preset: usize) -> (UserAccountEntity, CharacterEntity) { let new_user = NewUserAccountEntity { email: format!("{}@pso.com", username), username: username.into(), diff --git a/tests/test_bank.rs b/tests/test_bank.rs index 07a6ee8..443da34 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -2,7 +2,7 @@ use std::collections::BTreeSet; use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use elseware::ship::ship::{RecvShipPacket, SendShipPacket}; use shops::StandardItemShops; use libpso::packet::ship::*; diff --git a/tests/test_character.rs b/tests/test_character.rs index ee78434..0c8cecf 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -1,8 +1,8 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use elseware::ship::ship::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"] @@ -33,7 +33,7 @@ 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", 2).await; let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 5e4bcf9..ae49fce 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -1,7 +1,7 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use stats::leveltable::CharacterLevelTable; -use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; +use elseware::ship::ship::{SendShipPacket, RecvShipPacket}; use maps::variant::{MapVariant, MapVariantMode}; use maps::maps::Maps; use maps::area::MapArea; diff --git a/tests/test_item_actions.rs b/tests/test_item_actions.rs index 0212d08..758aa10 100644 --- a/tests/test_item_actions.rs +++ b/tests/test_item_actions.rs @@ -1,6 +1,6 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use elseware::ship::ship::RecvShipPacket; use entity::item; use libpso::packet::ship::*; diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs index bac45ac..0c700bb 100644 --- a/tests/test_item_drop.rs +++ b/tests/test_item_drop.rs @@ -1,6 +1,6 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::InMemoryGateway; -use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; +use elseware::ship::ship::{SendShipPacket, RecvShipPacket}; use maps::monster::MonsterType; use drops::{StandardDropTable, MonsterDropStats, MonsterDropType}; use drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; diff --git a/tests/test_item_id.rs b/tests/test_item_id.rs index ff8f4ad..ad2f860 100644 --- a/tests/test_item_id.rs +++ b/tests/test_item_id.rs @@ -1,7 +1,7 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use elseware::ship::ship::RecvShipPacket; use libpso::packet::ship::*; use libpso::packet::messages::*; diff --git a/tests/test_item_pickup.rs b/tests/test_item_pickup.rs index d1ba62e..3ec0b9c 100644 --- a/tests/test_item_pickup.rs +++ b/tests/test_item_pickup.rs @@ -1,7 +1,7 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use elseware::ship::ship::RecvShipPacket; use libpso::packet::ship::*; use libpso::packet::messages::*; diff --git a/tests/test_item_use.rs b/tests/test_item_use.rs index 0f28a18..13f2310 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -1,7 +1,7 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use elseware::ship::ship::RecvShipPacket; use entity::character::TechLevel; use libpso::packet::ship::*; diff --git a/tests/test_mags.rs b/tests/test_mags.rs index 963e71a..dac0e06 100644 --- a/tests/test_mags.rs +++ b/tests/test_mags.rs @@ -1,7 +1,7 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use elseware::ship::ship::RecvShipPacket; use entity::character::{CharacterClass, SectionID}; use libpso::packet::ship::*; diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index ced3e27..447ea7b 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -1,6 +1,6 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use elseware::ship::ship::{RecvShipPacket, SendShipPacket}; use libpso::packet::ship::*; //use libpso::packet::messages::*; @@ -16,7 +16,6 @@ async fn test_set_valid_quest_group() { let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).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; diff --git a/tests/test_shops.rs b/tests/test_shops.rs index 00d8f5c..cfcb749 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -1,7 +1,7 @@ use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use elseware::ship::ship::{RecvShipPacket, SendShipPacket}; use maps::room::Difficulty; use items::state::ItemStateError; use shops::StandardItemShops; diff --git a/tests/test_trade.rs b/tests/test_trade.rs index ec4fb3c..4a08d0a 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -2,7 +2,7 @@ use std::convert::TryInto; use networking::serverstate::{ClientId, ServerState}; use entity::gateway::{EntityGateway, InMemoryGateway}; use entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; +use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; use entity::item::{Meseta, ItemEntity, InventoryItemEntity}; use elseware::ship::packet::handler::trade::TradeError;