Compare commits

..

No commits in common. "dfd48e1496ccd9729b8e4df3ee183c9d6211d261" and "db66019f2c59c7f006e2d3b23b95b913aa76b555" have entirely different histories.

19 changed files with 392 additions and 861 deletions

View File

@ -191,6 +191,7 @@ where
C: PSOCipher, C: PSOCipher,
{ {
let buf = pkt.as_bytes(); let buf = pkt.as_bytes();
trace!("[send buf] {:?}", buf);
let cbuf = cipher.encrypt(&buf)?; let cbuf = cipher.encrypt(&buf)?;
socket.write_all(&cbuf).await?; socket.write_all(&cbuf).await?;
Ok(()) Ok(())

View File

@ -19,12 +19,15 @@ pub enum GatewayError {
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait EntityGateway: Send + Sync { pub trait EntityGateway: Send + Sync {
type Transaction: EntityGatewayTransaction + Clone; async fn transaction<'a>(&'a mut self) -> Result<Box<dyn EntityGatewayTransaction + 'a>, GatewayError>
{
unimplemented!();
}
async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, _func: F) -> Result<R, E> async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, _func: F) -> Result<R, E>
where where
Fut: Future<Output = Result<(Self::Transaction, R), E>> + Send + 'a, Fut: Future<Output = Result<(Box<dyn EntityGatewayTransaction + 'a>, R), E>> + Send + 'a,
F: FnOnce(Self::Transaction) -> Fut + Send, F: FnOnce(Box<dyn EntityGatewayTransaction + 'a>) -> Fut + Send,
R: Send, R: Send,
E: From<GatewayError>, E: From<GatewayError>,
Self: Sized Self: Sized
@ -152,14 +155,12 @@ pub trait EntityGateway: Send + Sync {
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait EntityGatewayTransaction: Send + Sync + Sized { pub trait EntityGatewayTransaction: Send + Sync {
type ParentGateway: EntityGateway + Clone; fn gateway(&mut self) -> &mut dyn EntityGateway {
fn gateway(&mut self) -> &mut Self::ParentGateway {
unimplemented!() unimplemented!()
} }
async fn commit(self) -> Result<(), GatewayError> { async fn commit(self: Box<Self>) -> Result<(), GatewayError> {
unimplemented!() unimplemented!()
} }
} }

View File

@ -9,10 +9,10 @@ use crate::entity::item::*;
use async_std::sync::{Arc, Mutex}; use async_std::sync::{Arc, Mutex};
#[derive(Clone)] // TODO: implement multiple banks
pub struct InMemoryGatewayTransaction { pub struct InMemoryGatewayTransaction<'a> {
working_gateway: InMemoryGateway, working_gateway: InMemoryGateway,
original_gateway: InMemoryGateway, original_gateway: &'a mut InMemoryGateway,
} }
@ -30,9 +30,7 @@ where
// functions here have been skipped as they are not used in transactions, add as needed // functions here have been skipped as they are not used in transactions, add as needed
#[async_trait::async_trait] #[async_trait::async_trait]
impl EntityGateway for InMemoryGatewayTransaction { impl<'a> EntityGateway for InMemoryGatewayTransaction<'a> {
type Transaction = InMemoryGatewayTransaction;
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> { async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
self.working_gateway.create_user(user).await self.working_gateway.create_user(user).await
} }
@ -184,14 +182,12 @@ impl EntityGateway for InMemoryGatewayTransaction {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl EntityGatewayTransaction for InMemoryGatewayTransaction { impl<'a> EntityGatewayTransaction for InMemoryGatewayTransaction<'a> {
type ParentGateway = InMemoryGatewayTransaction; fn gateway(&mut self) -> &mut dyn EntityGateway {
fn gateway(&mut self) -> &mut Self::ParentGateway {
self self
} }
async fn commit(mut self) -> Result<(), GatewayError> { async fn commit(mut self: Box<Self>) -> Result<(), GatewayError> {
self.original_gateway.users.lock().await.extend(self.working_gateway.users.lock().await.clone()); self.original_gateway.users.lock().await.extend(self.working_gateway.users.lock().await.clone());
self.original_gateway.user_settings.lock().await.extend(self.working_gateway.user_settings.lock().await.clone()); self.original_gateway.user_settings.lock().await.extend(self.working_gateway.user_settings.lock().await.clone());
self.original_gateway.characters.lock().await.extend(self.working_gateway.characters.lock().await.clone()); self.original_gateway.characters.lock().await.extend(self.working_gateway.characters.lock().await.clone());
@ -302,12 +298,49 @@ fn apply_modifiers(items: &BTreeMap<ItemEntityId, ItemEntity>,
#[async_trait::async_trait] #[async_trait::async_trait]
impl EntityGateway for InMemoryGateway { impl EntityGateway for InMemoryGateway {
type Transaction = InMemoryGatewayTransaction; async fn transaction<'a>(&'a mut self) -> Result<Box<dyn EntityGatewayTransaction + 'a>, GatewayError>
{
let working_gateway = {
let users = self.users.lock().await.clone();
let user_settings = self.user_settings.lock().await.clone();
let characters = self.characters.lock().await.clone();
let character_meseta = self.character_meseta.lock().await.clone();
let bank_meseta = self.bank_meseta.lock().await.clone();
let items = self.items.lock().await.clone();
let inventories = self.inventories.lock().await.clone();
let banks = self.banks.lock().await.clone();
let equips = self.equips.lock().await.clone();
let mag_modifiers = self.mag_modifiers.lock().await.clone();
let weapon_modifiers = self.weapon_modifiers.lock().await.clone();
let trades = self.trades.lock().await.clone();
InMemoryGateway {
users: Arc::new(Mutex::new(users)),
user_settings: Arc::new(Mutex::new(user_settings)),
characters: Arc::new(Mutex::new(characters)),
character_meseta: Arc::new(Mutex::new(character_meseta)),
bank_meseta: Arc::new(Mutex::new(bank_meseta)),
items: Arc::new(Mutex::new(items)),
inventories: Arc::new(Mutex::new(inventories)),
banks: Arc::new(Mutex::new(banks)),
equips: Arc::new(Mutex::new(equips)),
mag_modifiers: Arc::new(Mutex::new(mag_modifiers)),
weapon_modifiers: Arc::new(Mutex::new(weapon_modifiers)),
trades: Arc::new(Mutex::new(trades)),
}
};
Ok(Box::new(InMemoryGatewayTransaction {
working_gateway,
original_gateway: self,
}))
}
async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, func: F) -> Result<R, E> async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, func: F) -> Result<R, E>
where where
Fut: Future<Output = Result<(Self::Transaction, R), E>> + Send + 'a, Fut: Future<Output = Result<(Box<dyn EntityGatewayTransaction + 'a>, R), E>> + Send + 'a,
F: FnOnce(Self::Transaction) -> Fut + Send, F: FnOnce(Box<dyn EntityGatewayTransaction + 'a>) -> Fut + Send,
R: Send, R: Send,
E: From<GatewayError>, E: From<GatewayError>,
{ {
@ -339,10 +372,10 @@ impl EntityGateway for InMemoryGateway {
trades: Arc::new(Mutex::new(trades)), trades: Arc::new(Mutex::new(trades)),
}; };
let transaction = InMemoryGatewayTransaction { let transaction = Box::new(InMemoryGatewayTransaction {
working_gateway, working_gateway,
original_gateway: self.clone(), original_gateway: self,
}; });
let (transaction, result) = func(transaction).await?; let (transaction, result) = func(transaction).await?;

View File

@ -4,7 +4,6 @@
use std::convert::{From, TryFrom, Into}; use std::convert::{From, TryFrom, Into};
use futures::{Future, TryStreamExt}; use futures::{Future, TryStreamExt};
use async_std::stream::StreamExt; use async_std::stream::StreamExt;
use async_std::sync::{Arc, Mutex};
use libpso::character::guildcard; use libpso::character::guildcard;
use crate::entity::account::*; use crate::entity::account::*;
use crate::entity::character::*; use crate::entity::character::*;
@ -22,41 +21,31 @@ mod embedded {
} }
#[derive(Clone)]
pub struct PostgresTransaction<'t> { pub struct PostgresTransaction<'t> {
pgtransaction: Arc<Mutex<sqlx::Transaction<'t, sqlx::Postgres>>>, pgtransaction: sqlx::Transaction<'t, sqlx::Postgres>,
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl<'t> EntityGatewayTransaction for PostgresTransaction<'t> { impl<'t> EntityGatewayTransaction for PostgresTransaction<'t> {
type ParentGateway = PostgresTransaction<'t>; fn gateway(&mut self) -> &mut dyn EntityGateway {
fn gateway(&mut self) -> &mut Self::ParentGateway {
self self
} }
//async fn commit(self: Box<Self>) -> Result<(), GatewayError> { async fn commit(self: Box<Self>) -> Result<(), GatewayError> {
async fn commit(self) -> Result<(), GatewayError> { self.pgtransaction.commit().await?;
//self.pgtransaction.lock().await.commit().await?;
Arc::try_unwrap(self.pgtransaction)
.unwrap()
.into_inner()
.commit()
.await?;
Ok(()) Ok(())
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub struct PostgresGateway<'t> { pub struct PostgresGateway {
pool: sqlx::Pool<sqlx::Postgres>, pool: sqlx::Pool<sqlx::Postgres>,
_t: std::marker::PhantomData<&'t ()>,
} }
impl<'t> PostgresGateway<'t> { impl PostgresGateway {
pub fn new(host: &str, dbname: &str, username: &str, password: &str) -> PostgresGateway<'t> { pub fn new(host: &str, dbname: &str, username: &str, password: &str) -> PostgresGateway {
let mut conn = refinery::config::Config::new(refinery::config::ConfigDbType::Postgres) let mut conn = refinery::config::Config::new(refinery::config::ConfigDbType::Postgres)
.set_db_host(host) .set_db_host(host)
.set_db_user(username) .set_db_user(username)
@ -72,7 +61,6 @@ impl<'t> PostgresGateway<'t> {
PostgresGateway { PostgresGateway {
pool, pool,
_t: Default::default(),
} }
} }
} }
@ -593,19 +581,24 @@ async fn set_character_playtime(conn: &mut sqlx::PgConnection, char_id: &Charact
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl<'t> EntityGateway for PostgresGateway<'t> { impl EntityGateway for PostgresGateway {
type Transaction = PostgresTransaction<'t>; async fn transaction<'a>(&'a mut self) -> Result<Box<dyn EntityGatewayTransaction + 'a>, GatewayError>
{
Ok(Box::new(PostgresTransaction {
pgtransaction: self.pool.begin().await?,
}))
}
async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, func: F) -> Result<R, E> async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, func: F) -> Result<R, E>
where where
Fut: Future<Output = Result<(Self::Transaction, R), E>> + Send + 'a, Fut: Future<Output = Result<(Box<dyn EntityGatewayTransaction + 'a>, R), E>> + Send + 'a,
F: FnOnce(Self::Transaction) -> Fut + Send, F: FnOnce(Box<dyn EntityGatewayTransaction + 'a>) -> Fut + Send,
R: Send, R: Send,
E: From<GatewayError>, E: From<GatewayError>,
{ {
let transaction = PostgresTransaction { let transaction = Box::new(PostgresTransaction {
pgtransaction: Arc::new(Mutex::new(self.pool.begin().await.map_err(|_| ()).unwrap())) pgtransaction: self.pool.begin().await.map_err(|_| ()).unwrap()
}; });
let (transaction, result) = func(transaction).await.map_err(|_| ()).unwrap(); let (transaction, result) = func(transaction).await.map_err(|_| ()).unwrap();
transaction.commit().await.map_err(|_| ()).unwrap(); transaction.commit().await.map_err(|_| ()).unwrap();
Ok(result) Ok(result)
@ -735,46 +728,44 @@ impl<'t> EntityGateway for PostgresGateway<'t> {
#[async_trait::async_trait] #[async_trait::async_trait]
impl<'c> EntityGateway for PostgresTransaction<'c> { impl<'c> EntityGateway for PostgresTransaction<'c> {
type Transaction = PostgresTransaction<'c>;
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> { async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
create_user(&mut *self.pgtransaction.lock().await, user).await create_user(&mut *self.pgtransaction, user).await
} }
async fn get_user_by_id(&mut self, id: UserAccountId) -> Result<UserAccountEntity, GatewayError> { async fn get_user_by_id(&mut self, id: UserAccountId) -> Result<UserAccountEntity, GatewayError> {
get_user_by_id(&mut *self.pgtransaction.lock().await, id).await get_user_by_id(&mut *self.pgtransaction, id).await
} }
async fn get_user_by_name(&mut self, username: String) -> Result<UserAccountEntity, GatewayError> { async fn get_user_by_name(&mut self, username: String) -> Result<UserAccountEntity, GatewayError> {
get_user_by_name(&mut *self.pgtransaction.lock().await, username).await get_user_by_name(&mut *self.pgtransaction, username).await
} }
async fn save_user(&mut self, user: &UserAccountEntity) -> Result<(), GatewayError> { async fn save_user(&mut self, user: &UserAccountEntity) -> Result<(), GatewayError> {
save_user(&mut *self.pgtransaction.lock().await, user).await save_user(&mut *self.pgtransaction, user).await
} }
async fn create_user_settings(&mut self, settings: NewUserSettingsEntity) -> Result<UserSettingsEntity, GatewayError> { async fn create_user_settings(&mut self, settings: NewUserSettingsEntity) -> Result<UserSettingsEntity, GatewayError> {
create_user_settings(&mut *self.pgtransaction.lock().await, settings).await create_user_settings(&mut *self.pgtransaction, settings).await
} }
async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result<UserSettingsEntity, GatewayError> { async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result<UserSettingsEntity, GatewayError> {
get_user_settings_by_user(&mut *self.pgtransaction.lock().await, user).await get_user_settings_by_user(&mut *self.pgtransaction, user).await
} }
async fn save_user_settings(&mut self, settings: &UserSettingsEntity) -> Result<(), GatewayError> { async fn save_user_settings(&mut self, settings: &UserSettingsEntity) -> Result<(), GatewayError> {
save_user_settings(&mut *self.pgtransaction.lock().await, settings).await save_user_settings(&mut *self.pgtransaction, settings).await
} }
async fn create_character(&mut self, char: NewCharacterEntity) -> Result<CharacterEntity, GatewayError> { async fn create_character(&mut self, char: NewCharacterEntity) -> Result<CharacterEntity, GatewayError> {
create_character(&mut *self.pgtransaction.lock().await, char).await create_character(&mut *self.pgtransaction, char).await
} }
async fn get_characters_by_user(&mut self, user: &UserAccountEntity) -> Result<[Option<CharacterEntity>; 4], GatewayError> { async fn get_characters_by_user(&mut self, user: &UserAccountEntity) -> Result<[Option<CharacterEntity>; 4], GatewayError> {
get_characters_by_user(&mut *self.pgtransaction.lock().await, user).await get_characters_by_user(&mut *self.pgtransaction, user).await
} }
async fn save_character(&mut self, char: &CharacterEntity) -> Result<(), GatewayError> { async fn save_character(&mut self, char: &CharacterEntity) -> Result<(), GatewayError> {
save_character(&mut *self.pgtransaction.lock().await, char).await save_character(&mut *self.pgtransaction, char).await
} }
async fn get_guild_card_data_by_user(&mut self, user: &UserAccountEntity) -> Result<GuildCardDataEntity, GatewayError> { async fn get_guild_card_data_by_user(&mut self, user: &UserAccountEntity) -> Result<GuildCardDataEntity, GatewayError> {
@ -786,75 +777,75 @@ impl<'c> EntityGateway for PostgresTransaction<'c> {
} }
async fn create_item(&mut self, item: NewItemEntity) -> Result<ItemEntity, GatewayError> { async fn create_item(&mut self, item: NewItemEntity) -> Result<ItemEntity, GatewayError> {
create_item(&mut *self.pgtransaction.lock().await, item).await create_item(&mut *self.pgtransaction, item).await
} }
async fn add_item_note(&mut self, item_id: &ItemEntityId, item_note: ItemNote) -> Result<(), GatewayError> { async fn add_item_note(&mut self, item_id: &ItemEntityId, item_note: ItemNote) -> Result<(), GatewayError> {
add_item_note(&mut *self.pgtransaction.lock().await, item_id, item_note).await add_item_note(&mut *self.pgtransaction, item_id, item_note).await
} }
async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> { async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> {
feed_mag(&mut *self.pgtransaction.lock().await, mag_item_id, tool_item_id).await feed_mag(&mut *self.pgtransaction, mag_item_id, tool_item_id).await
} }
async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> { async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> {
change_mag_owner(&mut *self.pgtransaction.lock().await, mag_item_id, character).await change_mag_owner(&mut *self.pgtransaction, mag_item_id, character).await
} }
async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> { async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> {
use_mag_cell(&mut *self.pgtransaction.lock().await, mag_item_id, mag_cell_id).await use_mag_cell(&mut *self.pgtransaction, mag_item_id, mag_cell_id).await
} }
async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> { async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> {
add_weapon_modifier(&mut *self.pgtransaction.lock().await, item_id, modifier).await add_weapon_modifier(&mut *self.pgtransaction, item_id, modifier).await
} }
async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result<InventoryEntity, GatewayError> { async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result<InventoryEntity, GatewayError> {
get_character_inventory(&mut *self.pgtransaction.lock().await, char_id).await get_character_inventory(&mut *self.pgtransaction, char_id).await
} }
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_name: &BankName) -> Result<BankEntity, GatewayError> { async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_name: &BankName) -> Result<BankEntity, GatewayError> {
get_character_bank(&mut *self.pgtransaction.lock().await, char_id, bank_name).await get_character_bank(&mut *self.pgtransaction, char_id, bank_name).await
} }
async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> { async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> {
set_character_inventory(&mut *self.pgtransaction.lock().await, char_id, inventory).await set_character_inventory(&mut *self.pgtransaction, char_id, inventory).await
} }
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: &BankName) -> Result<(), GatewayError> { async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: &BankName) -> Result<(), GatewayError> {
set_character_bank(&mut *self.pgtransaction.lock().await, char_id, bank, bank_name).await set_character_bank(&mut *self.pgtransaction, char_id, bank, bank_name).await
} }
async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError> { async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError> {
get_character_equips(&mut *self.pgtransaction.lock().await, char_id).await get_character_equips(&mut *self.pgtransaction, char_id).await
} }
async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equips: &EquippedEntity) -> Result<(), GatewayError> { async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equips: &EquippedEntity) -> Result<(), GatewayError> {
set_character_equips(&mut *self.pgtransaction.lock().await, char_id, equips).await set_character_equips(&mut *self.pgtransaction, char_id, equips).await
} }
async fn set_character_meseta(&mut self, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError> { async fn set_character_meseta(&mut self, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError> {
set_character_meseta(&mut *self.pgtransaction.lock().await, char_id, meseta).await set_character_meseta(&mut *self.pgtransaction, char_id, meseta).await
} }
async fn get_character_meseta(&mut self, char_id: &CharacterEntityId) -> Result<Meseta, GatewayError> { async fn get_character_meseta(&mut self, char_id: &CharacterEntityId) -> Result<Meseta, GatewayError> {
get_character_meseta(&mut *self.pgtransaction.lock().await, char_id).await get_character_meseta(&mut *self.pgtransaction, char_id).await
} }
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> { async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> {
set_bank_meseta(&mut *self.pgtransaction.lock().await, char_id, bank, meseta).await set_bank_meseta(&mut *self.pgtransaction, char_id, bank, meseta).await
} }
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result<Meseta, GatewayError> { async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result<Meseta, GatewayError> {
get_bank_meseta(&mut *self.pgtransaction.lock().await, char_id, bank).await get_bank_meseta(&mut *self.pgtransaction, char_id, bank).await
} }
async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> { async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> {
create_trade(&mut *self.pgtransaction.lock().await, char_id1, char_id2).await create_trade(&mut *self.pgtransaction, char_id1, char_id2).await
} }
async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> {
set_character_playtime(&mut *self.pgtransaction.lock().await, char_id, playtime).await set_character_playtime(&mut *self.pgtransaction, char_id, playtime).await
} }
} }

View File

@ -241,13 +241,6 @@ impl InventoryItemEntity {
_ => None, _ => None,
} }
} }
pub fn stacked(&self) -> Option<&Vec<ItemEntity>> {
match self {
InventoryItemEntity::Stacked(i) => Some(i),
_ => None,
}
}
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]

View File

@ -212,43 +212,7 @@ impl ToolType {
ToolType::Addslot | ToolType::Addslot |
ToolType::PhotonDrop | ToolType::PhotonDrop |
ToolType::PhotonSphere | ToolType::PhotonSphere |
ToolType::PhotonCrystal | ToolType::PhotonCrystal)
ToolType::JackOLantern |
ToolType::ChristmasPresent |
ToolType::EasterEgg |
ToolType::CellOfMag502 |
ToolType::CellOfMag213 |
ToolType::PartsOfRobochao |
ToolType::HeartOfOpaOpa |
ToolType::HeartOfPian |
ToolType::HeartOfChao |
ToolType::HeartOfChuChu |
ToolType::HeartOfAngel |
ToolType::HeartOfDevil |
ToolType::KitOfHamburger |
ToolType::PanthersSpirit |
ToolType::KitOfMark3 |
ToolType::KitOfMasterSystem |
ToolType::KitOfGenesis |
ToolType::KitOfSegaSaturn |
ToolType::KitOfDreamcast |
ToolType::HeartOfKapuKapu |
ToolType::Tablet |
ToolType::DragonScale |
ToolType::HeavenStrikerCoat |
ToolType::PioneerParts |
ToolType::AmitiesMemo |
ToolType::HeartOfMorolian |
ToolType::RappysBeak |
ToolType::YahoosEngine |
ToolType::DPhotonCore |
ToolType::LibertaKit |
ToolType::CellOfMag0503 |
ToolType::CellOfMag0504 |
ToolType::CellOfMag0505 |
ToolType::CellOfMag0506 |
ToolType::CellOfMag0507
)
} }
pub fn max_stack(&self) -> usize { pub fn max_stack(&self) -> usize {
@ -280,41 +244,6 @@ impl ToolType {
ToolType::PhotonDrop => 99, ToolType::PhotonDrop => 99,
ToolType::PhotonSphere => 99, ToolType::PhotonSphere => 99,
ToolType::PhotonCrystal => 99, ToolType::PhotonCrystal => 99,
ToolType::JackOLantern => 99,
ToolType::ChristmasPresent => 99,
ToolType::EasterEgg => 99,
ToolType::CellOfMag502 => 99,
ToolType::CellOfMag213 => 99,
ToolType::PartsOfRobochao => 99,
ToolType::HeartOfOpaOpa => 99,
ToolType::HeartOfPian => 99,
ToolType::HeartOfChao => 99,
ToolType::HeartOfChuChu => 99,
ToolType::HeartOfAngel => 99,
ToolType::HeartOfDevil => 99,
ToolType::KitOfHamburger => 99,
ToolType::PanthersSpirit => 99,
ToolType::KitOfMark3 => 99,
ToolType::KitOfMasterSystem => 99,
ToolType::KitOfGenesis => 99,
ToolType::KitOfSegaSaturn => 99,
ToolType::KitOfDreamcast => 99,
ToolType::HeartOfKapuKapu => 99,
ToolType::Tablet => 99,
ToolType::DragonScale => 99,
ToolType::HeavenStrikerCoat => 99,
ToolType::PioneerParts => 99,
ToolType::AmitiesMemo => 99,
ToolType::HeartOfMorolian => 99,
ToolType::RappysBeak => 99,
ToolType::YahoosEngine => 99,
ToolType::DPhotonCore => 99,
ToolType::LibertaKit => 99,
ToolType::CellOfMag0503 => 99,
ToolType::CellOfMag0504 => 99,
ToolType::CellOfMag0505 => 99,
ToolType::CellOfMag0506 => 99,
ToolType::CellOfMag0507 => 99,
_ => 1, _ => 1,
} }
} }
@ -326,7 +255,6 @@ impl ToolType {
ToolType::HeartOfOpaOpa | ToolType::HeartOfOpaOpa |
ToolType::HeartOfPian | ToolType::HeartOfPian |
ToolType::HeartOfChao | ToolType::HeartOfChao |
ToolType::HeartOfChuChu |
ToolType::HeartOfAngel | ToolType::HeartOfAngel |
ToolType::HeartOfDevil | ToolType::HeartOfDevil |
ToolType::KitOfHamburger | ToolType::KitOfHamburger |
@ -336,7 +264,6 @@ impl ToolType {
ToolType::KitOfGenesis | ToolType::KitOfGenesis |
ToolType::KitOfSegaSaturn | ToolType::KitOfSegaSaturn |
ToolType::KitOfDreamcast | ToolType::KitOfDreamcast |
ToolType::HeartOfKapuKapu |
ToolType::Tablet | ToolType::Tablet |
ToolType::DragonScale | ToolType::DragonScale |
ToolType::HeavenStrikerCoat | ToolType::HeavenStrikerCoat |

View File

@ -838,7 +838,6 @@ mod test {
#[async_trait::async_trait] #[async_trait::async_trait]
impl EntityGateway for TestData { impl EntityGateway for TestData {
type Transaction = ();
async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result<UserSettingsEntity, GatewayError> { async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result<UserSettingsEntity, GatewayError> {
Ok(UserSettingsEntity { Ok(UserSettingsEntity {
id: UserSettingsId(0), id: UserSettingsId(0),
@ -880,9 +879,7 @@ mod test {
async fn test_user_checksum() { async fn test_user_checksum() {
#[derive(Clone)] #[derive(Clone)]
struct TestData; struct TestData;
impl EntityGateway for TestData { impl EntityGateway for TestData {}
type Transaction = ();
}
let mut server = CharacterServerState::new(TestData {}, AuthToken("".into())); let mut server = CharacterServerState::new(TestData {}, AuthToken("".into()));
let send = server.handle(ClientId(1), RecvCharacterPacket::Checksum(Checksum {checksum: 1234, let send = server.handle(ClientId(1), RecvCharacterPacket::Checksum(Checksum {checksum: 1234,
padding: 0, padding: 0,

View File

@ -179,7 +179,7 @@ impl<EG: EntityGateway + Clone> ServerState for LoginServerState<EG> {
mod test { mod test {
use super::*; use super::*;
use crate::entity::account::{UserAccountId}; use crate::entity::account::{UserAccountId};
use crate::entity::gateway::{EntityGatewayTransaction, GatewayError}; use crate::entity::gateway::GatewayError;
const LOGIN_PACKET: RecvLoginPacket = RecvLoginPacket::Login(Login { const LOGIN_PACKET: RecvLoginPacket = RecvLoginPacket::Login(Login {
tag: 65536, tag: 65536,
@ -205,14 +205,6 @@ mod test {
} }
}); });
impl EntityGateway for () {
type Transaction = ();
}
impl EntityGatewayTransaction for () {
type ParentGateway = ();
}
#[async_std::test] #[async_std::test]
async fn test_correct_login() { async fn test_correct_login() {
#[derive(Clone)] #[derive(Clone)]
@ -221,7 +213,6 @@ mod test {
#[async_trait::async_trait] #[async_trait::async_trait]
impl EntityGateway for TestData { impl EntityGateway for TestData {
type Transaction = ();
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> { async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
assert!(name == "testuser"); assert!(name == "testuser");
Ok(UserAccountEntity { Ok(UserAccountEntity {
@ -280,7 +271,6 @@ mod test {
#[async_trait::async_trait] #[async_trait::async_trait]
impl EntityGateway for TestData { impl EntityGateway for TestData {
type Transaction = ();
async fn get_user_by_name(&mut self, _name: String) -> Result<UserAccountEntity, GatewayError> { async fn get_user_by_name(&mut self, _name: String) -> Result<UserAccountEntity, GatewayError> {
Err(GatewayError::Error) Err(GatewayError::Error)
} }
@ -315,7 +305,6 @@ mod test {
#[async_trait::async_trait] #[async_trait::async_trait]
impl EntityGateway for TestData { impl EntityGateway for TestData {
type Transaction = ();
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> { async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
assert!(name == "testuser"); assert!(name == "testuser");
Ok(UserAccountEntity { Ok(UserAccountEntity {
@ -365,7 +354,6 @@ mod test {
#[async_trait::async_trait] #[async_trait::async_trait]
impl EntityGateway for TestData { impl EntityGateway for TestData {
type Transaction = ();
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> { async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
assert!(name == "testuser"); assert!(name == "testuser");
Ok(UserAccountEntity { Ok(UserAccountEntity {

View File

@ -1,46 +1,33 @@
// TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency // TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency
use crate::ship::items::ClientItemId; use crate::ship::items::ClientItemId;
use crate::entity::item::{Meseta, ItemNote}; use crate::entity::item::{Meseta, ItemNote};
use async_std::sync::Arc;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::iter::IntoIterator;
use libpso::packet::{ship::Message, messages::GameMessage};
use crate::ship::map::MapArea; use crate::ship::map::MapArea;
use crate::ship::ship::SendShipPacket;
use crate::entity::character::{CharacterEntity, CharacterEntityId}; use crate::entity::character::{CharacterEntity, CharacterEntityId};
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; use crate::entity::gateway::EntityGatewayTransaction;
use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail};
use crate::ship::items::bank::{BankItem, BankItemDetail}; use crate::ship::items::bank::{BankItem, BankItemDetail};
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
use crate::ship::items::floor::{FloorItem, FloorItemDetail}; use crate::ship::items::floor::{FloorItem, FloorItemDetail};
use crate::ship::items::apply_item::{apply_item, ApplyItemAction}; use crate::ship::items::apply_item::apply_item;
use crate::entity::item::{ItemDetail, NewItemEntity, TradeId}; use crate::entity::item::{ItemDetail, NewItemEntity, TradeId};
use crate::entity::item::tool::Tool; use crate::entity::item::tool::Tool;
use crate::entity::item::ItemModifier; use crate::entity::item::ItemModifier;
use crate::ship::shops::ShopItem; use crate::ship::shops::ShopItem;
use crate::ship::drops::{ItemDrop, ItemDropType}; use crate::ship::drops::{ItemDrop, ItemDropType};
use crate::ship::packet::builder;
use crate::ship::location::AreaClient;
type BoxFuture<T> = Pin<Box<dyn Future<Output=T> + Send>>;
pub enum TriggerCreateItem { pub enum TriggerCreateItem {
Yes, Yes,
No No
} }
pub(super) fn take_item_from_floor<EG, TR>( pub(super) fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
item_id: ClientItemId -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), ItemStateError>>
where
EG: EntityGateway + Send,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction): (ItemStateProxy, TR) , _| { move |(mut item_state, transaction): (ItemStateProxy<'_>, Box<dyn EntityGatewayTransaction + '_>) , _| {
Box::pin(async move { Box::pin(async move {
let mut floor = item_state.floor(&character_id).await?; let mut floor = item_state.floor(&character_id).await?;
let item = floor.take_item(&item_id).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?; let item = floor.take_item(&item_id).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?;
@ -51,13 +38,9 @@ where
} }
} }
pub(super) fn add_floor_item_to_inventory<EG, TR>( pub(super) fn add_floor_item_to_inventory(character: &CharacterEntity)
character: &CharacterEntity -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem)
) -> impl Fn((ItemStateProxy, TR), FloorItem) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), TriggerCreateItem), ItemStateError>> + Send + 'a>>
-> BoxFuture<Result<((ItemStateProxy, TR), TriggerCreateItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + Clone + 'static,
{ {
let character = character.clone(); let character = character.clone();
move |(mut item_state, transaction), floor_item| { move |(mut item_state, transaction), floor_item| {
@ -84,7 +67,7 @@ where
let add_result = inventory.add_floor_item(floor_item)?; let add_result = inventory.add_floor_item(floor_item)?;
transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), Ok(((item_state, transaction),
match add_result { match add_result {
@ -98,15 +81,9 @@ where
pub(super) fn take_item_from_inventory<EG, TR>( pub(super) fn take_item_from_inventory(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
item_id: ClientItemId, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
amount: u32,
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
@ -114,7 +91,7 @@ where
let item = inventory.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?; let item = inventory.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?;
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), item)) Ok(((item_state, transaction), item))
}) })
@ -122,15 +99,9 @@ where
} }
pub(super) fn add_inventory_item_to_shared_floor<EG, TR>( pub(super) fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId, map_area: MapArea, drop_position: (f32, f32, f32))
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
map_area: MapArea, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
drop_position: (f32, f32, f32),
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction), inventory_item| { move |(mut item_state, transaction), inventory_item| {
Box::pin(async move { Box::pin(async move {
@ -156,59 +127,43 @@ where
} }
pub(super) fn take_meseta_from_inventory<EG, TR>( pub(super) fn take_meseta_from_inventory(character_id: CharacterEntityId, amount: u32)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
amount: u32, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
let mut inventory = item_state.inventory(&character_id).await?; let mut inventory = item_state.inventory(&character_id).await?;
inventory.remove_meseta(amount)?; inventory.remove_meseta(amount)?;
transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), ())) Ok(((item_state, transaction), ()))
}) })
} }
} }
pub(super) fn add_meseta_to_inventory<EG, TR>( pub(super) fn add_meseta_to_inventory(character_id: CharacterEntityId, amount: u32)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
amount: u32 -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
let mut inventory = item_state.inventory(&character_id).await?; let mut inventory = item_state.inventory(&character_id).await?;
inventory.add_meseta(amount)?; inventory.add_meseta(amount)?;
transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), ())) Ok(((item_state, transaction), ()))
}) })
} }
} }
pub(super) fn add_meseta_to_shared_floor<EG, TR>( pub(super) fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount: u32, map_area: MapArea, drop_position: (f32, f32))
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
amount: u32, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
map_area: MapArea,
drop_position: (f32, f32)
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction), _| { move |(mut item_state, transaction), _| {
Box::pin(async move { Box::pin(async move {
let floor_item = FloorItem { let floor_item = FloorItem {
@ -229,14 +184,9 @@ where
} }
} }
pub(super) fn take_meseta_from_bank<EG, TR>( pub(super) fn take_meseta_from_bank(character_id: CharacterEntityId, amount: u32)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
amount: u32, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
@ -249,14 +199,9 @@ where
} }
} }
pub(super) fn add_meseta_from_bank_to_inventory<EG, TR>( pub(super) fn add_meseta_from_bank_to_inventory(character_id: CharacterEntityId, amount: u32)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
amount: u32, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
@ -270,14 +215,9 @@ where
} }
pub(super) fn add_meseta_to_bank<EG, TR>( pub(super) fn add_meseta_to_bank(character_id: CharacterEntityId, amount: u32)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
amount: u32, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
@ -291,35 +231,25 @@ where
} }
pub(super) fn take_item_from_bank<EG, TR>( pub(super) fn take_item_from_bank(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
item_id: ClientItemId, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), BankItem), ItemStateError>> + Send + 'a>>
amount: u32,
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), BankItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
let mut bank = item_state.bank(&character_id).await?; let mut bank = item_state.bank(&character_id).await?;
let item = bank.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoBankItem(item_id))?; let item = bank.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoBankItem(item_id))?;
transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?; transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?;
item_state.set_bank(bank).await; item_state.set_bank(bank);
Ok(((item_state, transaction), item)) Ok(((item_state, transaction), item))
}) })
} }
} }
pub(super) fn add_bank_item_to_inventory<EG, TR>( pub(super) fn add_bank_item_to_inventory(character: &CharacterEntity)
character: &CharacterEntity, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), BankItem)
) -> impl Fn((ItemStateProxy, TR), BankItem) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
let character = character.clone(); let character = character.clone();
move |(mut item_state, transaction), bank_item| { move |(mut item_state, transaction), bank_item| {
@ -356,7 +286,7 @@ where
inventory.add_item(inventory_item.clone())?; inventory.add_item(inventory_item.clone())?;
transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), inventory_item)) Ok(((item_state, transaction), inventory_item))
}) })
@ -364,13 +294,9 @@ where
} }
pub(super) fn add_inventory_item_to_bank<EG, TR>( pub(super) fn add_inventory_item_to_bank(character_id: CharacterEntityId)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
) -> impl Fn((ItemStateProxy, TR), InventoryItem) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction), inventory_item| { move |(mut item_state, transaction), inventory_item| {
Box::pin(async move { Box::pin(async move {
@ -389,7 +315,7 @@ where
bank.add_inventory_item(inventory_item)?; bank.add_inventory_item(inventory_item)?;
transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?; transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?;
item_state.set_bank(bank).await; item_state.set_bank(bank);
Ok(((item_state, transaction), ())) Ok(((item_state, transaction), ()))
@ -398,22 +324,16 @@ where
} }
pub(super) fn equip_inventory_item<EG, TR>( pub(super) fn equip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId, equip_slot: u8)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
item_id: ClientItemId, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
equip_slot: u8,
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
let mut inventory = item_state.inventory(&character_id).await?; let mut inventory = item_state.inventory(&character_id).await?;
inventory.equip(&item_id, equip_slot); inventory.equip(&item_id, equip_slot);
transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?; transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), ())) Ok(((item_state, transaction), ()))
}) })
@ -421,21 +341,16 @@ where
} }
pub(super) fn unequip_inventory_item<EG, TR>( pub(super) fn unequip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
item_id: ClientItemId, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
let mut inventory = item_state.inventory(&character_id).await?; let mut inventory = item_state.inventory(&character_id).await?;
inventory.unequip(&item_id); inventory.unequip(&item_id);
transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?; transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), ())) Ok(((item_state, transaction), ()))
}) })
@ -444,14 +359,9 @@ where
pub(super) fn sort_inventory_items<EG, TR>( pub(super) fn sort_inventory_items(character_id: CharacterEntityId, item_ids: Vec<ClientItemId>)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
item_ids: Vec<ClientItemId>, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), ()), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
let item_ids = item_ids.clone(); let item_ids = item_ids.clone();
@ -459,7 +369,7 @@ where
let mut inventory = item_state.inventory(&character_id).await?; let mut inventory = item_state.inventory(&character_id).await?;
inventory.sort(&item_ids); inventory.sort(&item_ids);
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), ())) Ok(((item_state, transaction), ()))
}) })
@ -467,15 +377,10 @@ where
} }
pub(super) fn use_consumed_item<EG, TR>( pub(super) fn use_consumed_item(character: CharacterEntity)
character: &CharacterEntity, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
) -> impl Fn((ItemStateProxy, TR), InventoryItem) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), CharacterEntity), ItemStateError>> + Send + 'a>>
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<ApplyItemAction>), ItemStateError>>
where
EG: EntityGateway + Clone + 'static,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
let character = character.clone();
move |(mut item_state, transaction), inventory_item| { move |(mut item_state, transaction), inventory_item| {
let mut character = character.clone(); let mut character = character.clone();
Box::pin(async move { Box::pin(async move {
@ -485,22 +390,17 @@ where
Ok(transaction) Ok(transaction)
}}).await?; }}).await?;
let apply_item_actions = apply_item(&mut item_state, transaction.gateway(), &mut character, inventory_item).await?; apply_item(&mut item_state, transaction.gateway(), &mut character, inventory_item).await?;
Ok(((item_state, transaction), apply_item_actions)) Ok(((item_state, transaction), character))
}) })
} }
} }
pub(super) fn feed_mag_item<EG, TR>( pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemId)
character: CharacterEntity, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
mag_item_id: ClientItemId, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), CharacterEntity), ItemStateError>> + Send + 'a>>
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
-> BoxFuture<Result<((ItemStateProxy, TR), CharacterEntity), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction), tool| { move |(mut item_state, transaction), tool| {
let character = character.clone(); let character = character.clone();
@ -537,24 +437,20 @@ where
mag_entity.feed(food_tool); mag_entity.feed(food_tool);
transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), character)) Ok(((item_state, transaction), character))
}) })
} }
} }
#[allow(clippy::needless_lifetimes)] // clippy this lifetime is not needless get off my case
pub(super) fn add_bought_item_to_inventory<'a, EG, TR>( pub(super) fn add_bought_item_to_inventory<'a>(character_id: CharacterEntityId,
character_id: CharacterEntityId, shop_item: &'a (dyn ShopItem + Send + Sync),
shop_item: &'a (dyn ShopItem + Send + Sync), item_id: ClientItemId,
item_id: ClientItemId, amount: u32)
amount: u32, -> impl Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
) -> impl Fn((ItemStateProxy, TR), ()) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy, TR), InventoryItem), ItemStateError>> + Send + 'a>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
@ -603,20 +499,16 @@ where
}; };
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), inventory_item)) Ok(((item_state, transaction), inventory_item))
}) })
} }
} }
pub(super) fn sell_inventory_item<EG, TR>( pub(super) fn sell_inventory_item<'a>(character_id: CharacterEntityId)
character_id: CharacterEntityId, -> impl Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
) -> impl Fn((ItemStateProxy, TR), InventoryItem) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction), inventory_item| { move |(mut item_state, transaction), inventory_item| {
Box::pin(async move { Box::pin(async move {
@ -630,7 +522,7 @@ where
Ok(transaction) Ok(transaction)
}}).await?; }}).await?;
transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), inventory_item)) Ok(((item_state, transaction), inventory_item))
}) })
} }
@ -638,22 +530,19 @@ where
#[async_recursion::async_recursion] #[async_recursion::async_recursion]
async fn iterate_inner<'a, EG, TR, I, O, T, F, FR>( async fn iterate_inner<'a, I, O, T, F, FR>(state: (ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>),
state: (ItemStateProxy, TR), mut input: Vec<I>,
mut input: Vec<I>, func: F,
func: F, arg: T)
arg: T, -> Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<O>), ItemStateError>
) -> Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>
where where
'a: 'async_recursion, 'a: 'async_recursion,
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG>,
I: Send, I: Send,
O: Send, O: Send,
T: Clone + Send + Sync, T: Clone + Send + Sync,
F: Fn(I) -> FR + Send + Sync + Clone + 'static, F: Fn(I) -> FR + Send + Sync + Clone + 'static,
FR: Fn((ItemStateProxy, TR), T) FR: Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), T)
-> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), O), ItemStateError>> + Send + 'a>> + Send + Sync,
{ {
let item = match input.pop() { let item = match input.pop() {
Some(item) => item, Some(item) => item,
@ -669,20 +558,18 @@ where
Ok((state, output)) Ok((state, output))
} }
pub(super) fn iterate<EG, TR, I, O, T, F, FR>( pub(super) fn iterate<'k, I, O, T, F, FR>(
input: Vec<I>, input: Vec<I>,
func: F, func: F)
) -> impl Fn((ItemStateProxy, TR), T) -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), T)
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>> -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<O>), ItemStateError>> + Send + 'a>>
where where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
O: Send, O: Send,
I: Send + Clone + 'static + std::fmt::Debug, I: Send + Clone + 'static + std::fmt::Debug,
T: Send + Clone + 'static + std::fmt::Debug, T: Send + Clone + 'static + std::fmt::Debug,
F: Fn(I) -> FR + Send + Sync + Clone + 'static, F: Fn(I) -> FR + Send + Sync + Clone + 'static,
FR: Fn((ItemStateProxy, TR), T) FR: for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), T)
-> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), O), ItemStateError>> + Send + 'a>> + Send + Sync,
T: Clone + Send + Sync, T: Clone + Send + Sync,
{ {
move |(item_state, transaction), arg| { move |(item_state, transaction), arg| {
@ -697,22 +584,19 @@ where
#[async_recursion::async_recursion] #[async_recursion::async_recursion]
async fn foreach_inner<'a, EG, TR, O, T, F, I>( async fn foreach_inner<'a, O, T, F>(state: (ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>),
state: (ItemStateProxy, TR), mut input: Vec<T>,
mut input: I, func: F)
func: Arc<F>, -> Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<O>), ItemStateError>
) -> Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>
where where
'a: 'async_recursion, 'a: 'async_recursion,
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
O: Send, O: Send,
T: Send, T: Clone + Send,
F: Fn((ItemStateProxy, TR), T) F: Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), T)
-> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), O), ItemStateError>> + Send + 'a>> + Send + Sync,
I: Iterator<Item = T> + Send + Sync + 'static, F: Clone,
{ {
let item = match input.next() { let item = match input.pop() {
Some(item) => item, Some(item) => item,
None => return Ok((state, Vec::new())) None => return Ok((state, Vec::new()))
}; };
@ -725,25 +609,19 @@ where
Ok((state, output)) Ok((state, output))
} }
pub(super) fn foreach<EG, TR, O, T, F, I>( pub(super) fn foreach<'k, O, T, F>(func: F)
func: F -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<T>)
) -> impl Fn((ItemStateProxy, TR), I) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<O>), ItemStateError>> + Send + 'a>>
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>>
where where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
O: Send, O: Send,
T: Send + Clone + 'static + std::fmt::Debug, T: Send + Clone + 'static + std::fmt::Debug,
F: Fn((ItemStateProxy, TR), T) F: for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), T)
-> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync + 'static, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), O), ItemStateError>> + Send + 'a>> + Send + Sync + 'static,
T: Send + Sync, F: Clone,
I: IntoIterator<Item = T> + Send + Sync + 'static, T: Clone + Send + Sync,
I::IntoIter: Send + Sync,
{ {
let func = Arc::new(func);
move |(item_state, transaction), items| { move |(item_state, transaction), items| {
let func = func.clone(); let func = func.clone();
let items = items.into_iter();
Box::pin(async move { Box::pin(async move {
let (state, result) = foreach_inner((item_state, transaction), items, func).await?; let (state, result) = foreach_inner((item_state, transaction), items, func).await?;
Ok((state, result)) Ok((state, result))
@ -751,14 +629,9 @@ where
} }
} }
pub(super) fn insert<'a, EG, TR, T>( pub(super) fn insert<'a, T: Send + Clone + 'a>(element: T)
element: T -> impl Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
) -> impl Fn((ItemStateProxy, TR), ()) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), T), ItemStateError>> + Send + 'a>>
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy, TR), T), ItemStateError>> + Send + 'a>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
T: Send + Clone + 'a,
{ {
move |state, _| { move |state, _| {
let element = element.clone(); let element = element.clone();
@ -768,41 +641,9 @@ where
} }
} }
pub(super) fn fork<EG, TR, F1, F2, T, O1, O2>( pub(super) fn add_item_to_inventory(character: CharacterEntity)
func1: F1, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
func2: F2, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>> + Clone
) -> impl Fn((ItemStateProxy, TR), T)
-> BoxFuture<Result<((ItemStateProxy, TR), (O1, O2)), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
F1: Fn((ItemStateProxy, TR), T) -> BoxFuture<Result<((ItemStateProxy, TR), O1), ItemStateError>> + Send + Sync + 'static,
F2: Fn((ItemStateProxy, TR), T) -> BoxFuture<Result<((ItemStateProxy, TR), O2), ItemStateError>> + Send + Sync + 'static,
T: Send + Sync + Clone + 'static,
O1: Send,
O2: Send,
{
let func1 = Arc::new(func1);
let func2 = Arc::new(func2);
move |(item_state, transaction), input| {
let func1 = func1.clone();
let func2 = func2.clone();
Box::pin(async move {
let ((item_state, transaction), result1) = func1((item_state, transaction), input.clone()).await?;
let ((item_state, transaction), result2) = func2((item_state, transaction), input).await?;
Ok(((item_state, transaction), (result1, result2)))
})
}
}
pub(super) fn add_item_to_inventory<EG, TR>(
character: CharacterEntity,
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), ItemStateError>> + Clone
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction), inventory_item| { move |(mut item_state, transaction), inventory_item| {
let character = character.clone(); let character = character.clone();
@ -817,22 +658,16 @@ where
inventory.add_item(inventory_item.clone())?; inventory.add_item(inventory_item.clone())?;
transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(((item_state, transaction), inventory_item)) Ok(((item_state, transaction), inventory_item))
}) })
} }
} }
pub(super) fn record_trade<EG, TR>( pub(super) fn record_trade(trade_id: TradeId, character_to: CharacterEntityId, character_from: CharacterEntityId)
trade_id: TradeId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<InventoryItem>)
character_to: CharacterEntityId, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<InventoryItem>), ItemStateError>> + Send + 'a>> + Clone
character_from: CharacterEntityId,
) -> impl Fn((ItemStateProxy, TR), Vec<InventoryItem>)
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<InventoryItem>), ItemStateError>> + Clone
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(item_state, mut transaction), traded_items| { move |(item_state, mut transaction), traded_items| {
Box::pin(async move { Box::pin(async move {
@ -853,12 +688,9 @@ where
} }
pub(super) fn assign_new_item_id<EG, TR>( pub(super) fn assign_new_item_id()
) -> impl Fn((ItemStateProxy, TR), InventoryItem) -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), ItemStateError>> + Clone -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>> + Clone
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction), mut inventory_item| { move |(mut item_state, transaction), mut inventory_item| {
Box::pin(async move { Box::pin(async move {
@ -869,14 +701,9 @@ where
} }
pub(super) fn convert_item_drop_to_floor_item<EG, TR>( pub(super) fn convert_item_drop_to_floor_item(character_id: CharacterEntityId, item_drop: ItemDrop)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
item_drop: ItemDrop, -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>> + Clone
) -> impl Fn((ItemStateProxy, TR), ())
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), ItemStateError>> + Clone
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
let item_drop = item_drop.clone(); let item_drop = item_drop.clone();
@ -971,13 +798,9 @@ where
} }
} }
pub(super) fn add_item_to_local_floor<EG, TR>( pub(super) fn add_item_to_local_floor(character_id: CharacterEntityId)
character_id: CharacterEntityId, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem)
) -> impl Fn((ItemStateProxy, TR), FloorItem) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(mut item_state, transaction) , floor_item| { move |(mut item_state, transaction) , floor_item| {
Box::pin(async move { Box::pin(async move {
@ -990,13 +813,9 @@ where
} }
} }
pub(super) fn apply_modifier_to_inventory_item<EG, TR>( pub(super) fn apply_modifier_to_inventory_item(modifier: ItemModifier)
modifier: ItemModifier, -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
) -> impl Fn((ItemStateProxy, TR), InventoryItem) -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(item_state, mut transaction), mut inventory_item| { move |(item_state, mut transaction), mut inventory_item| {
let modifier = modifier.clone(); let modifier = modifier.clone();
@ -1014,12 +833,9 @@ where
} }
} }
pub(super) fn as_individual_item<EG, TR>( pub(super) fn as_individual_item()
) -> impl Fn((ItemStateProxy, TR), InventoryItem) -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
-> BoxFuture<Result<((ItemStateProxy, TR), IndividualItemDetail), ItemStateError>> -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), IndividualItemDetail), ItemStateError>> + Send + 'a>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{ {
move |(item_state, transaction), inventory_item| { move |(item_state, transaction), inventory_item| {
Box::pin(async move { Box::pin(async move {
@ -1032,85 +848,3 @@ where
}) })
} }
} }
pub(super) fn apply_item_action_packets<EG, TR>(
character_id: CharacterEntityId,
area_client: AreaClient,
) -> impl Fn((ItemStateProxy, TR), ApplyItemAction)
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<SendShipPacket>), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{
move |(mut item_state, mut transaction), apply_item_action| {
Box::pin(async move {
let pkts = if let ApplyItemAction::CreateItem(item_detail) = apply_item_action {
let new_item = transaction.gateway().create_item(NewItemEntity {
item: item_detail.clone(),
}).await?;
let item_id = item_state.new_item_id().await?;
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 item_detail = StackedItemDetail {
entity_ids: vec![new_item.id],
tool
};
(InventoryItemDetail::Stacked(item_detail), create_item)
}
else {
let item_detail = IndividualItemDetail {
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)?;
(InventoryItemDetail::Individual(item_detail), create_item)
};
let inventory_item = InventoryItem {
item_id,
item: inventory_item_detail,
};
let mut inventory = item_state.inventory(&character_id).await?;
inventory.add_item(inventory_item)?;
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)))]
}
else {
Vec::new()
};
Ok(((item_state, transaction), pkts))
})
}
}
pub(super) fn apply_item_action_character<EG, TR>(
character: &CharacterEntity
) -> impl Fn((ItemStateProxy, TR), Vec<ApplyItemAction>)
-> BoxFuture<Result<((ItemStateProxy, TR), CharacterEntity), ItemStateError>>
where
EG: EntityGateway,
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
{
let character = character.clone();
move |(item_state, transaction), apply_item_actions| {
let mut character = character.clone();
Box::pin(async move {
for action in apply_item_actions {
if let ApplyItemAction::UpdateCharacter(new_character) = action {
character = *new_character
}
}
Ok(((item_state, transaction), character))
})
}
}

View File

@ -1,12 +1,9 @@
use std::convert::TryInto;
use futures::future::join_all;
use thiserror::Error; use thiserror::Error;
use rand::SeedableRng; use std::convert::TryInto;
use rand::distributions::{WeightedIndex, Distribution};
use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::gateway::{EntityGateway, GatewayError};
use crate::entity::character::CharacterEntity; use crate::entity::character::CharacterEntity;
use crate::entity::item::mag::{MagCell, MagCellError}; use crate::entity::item::mag::{MagCell, MagCellError};
use crate::entity::item::tool::{Tool, ToolType}; use crate::entity::item::tool::ToolType;
use crate::entity::item::{ItemDetail, ItemEntityId}; use crate::entity::item::{ItemDetail, ItemEntityId};
use crate::ship::items::state::{ItemStateProxy, ItemStateError}; use crate::ship::items::state::{ItemStateProxy, ItemStateError};
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
@ -30,60 +27,53 @@ pub enum ApplyItemError {
MagCellError(#[from] MagCellError), MagCellError(#[from] MagCellError),
} }
#[derive(Debug, Clone)]
pub enum ApplyItemAction {
UpdateCharacter(Box<CharacterEntity>),
CreateItem(ItemDetail),
//TransformItem,
//RemoveItem,
}
impl From<ItemStateError> for ApplyItemError { impl From<ItemStateError> for ApplyItemError {
fn from(other: ItemStateError) -> ApplyItemError { fn from(other: ItemStateError) -> ApplyItemError {
ApplyItemError::ItemStateError(Box::new(other)) ApplyItemError::ItemStateError(Box::new(other))
} }
} }
async fn power_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { // TODO: make all these functions not-pub
pub async fn power_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.power += 1; character.materials.power += 1;
entity_gateway.save_character(character).await?; entity_gateway.save_character(character).await?;
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) Ok(())
} }
async fn mind_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { pub async fn mind_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.mind += 1; character.materials.mind += 1;
entity_gateway.save_character(character).await.unwrap(); entity_gateway.save_character(character).await.unwrap();
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) Ok(())
} }
async fn evade_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { pub async fn evade_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.evade += 1; character.materials.evade += 1;
entity_gateway.save_character(character).await.unwrap(); entity_gateway.save_character(character).await.unwrap();
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) Ok(())
} }
async fn def_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { pub async fn def_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.def += 1; character.materials.def += 1;
entity_gateway.save_character(character).await.unwrap(); entity_gateway.save_character(character).await.unwrap();
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) Ok(())
} }
async fn luck_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { pub async fn luck_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.luck += 1; character.materials.luck += 1;
entity_gateway.save_character(character).await.unwrap(); entity_gateway.save_character(character).await.unwrap();
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) Ok(())
} }
async fn hp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { pub async fn hp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.hp += 1; character.materials.hp += 1;
entity_gateway.save_character(character).await.unwrap(); entity_gateway.save_character(character).await.unwrap();
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) Ok(())
} }
async fn tp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { pub async fn tp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.tp += 1; character.materials.tp += 1;
entity_gateway.save_character(character).await.unwrap(); entity_gateway.save_character(character).await.unwrap();
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) Ok(())
} }
/* /*
@ -108,12 +98,12 @@ async fn mag_cell<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &Consum
*/ */
async fn mag_cell<'a, EG>(item_state: &mut ItemStateProxy, async fn mag_cell<'a, EG>(item_state: &mut ItemStateProxy<'a>,
entity_gateway: &mut EG, entity_gateway: &mut EG,
character: &CharacterEntity, character: &CharacterEntity,
cell_entity_id: ItemEntityId, cell_entity_id: ItemEntityId,
mag_cell_type: MagCell) mag_cell_type: MagCell)
-> Result<Vec<ApplyItemAction>, ApplyItemError> -> Result<(), ApplyItemError>
where where
EG: EntityGateway + ?Sized, EG: EntityGateway + ?Sized,
{ {
@ -125,9 +115,9 @@ where
entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await?; entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await?;
entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
item_state.set_inventory(inventory).await; item_state.set_inventory(inventory);
Ok(Vec::new()) Ok(())
} }
/* /*
@ -228,31 +218,12 @@ pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell:
} }
*/ */
async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy<'a>,
fn jack_o_lantern() -> Result<Vec<ApplyItemAction>, ApplyItemError>
{
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,
2 => ToolType::HeartOfChuChu,
3 => ToolType::HeartOfKapuKapu,
4 => ToolType::PartsOfRobochao,
5 => ToolType::HeartOfOpaOpa,
6 => ToolType::HeartOfPian,
7 => ToolType::HeartOfChao,
_ => unreachable!(),
};
Ok(vec![ApplyItemAction::CreateItem(ItemDetail::Tool(Tool {tool: mag_type}))])
}
async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy,
entity_gateway: &mut EG, entity_gateway: &mut EG,
character: &mut CharacterEntity, character: &mut CharacterEntity,
entity_id: ItemEntityId, entity_id: ItemEntityId,
tool: ToolType) tool: ToolType)
-> Result<Vec<ApplyItemAction>, ApplyItemError> -> Result<(), ApplyItemError>
where where
EG: EntityGateway + ?Sized, EG: EntityGateway + ?Sized,
{ {
@ -264,13 +235,13 @@ where
ToolType::LuckMaterial => luck_material(entity_gateway, character).await, ToolType::LuckMaterial => luck_material(entity_gateway, character).await,
ToolType::HpMaterial => hp_material(entity_gateway, character).await, ToolType::HpMaterial => hp_material(entity_gateway, character).await,
ToolType::TpMaterial => tp_material(entity_gateway, character).await, ToolType::TpMaterial => tp_material(entity_gateway, character).await,
ToolType::Monomate => Ok(Vec::new()), ToolType::Monomate => Ok(()),
ToolType::Dimate => Ok(Vec::new()), ToolType::Dimate => Ok(()),
ToolType::Trimate => Ok(Vec::new()), ToolType::Trimate => Ok(()),
ToolType::Monofluid => Ok(Vec::new()), ToolType::Monofluid => Ok(()),
ToolType::Difluid => Ok(Vec::new()), ToolType::Difluid => Ok(()),
ToolType::Trifluid => Ok(Vec::new()), ToolType::Trifluid => Ok(()),
ToolType::HuntersReport => Ok(Vec::new()), ToolType::HuntersReport => Ok(()),
ToolType::CellOfMag502 ToolType::CellOfMag502
| ToolType::CellOfMag213 | ToolType::CellOfMag213
| ToolType::PartsOfRobochao | ToolType::PartsOfRobochao
@ -297,7 +268,6 @@ where
| ToolType::LibertaKit => { | ToolType::LibertaKit => {
mag_cell(item_state, entity_gateway, character, entity_id, tool.try_into()?).await mag_cell(item_state, entity_gateway, character, entity_id, tool.try_into()?).await
} }
ToolType::JackOLantern => jack_o_lantern(),
// TODO: rest of these // TODO: rest of these
_ => Err(ApplyItemError::InvalidItem) _ => Err(ApplyItemError::InvalidItem)
} }
@ -305,14 +275,7 @@ where
} }
pub async fn apply_item<'a, EG>(item_state: &mut ItemStateProxy, pub async fn apply_item<'a, EG: EntityGateway + ?Sized>(item_state: &mut ItemStateProxy<'a>, entity_gateway: &mut EG, character: &mut CharacterEntity, item: InventoryItem) -> Result<(), ApplyItemError> {
entity_gateway: &mut EG,
character: &mut CharacterEntity,
item: InventoryItem
) -> Result<Vec<ApplyItemAction>, ApplyItemError>
where
EG: EntityGateway + ?Sized + Clone + 'static
{
match item.item { match item.item {
InventoryItemDetail::Individual(individual_item) => { InventoryItemDetail::Individual(individual_item) => {
match individual_item.item { match individual_item.item {
@ -321,22 +284,10 @@ where
} }
}, },
InventoryItemDetail::Stacked(stacked_item) => { InventoryItemDetail::Stacked(stacked_item) => {
Ok(join_all(stacked_item.entity_ids.iter() for entity_id in stacked_item.entity_ids {
.map(|entity_id| { apply_tool(item_state, entity_gateway, character, entity_id, stacked_item.tool.tool).await?
let mut entity_gateway = entity_gateway.clone(); }
let mut character = character.clone(); Ok(())
let mut item_state = item_state.clone();
async move {
apply_tool(&mut item_state, &mut entity_gateway, &mut character, *entity_id, stacked_item.tool.tool).await
}
})
.collect::<Vec<_>>())
.await
.into_iter()
.collect::<Result<Vec<Vec<_>>, _>>()?
.into_iter()
.flatten()
.collect())
}, },
} }
} }

View File

@ -179,7 +179,7 @@ pub enum InventoryError {
MesetaFull, MesetaFull,
} }
#[derive(Clone, Debug)] #[derive(Clone)]
pub struct InventoryState { pub struct InventoryState {
pub character_id: CharacterEntityId, pub character_id: CharacterEntityId,
pub item_id_counter: u32, pub item_id_counter: u32,

View File

@ -1,5 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use async_std::sync::{Arc, RwLock, Mutex}; use async_std::sync::{Arc, RwLock};
use futures::future::join_all; use futures::future::join_all;
use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::gateway::{EntityGateway, GatewayError};
@ -124,7 +124,7 @@ pub enum AddItemResult {
} }
#[derive(Clone, Debug)] #[derive(Clone)]
pub struct ItemState { pub struct ItemState {
character_inventory: Arc<RwLock<HashMap<CharacterEntityId, RwLock<InventoryState>>>>, character_inventory: Arc<RwLock<HashMap<CharacterEntityId, RwLock<InventoryState>>>>,
character_bank: Arc<RwLock<HashMap<CharacterEntityId, RwLock<BankState>>>>, character_bank: Arc<RwLock<HashMap<CharacterEntityId, RwLock<BankState>>>>,
@ -373,38 +373,36 @@ impl ItemState {
} }
#[derive(Default, Clone)] #[derive(Default)]
struct ProxiedItemState { struct ProxiedItemState {
character_inventory: Arc<Mutex<HashMap<CharacterEntityId, InventoryState>>>, character_inventory: HashMap<CharacterEntityId, InventoryState>,
character_bank: Arc<Mutex<HashMap<CharacterEntityId, BankState>>>, character_bank: HashMap<CharacterEntityId, BankState>,
//character_room: HashMap<CharacterEntityId, RoomId>, //character_room: HashMap<CharacterEntityId, RoomId>,
character_floor: Arc<Mutex<HashMap<CharacterEntityId, LocalFloor>>>, character_floor: HashMap<CharacterEntityId, LocalFloor>,
room_floor: Arc<Mutex<HashMap<RoomId, SharedFloor>>>, room_floor: HashMap<RoomId, SharedFloor>,
} }
#[derive(Clone)] pub struct ItemStateProxy<'a> {
pub struct ItemStateProxy { item_state: &'a mut ItemState,
item_state: ItemState,
proxied_state: ProxiedItemState, proxied_state: ProxiedItemState,
} }
impl ItemStateProxy { impl<'a> ItemStateProxy<'a> {
pub async fn commit(self) { pub async fn commit(self) {
async fn copy_back<K, V>(master: &Arc<RwLock<HashMap<K, RwLock<V>>>>, async fn copy_back<K, V>(master: &Arc<RwLock<HashMap<K, RwLock<V>>>>,
proxy: Arc<Mutex<HashMap<K, V>>>) proxy: HashMap<K, V>)
where where
K: Eq + std::hash::Hash, K: Eq + std::hash::Hash,
V: Clone,
{ {
for (key, value) in proxy.lock().await.iter() { for (key, value) in proxy {
if let Some(element) = master if let Some(element) = master
.read() .read()
.await .await
.get(key) { .get(&key) {
*element *element
.write() .write()
.await = value.clone(); .await = value;
} }
} }
} }
@ -419,7 +417,7 @@ impl ItemStateProxy {
async fn get_or_clone<K, V>(master: &Arc<RwLock<HashMap<K, RwLock<V>>>>, async fn get_or_clone<K, V>(master: &Arc<RwLock<HashMap<K, RwLock<V>>>>,
proxy: &Arc<Mutex<HashMap<K, V>>>, proxy: &mut HashMap<K, V>,
key: K, key: K,
err: fn(K) -> ItemStateError) -> Result<V, ItemStateError> err: fn(K) -> ItemStateError) -> Result<V, ItemStateError>
where where
@ -434,17 +432,14 @@ where
.read() .read()
.await .await
.clone(); .clone();
Ok(proxy Ok(proxy.entry(key)
.lock()
.await
.entry(key)
.or_insert_with(|| existing_element) .or_insert_with(|| existing_element)
.clone()) .clone())
} }
impl ItemStateProxy { impl<'a> ItemStateProxy<'a> {
pub fn new(item_state: ItemState) -> Self { pub fn new(item_state: &'a mut ItemState) -> Self {
ItemStateProxy { ItemStateProxy {
item_state, item_state,
proxied_state: Default::default(), proxied_state: Default::default(),
@ -453,39 +448,39 @@ impl ItemStateProxy {
pub async fn inventory(&mut self, character_id: &CharacterEntityId) -> Result<InventoryState, ItemStateError> { pub async fn inventory(&mut self, character_id: &CharacterEntityId) -> Result<InventoryState, ItemStateError> {
get_or_clone(&self.item_state.character_inventory, get_or_clone(&self.item_state.character_inventory,
&self.proxied_state.character_inventory, &mut self.proxied_state.character_inventory,
*character_id, *character_id,
ItemStateError::NoCharacter).await ItemStateError::NoCharacter).await
} }
pub async fn set_inventory(&mut self, inventory: InventoryState) { pub fn set_inventory(&mut self, inventory: InventoryState) {
self.proxied_state.character_inventory.lock().await.insert(inventory.character_id, inventory); self.proxied_state.character_inventory.insert(inventory.character_id, inventory);
} }
pub async fn bank(&mut self, character_id: &CharacterEntityId) -> Result<BankState, ItemStateError> { pub async fn bank(&mut self, character_id: &CharacterEntityId) -> Result<BankState, ItemStateError> {
get_or_clone(&self.item_state.character_bank, get_or_clone(&self.item_state.character_bank,
&self.proxied_state.character_bank, &mut self.proxied_state.character_bank,
*character_id, *character_id,
ItemStateError::NoCharacter).await ItemStateError::NoCharacter).await
} }
pub async fn set_bank(&mut self, bank: BankState) { pub fn set_bank(&mut self, bank: BankState) {
self.proxied_state.character_bank.lock().await.insert(bank.character_id, bank); self.proxied_state.character_bank.insert(bank.character_id, bank);
} }
pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result<FloorState, ItemStateError> { pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result<FloorState, ItemStateError> {
let room_id = *self.item_state.character_room.read().await.get(character_id).unwrap(); let room_id = *self.item_state.character_room.read().await.get(character_id).unwrap();
Ok(FloorState { Ok(FloorState {
character_id: *character_id, character_id: *character_id,
local: get_or_clone(&self.item_state.character_floor, &self.proxied_state.character_floor, *character_id, ItemStateError::NoCharacter).await?, local: get_or_clone(&self.item_state.character_floor, &mut self.proxied_state.character_floor, *character_id, ItemStateError::NoCharacter).await?,
shared: get_or_clone(&self.item_state.room_floor, &self.proxied_state.room_floor, room_id, ItemStateError::NoRoom).await?, shared: get_or_clone(&self.item_state.room_floor, &mut self.proxied_state.room_floor, room_id, ItemStateError::NoRoom).await?,
}) })
} }
pub async fn set_floor(&mut self, floor: FloorState) { pub async fn set_floor(&mut self, floor: FloorState) {
let room_id = *self.item_state.character_room.read().await.get(&floor.character_id).unwrap(); let room_id = *self.item_state.character_room.read().await.get(&floor.character_id).unwrap();
self.proxied_state.character_floor.lock().await.insert(floor.character_id, floor.local); self.proxied_state.character_floor.insert(floor.character_id, floor.local);
self.proxied_state.room_floor.lock().await.insert(room_id, floor.shared); self.proxied_state.room_floor.insert(room_id, floor.shared);
} }
pub async fn new_item_id(&mut self) -> Result<ClientItemId, ItemStateError> { pub async fn new_item_id(&mut self) -> Result<ClientItemId, ItemStateError> {

View File

@ -1,10 +1,9 @@
use crate::ship::items::ClientItemId; use crate::ship::items::ClientItemId;
use crate::entity::item::Meseta; use crate::entity::item::Meseta;
use crate::ship::ship::SendShipPacket;
use crate::ship::map::MapArea; use crate::ship::map::MapArea;
use crate::entity::character::{CharacterEntity, CharacterEntityId}; use crate::entity::character::{CharacterEntity, CharacterEntityId};
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; use crate::entity::gateway::EntityGateway;
use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateError, IndividualItemDetail}; use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateError, IndividualItemDetail};
use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction}; use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction};
use crate::ship::items::inventory::InventoryItem; use crate::ship::items::inventory::InventoryItem;
@ -24,11 +23,10 @@ pub async fn pick_up_item<EG>(
item_id: &ClientItemId) item_id: &ClientItemId)
-> Result<actions::TriggerCreateItem, ItemStateError> -> Result<actions::TriggerCreateItem, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
EG::Transaction: Clone,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_item_from_floor(character.id, *item_id)) .act(actions::take_item_from_floor(character.id, *item_id))
.act(actions::add_floor_item_to_inventory(character)) .act(actions::add_floor_item_to_inventory(character))
@ -48,10 +46,10 @@ pub async fn drop_item<EG>(
drop_position: (f32, f32, f32)) drop_position: (f32, f32, f32))
-> Result<FloorItem, ItemStateError> -> Result<FloorItem, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_item_from_inventory(character.id, *item_id, 0)) .act(actions::take_item_from_inventory(character.id, *item_id, 0))
.act(actions::add_inventory_item_to_shared_floor(character.id, map_area, drop_position)) .act(actions::add_inventory_item_to_shared_floor(character.id, map_area, drop_position))
@ -72,10 +70,10 @@ pub async fn drop_partial_item<'a, EG>(
amount: u32) amount: u32)
-> Result<FloorItem, ItemStateError> -> Result<FloorItem, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_item_from_inventory(character.id, *item_id, amount)) .act(actions::take_item_from_inventory(character.id, *item_id, amount))
.act(actions::add_inventory_item_to_shared_floor(character.id, map_area, (drop_position.0, 0.0, drop_position.1))) .act(actions::add_inventory_item_to_shared_floor(character.id, map_area, (drop_position.0, 0.0, drop_position.1)))
@ -97,10 +95,10 @@ pub async fn drop_meseta<'a, EG>(
amount: u32) amount: u32)
-> Result<FloorItem, ItemStateError> -> Result<FloorItem, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_meseta_from_inventory(character.id, amount)) .act(actions::take_meseta_from_inventory(character.id, amount))
.act(actions::add_meseta_to_shared_floor(character.id, amount, map_area, drop_position)) .act(actions::add_meseta_to_shared_floor(character.id, amount, map_area, drop_position))
@ -119,10 +117,10 @@ pub async fn withdraw_meseta<'a, EG>(
amount: u32) amount: u32)
-> Result<(), ItemStateError> -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_meseta_from_bank(character.id, amount)) .act(actions::take_meseta_from_bank(character.id, amount))
.act(actions::add_meseta_from_bank_to_inventory(character.id, amount)) .act(actions::add_meseta_from_bank_to_inventory(character.id, amount))
@ -141,10 +139,10 @@ pub async fn deposit_meseta<'a, EG>(
amount: u32) amount: u32)
-> Result<(), ItemStateError> -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), _) = ItemStateAction::default() let ((item_state_proxy, transaction), _) = ItemStateAction::default()
.act(actions::take_meseta_from_inventory(character.id, amount)) .act(actions::take_meseta_from_inventory(character.id, amount))
.act(actions::add_meseta_to_bank(character.id, amount)) .act(actions::add_meseta_to_bank(character.id, amount))
@ -164,10 +162,10 @@ pub async fn withdraw_item<'a, EG>(
amount: u32) amount: u32)
-> Result<InventoryItem, ItemStateError> -> Result<InventoryItem, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_item_from_bank(character.id, *item_id, amount)) .act(actions::take_item_from_bank(character.id, *item_id, amount))
//.act(bank_item_to_inventory_item) //.act(bank_item_to_inventory_item)
@ -189,10 +187,10 @@ pub async fn deposit_item<'a, EG> (
amount: u32) amount: u32)
-> Result<(), ItemStateError> -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_item_from_inventory(character.id, *item_id, amount)) .act(actions::take_item_from_inventory(character.id, *item_id, amount))
.act(actions::add_inventory_item_to_bank(character.id)) .act(actions::add_inventory_item_to_bank(character.id))
@ -211,10 +209,10 @@ pub async fn equip_item<'a, EG> (
equip_slot: u8, equip_slot: u8,
) -> Result<(), ItemStateError> ) -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::equip_inventory_item(character.id, *item_id, equip_slot)) .act(actions::equip_inventory_item(character.id, *item_id, equip_slot))
.commit((item_state_proxy, transaction)) .commit((item_state_proxy, transaction))
@ -232,10 +230,10 @@ pub async fn unequip_item<'a, EG> (
item_id: &ClientItemId, item_id: &ClientItemId,
) -> Result<(), ItemStateError> ) -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::unequip_inventory_item(character.id, *item_id)) .act(actions::unequip_inventory_item(character.id, *item_id))
.commit((item_state_proxy, transaction)) .commit((item_state_proxy, transaction))
@ -253,10 +251,10 @@ pub async fn sort_inventory<'a, EG> (
item_ids: Vec<ClientItemId>, item_ids: Vec<ClientItemId>,
) -> Result<(), ItemStateError> ) -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::sort_inventory_items(character.id, item_ids)) .act(actions::sort_inventory_items(character.id, item_ids))
.commit((item_state_proxy, transaction)) .commit((item_state_proxy, transaction))
@ -271,28 +269,22 @@ pub async fn use_item<'a, EG> (
item_state: &'a mut ItemState, item_state: &'a mut ItemState,
entity_gateway: &mut EG, entity_gateway: &mut EG,
character: &mut CharacterEntity, character: &mut CharacterEntity,
area_client: AreaClient,
item_id: &ClientItemId, item_id: &ClientItemId,
amount: u32, amount: u32,
) -> Result<Vec<SendShipPacket>, ItemStateError> ) -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), (pkts, new_character)) = ItemStateAction::default() let ((item_state_proxy, transaction), new_character) = ItemStateAction::default()
.act(actions::take_item_from_inventory(character.id, *item_id, amount)) .act(actions::take_item_from_inventory(character.id, *item_id, amount))
.act(actions::use_consumed_item(character)) .act(actions::use_consumed_item(character.clone()))
.act(actions::fork(
actions::foreach(actions::apply_item_action_packets(character.id, area_client)),
actions::apply_item_action_character(character)
))
.commit((item_state_proxy, transaction)) .commit((item_state_proxy, transaction))
.await?; .await?;
item_state_proxy.commit().await; item_state_proxy.commit().await;
*character = new_character; *character = new_character;
Ok((transaction, pkts.into_iter().flatten().collect())) Ok((transaction, ()))
}).await }).await
} }
@ -305,10 +297,10 @@ pub async fn feed_mag<'a, EG> (
tool_item_id: &ClientItemId, tool_item_id: &ClientItemId,
) -> Result<(), ItemStateError> ) -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), _) = ItemStateAction::default() let ((item_state_proxy, transaction), _) = ItemStateAction::default()
.act(actions::take_item_from_inventory(character.id, *tool_item_id, 1)) .act(actions::take_item_from_inventory(character.id, *tool_item_id, 1))
.act(actions::feed_mag_item(character.clone(), *mag_item_id)) .act(actions::feed_mag_item(character.clone(), *mag_item_id))
@ -329,11 +321,11 @@ pub async fn buy_shop_item<'a, EG> (
amount: u32, amount: u32,
) -> Result<InventoryItem, ItemStateError> ) -> Result<InventoryItem, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
let item_price = shop_item.price() as u32 * amount; let item_price = shop_item.price() as u32 * amount;
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_meseta_from_inventory(character.id, item_price)) .act(actions::take_meseta_from_inventory(character.id, item_price))
//.act(bought_item_to_inventory_item) //.act(bought_item_to_inventory_item)
@ -355,10 +347,10 @@ pub async fn sell_item<'a, EG> (
amount: u32, amount: u32,
) -> Result<InventoryItem, ItemStateError> ) -> Result<InventoryItem, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), result) = ItemStateAction::default() let ((item_state_proxy, transaction), result) = ItemStateAction::default()
.act(actions::take_item_from_inventory(character.id, item_id, amount)) .act(actions::take_item_from_inventory(character.id, item_id, amount))
.act(actions::sell_inventory_item(character.id)) .act(actions::sell_inventory_item(character.id))
@ -375,7 +367,7 @@ pub async fn trade_items<'a, EG> (
p2: (&AreaClient, &CharacterEntity, &Vec<TradeItem>, Meseta)) p2: (&AreaClient, &CharacterEntity, &Vec<TradeItem>, Meseta))
-> Result<(Vec<InventoryItem>, Vec<InventoryItem>), ItemStateError> -> Result<(Vec<InventoryItem>, Vec<InventoryItem>), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
let p1_trade_items = p1.2 let p1_trade_items = p1.2
.iter() .iter()
@ -399,7 +391,7 @@ where
let p1_id = p1.1.id; let p1_id = p1.1.id;
let p2_id = p2.1.id; let p2_id = p2.1.id;
let trade = transaction.gateway().create_trade(&p1_id, &p2_id).await?; let trade = transaction.gateway().create_trade(&p1_id, &p2_id).await?;
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), p1_removed_items) = ItemStateAction::default() let ((item_state_proxy, transaction), p1_removed_items) = ItemStateAction::default()
.act(actions::iterate(p1_trade_items, move |p1_trade_item| actions::take_item_from_inventory(p1_id, p1_trade_item.0, p1_trade_item.1) )) .act(actions::iterate(p1_trade_items, move |p1_trade_item| actions::take_item_from_inventory(p1_id, p1_trade_item.0, p1_trade_item.1) ))
.act(actions::foreach(actions::assign_new_item_id())) .act(actions::foreach(actions::assign_new_item_id()))
@ -445,10 +437,10 @@ pub async fn take_meseta<'a, EG> (
meseta: Meseta) meseta: Meseta)
-> Result<(), ItemStateError> -> Result<(), ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), _) = ItemStateAction::default() let ((item_state_proxy, transaction), _) = ItemStateAction::default()
.act(actions::take_meseta_from_inventory(*character_id, meseta.0)) .act(actions::take_meseta_from_inventory(*character_id, meseta.0))
.commit((item_state_proxy, transaction)) .commit((item_state_proxy, transaction))
@ -466,10 +458,10 @@ pub async fn enemy_drops_item<'a, EG> (
item_drop: ItemDrop) item_drop: ItemDrop)
-> Result<FloorItem, ItemStateError> -> Result<FloorItem, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default() let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default()
.act(actions::convert_item_drop_to_floor_item(character_id, item_drop)) .act(actions::convert_item_drop_to_floor_item(character_id, item_drop))
.act(actions::add_item_to_local_floor(character_id)) .act(actions::add_item_to_local_floor(character_id))
@ -490,10 +482,10 @@ pub async fn apply_modifier<'a, EG> (
modifier: ItemModifier) modifier: ItemModifier)
-> Result<IndividualItemDetail, ItemStateError> -> Result<IndividualItemDetail, ItemStateError>
where where
EG: EntityGateway + 'static, EG: EntityGateway,
{ {
entity_gateway.with_transaction(|transaction| async move { entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state.clone()); let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), item) = ItemStateAction::default() let ((item_state_proxy, transaction), item) = ItemStateAction::default()
.act(actions::take_item_from_inventory(character.id, item_id, 1)) .act(actions::take_item_from_inventory(character.id, item_id, 1))
.act(actions::apply_modifier_to_inventory_item(modifier)) .act(actions::apply_modifier_to_inventory_item(modifier))

View File

@ -69,10 +69,9 @@ pub enum ClientRemovalError {
} }
#[derive(Error, Debug, PartialEq, Eq)] #[derive(Error, Debug, PartialEq, Eq)]
#[error("get clients")]
pub enum GetClientsError { pub enum GetClientsError {
#[error("invalid client")]
InvalidClient, InvalidClient,
#[error("invalid area")]
InvalidArea, InvalidArea,
} }
@ -148,7 +147,7 @@ pub enum RoomLobby {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ClientLocation { pub struct ClientLocation {
lobbies: [Arc<RwLock<Lobby>>; 15], lobbies: [Arc<RwLock<Lobby>>; 15],
rooms: [Arc<RwLock<Option<Room>>>; MAX_ROOMS], rooms: [Option<Arc<RwLock<Room>>>; MAX_ROOMS],
client_location: Arc<RwLock<HashMap<ClientId, RoomLobby>>>, client_location: Arc<RwLock<HashMap<ClientId, RoomLobby>>>,
} }
@ -156,7 +155,7 @@ impl Default for ClientLocation {
fn default() -> ClientLocation { fn default() -> ClientLocation {
ClientLocation { ClientLocation {
lobbies: core::array::from_fn(|_| Arc::new(RwLock::new(Lobby([None; 12])))), lobbies: core::array::from_fn(|_| Arc::new(RwLock::new(Lobby([None; 12])))),
rooms: core::array::from_fn(|_| Arc::new(RwLock::new(None))), rooms: core::array::from_fn(|_| None),
client_location: Arc::new(RwLock::new(HashMap::new())), client_location: Arc::new(RwLock::new(HashMap::new())),
} }
} }
@ -211,16 +210,15 @@ impl ClientLocation {
} }
pub async fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> { pub async fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
let (index, empty_slot) = Box::pin(stream::iter(self.rooms.iter()) let (index, empty_slot) = self.rooms.iter_mut()
.enumerate() .enumerate()
.filter(|(_, r)| async {r.read().await.is_none()})) .find(|(_, r)| r.is_none())
.next()
.await
.ok_or(CreateRoomError::NoOpenSlots)?; .ok_or(CreateRoomError::NoOpenSlots)?;
*empty_slot.write().await = Some(Room([None; 4])); *empty_slot = Some(Arc::new(RwLock::new(Room([None; 4]))));
self.add_client_to_room(id, RoomId(index)) self.add_client_to_room(id, RoomId(index))
.await .await
.map_err(|_err| CreateRoomError::JoinError)?; .map_err(|_err| CreateRoomError::JoinError)?;
Ok(RoomId(index)) Ok(RoomId(index))
} }
@ -228,10 +226,9 @@ impl ClientLocation {
let mut r = self.rooms.get(room.0) let mut r = self.rooms.get(room.0)
.ok_or(JoinRoomError::RoomDoesNotExist)? .ok_or(JoinRoomError::RoomDoesNotExist)?
.as_ref() .as_ref()
.ok_or(JoinRoomError::RoomDoesNotExist)?
.write() .write()
.await; .await;
let r = r.as_mut()
.ok_or(JoinRoomError::RoomDoesNotExist)?;
let (index, empty_slot) = r.0.iter_mut() let (index, empty_slot) = r.0.iter_mut()
.enumerate() .enumerate()
.find(|(_, k)| k.is_none()) .find(|(_, k)| k.is_none())
@ -296,9 +293,9 @@ impl ClientLocation {
pub async fn get_room_leader(&self, room: RoomId) -> Result<AreaClient, GetLeaderError> { pub async fn get_room_leader(&self, room: RoomId) -> Result<AreaClient, GetLeaderError> {
let r = self.rooms[room.0] let r = self.rooms[room.0]
.as_ref() .as_ref()
.ok_or(GetLeaderError::InvalidArea)?
.read() .read()
.await .await;
.ok_or(GetLeaderError::InvalidArea)?;
let mut r = r let mut r = r
.0 .0
.iter() .iter()
@ -371,9 +368,9 @@ impl ClientLocation {
Ok(self.rooms.get(room.0) Ok(self.rooms.get(room.0)
.ok_or(GetClientsError::InvalidArea)? .ok_or(GetClientsError::InvalidArea)?
.as_ref() .as_ref()
.ok_or(GetClientsError::InvalidArea)?
.read() .read()
.await .await
.ok_or(GetClientsError::InvalidArea)?
.0 .0
.iter() .iter()
.filter_map(|client| { .filter_map(|client| {
@ -459,13 +456,9 @@ impl ClientLocation {
.ok_or(ClientRemovalError::ClientNotInArea)?; .ok_or(ClientRemovalError::ClientNotInArea)?;
match area { match area {
RoomLobby::Room(room) => { RoomLobby::Room(room) => {
let mut r = self.rooms.get(room.0) let r = self.rooms.get(room.0).ok_or(ClientRemovalError::InvalidArea)?;
.ok_or(ClientRemovalError::InvalidArea)? if let Some(r) = r {
.as_ref() remove_client(id, &mut r.write().await.0)
.write()
.await;
if let Some(r) = r.as_mut() {
remove_client(id, &mut r.0)
} }
else { else {
return Err(ClientRemovalError::InvalidArea) return Err(ClientRemovalError::InvalidArea)

View File

@ -84,7 +84,7 @@ pub async fn request_item<EG>(id: ClientId,
item_state: &mut ItemState) item_state: &mut ItemState)
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> -> Result<Vec<(ClientId, SendShipPacket)>, ShipError>
where where
EG: EntityGateway + 'static, EG: EntityGateway
{ {
let room_id = client_location.get_room(id).await?; let room_id = client_location.get_room(id).await?;
let monster = rooms.with(room_id, |room| Box::pin(async move { let monster = rooms.with(room_id, |room| Box::pin(async move {

View File

@ -330,32 +330,20 @@ where
pub async fn player_uses_item<EG>(id: ClientId, pub async fn player_uses_item<EG>(id: ClientId,
player_use_tool: PlayerUseItem, player_use_tool: PlayerUseItem,
entity_gateway: &mut EG, entity_gateway: &mut EG,
client_location: &ClientLocation, _client_location: &ClientLocation,
clients: &Clients, clients: &Clients,
item_state: &mut ItemState) item_state: &mut ItemState)
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> -> Result<Vec<(ClientId, SendShipPacket)>, ShipError>
where where
EG: EntityGateway + Clone + 'static, EG: EntityGateway + Clone + 'static,
{ {
let neighbors = client_location.get_all_clients_by_client(id).await?.into_iter(); clients.with_mut(id, |client| {
let area_client = client_location.get_local_client(id).await?;
Ok(clients.with_mut(id, |client| {
let mut entity_gateway = entity_gateway.clone(); let mut entity_gateway = entity_gateway.clone();
let mut item_state = item_state.clone(); let mut item_state = item_state.clone();
Box::pin(async move { Box::pin(async move {
use_item(&mut item_state, &mut entity_gateway, &mut client.character, area_client, &ClientItemId(player_use_tool.item_id), 1).await use_item(&mut item_state, &mut entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await
})}).await?? })}).await??;
.into_iter() Ok(Vec::new())
.flat_map(move |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())]
})
})
.flatten()
.collect::<Vec<_>>()
)
} }
pub async fn player_used_medical_center<EG>(id: ClientId, pub async fn player_used_medical_center<EG>(id: ClientId,

View File

@ -104,7 +104,7 @@ pub enum ShipError {
InvalidSlot(ClientId, u32), InvalidSlot(ClientId, u32),
#[error("too many clients")] #[error("too many clients")]
TooManyClients, TooManyClients,
#[error("client location {0}")] #[error("client error location {0}")]
ClientLocationError(ClientLocationError), ClientLocationError(ClientLocationError),
#[error("maps error {0}")] #[error("maps error {0}")]
MapsError(#[from] MapsError), MapsError(#[from] MapsError),

View File

@ -251,59 +251,6 @@ async fn test_use_materials() {
assert!(char.materials.luck == 2); assert!(char.materials.luck == 2);
} }
#[async_std::test]
async fn test_jackolantern() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let p1_inv = vec![
item::InventoryItemEntity::Stacked(
vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::JackOLantern,
}
),
}).await.unwrap(),
entity_gateway.create_item(item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::JackOLantern,
}
),
}).await.unwrap(),
])];
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());
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;
ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
client: 0,
target: 0,
item_id: 0x10000,
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
client: 0,
target: 0,
item_id: 0x10000,
})))).await.unwrap();
let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
for item in inventory_items.items {
for sitem in item.stacked().unwrap() {
assert!(sitem.item.clone().as_tool().unwrap().tool.is_mag_cell());
}
}
}
// TODO: tests for ALL ITEMS WOW // TODO: tests for ALL ITEMS WOW
/* /*

View File

@ -1792,7 +1792,7 @@ async fn test_trade_multiple_individual() {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 1, client: 1,
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810004, item_id: 0x810003,
.. ..
}), }),
.. ..
@ -1801,7 +1801,7 @@ async fn test_trade_multiple_individual() {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 1, client: 1,
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810004, item_id: 0x810003,
.. ..
}), }),
.. ..
@ -1810,7 +1810,7 @@ async fn test_trade_multiple_individual() {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 1, client: 1,
item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810003, item_id: 0x810004,
.. ..
}), }),
.. ..
@ -1819,7 +1819,7 @@ async fn test_trade_multiple_individual() {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 1, client: 1,
item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810003, item_id: 0x810004,
.. ..
}), }),
.. ..
@ -1828,7 +1828,7 @@ async fn test_trade_multiple_individual() {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 0, client: 0,
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810002, item_id: 0x810001,
.. ..
}), }),
.. ..
@ -1837,7 +1837,7 @@ async fn test_trade_multiple_individual() {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 0, client: 0,
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810002, item_id: 0x810001,
.. ..
}), }),
.. ..
@ -1846,7 +1846,7 @@ async fn test_trade_multiple_individual() {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 0, client: 0,
item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810001, item_id: 0x810002,
.. ..
}), }),
.. ..
@ -1855,7 +1855,7 @@ async fn test_trade_multiple_individual() {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 0, client: 0,
item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810001, item_id: 0x810002,
.. ..
}), }),
.. ..
@ -2063,7 +2063,7 @@ async fn test_trade_multiple_stacked() {
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message { assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 1, client: 1,
item_id: 0x810004, item_id: 0x810003,
.. ..
}), }),
.. ..
@ -2071,7 +2071,7 @@ async fn test_trade_multiple_stacked() {
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message { assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 1, client: 1,
item_id: 0x810004, item_id: 0x810003,
.. ..
}), }),
.. ..
@ -2079,7 +2079,7 @@ async fn test_trade_multiple_stacked() {
assert!(matches!(ack[6], (ClientId(1), SendShipPacket::Message(Message { assert!(matches!(ack[6], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 1, client: 1,
item_id: 0x810003, item_id: 0x810004,
.. ..
}), }),
.. ..
@ -2087,7 +2087,7 @@ async fn test_trade_multiple_stacked() {
assert!(matches!(ack[7], (ClientId(2), SendShipPacket::Message(Message { assert!(matches!(ack[7], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 1, client: 1,
item_id: 0x810003, item_id: 0x810004,
.. ..
}), }),
.. ..
@ -2095,7 +2095,7 @@ async fn test_trade_multiple_stacked() {
assert!(matches!(ack[8], (ClientId(1), SendShipPacket::Message(Message { assert!(matches!(ack[8], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 0, client: 0,
item_id: 0x810002, item_id: 0x810001,
.. ..
}), }),
.. ..
@ -2103,7 +2103,7 @@ async fn test_trade_multiple_stacked() {
assert!(matches!(ack[9], (ClientId(2), SendShipPacket::Message(Message { assert!(matches!(ack[9], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 0, client: 0,
item_id: 0x810002, item_id: 0x810001,
.. ..
}), }),
.. ..
@ -2111,7 +2111,7 @@ async fn test_trade_multiple_stacked() {
assert!(matches!(ack[10], (ClientId(1), SendShipPacket::Message(Message { assert!(matches!(ack[10], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 0, client: 0,
item_id: 0x810001, item_id: 0x810002,
.. ..
}), }),
.. ..
@ -2119,7 +2119,7 @@ async fn test_trade_multiple_stacked() {
assert!(matches!(ack[11], (ClientId(2), SendShipPacket::Message(Message { assert!(matches!(ack[11], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem { msg: GameMessage::CreateItem(CreateItem {
client: 0, client: 0,
item_id: 0x810001, item_id: 0x810002,
.. ..
}), }),
.. ..