Merge pull request 'impl grinders, fix mag pbs, fix bank thing, etc' (#128) from use_grinders into master
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #128
This commit is contained in:
commit
effc82d782
@ -11,7 +11,7 @@ photon_blast = "Pilla"
|
|||||||
|
|
||||||
[Surya]
|
[Surya]
|
||||||
feed_table = 3
|
feed_table = 3
|
||||||
photon_blast = "Leilla"
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Vayu]
|
[Vayu]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
@ -19,7 +19,7 @@ photon_blast = "MyllaYoulla"
|
|||||||
|
|
||||||
[Varaha]
|
[Varaha]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
photon_blast = "Leilla"
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Kama]
|
[Kama]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
@ -27,7 +27,7 @@ photon_blast = "Pilla"
|
|||||||
|
|
||||||
[Ushasu]
|
[Ushasu]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
photon_blast = "Leilla"
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Apsaras]
|
[Apsaras]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
@ -35,7 +35,7 @@ photon_blast = "Estlla"
|
|||||||
|
|
||||||
[Kumara]
|
[Kumara]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
photon_blast = "Leilla"
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Kaitabha]
|
[Kaitabha]
|
||||||
feed_table = 4
|
feed_table = 4
|
||||||
@ -55,7 +55,7 @@ photon_blast = "Estlla"
|
|||||||
|
|
||||||
[Rudra]
|
[Rudra]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
photon_blast = "Leilla"
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Marutah]
|
[Marutah]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
@ -63,7 +63,7 @@ photon_blast = "Pilla"
|
|||||||
|
|
||||||
[Yaksa]
|
[Yaksa]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
photon_blast = "Leilla"
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Sita]
|
[Sita]
|
||||||
feed_table = 5
|
feed_table = 5
|
||||||
@ -99,7 +99,7 @@ photon_blast = "Estlla"
|
|||||||
|
|
||||||
[Vritra]
|
[Vritra]
|
||||||
feed_table = 1
|
feed_table = 1
|
||||||
photon_blast = "Golla"
|
photon_blast = "Leilla"
|
||||||
|
|
||||||
[Namuci]
|
[Namuci]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
@ -107,7 +107,7 @@ photon_blast = "MyllaYoulla"
|
|||||||
|
|
||||||
[Sumba]
|
[Sumba]
|
||||||
feed_table = 2
|
feed_table = 2
|
||||||
photon_blast = "Leilla"
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Naga]
|
[Naga]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
@ -144,7 +144,7 @@ photon_blast = "Estlla"
|
|||||||
|
|
||||||
[Naraka]
|
[Naraka]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
photon_blast = "Leilla"
|
photon_blast = "Golla"
|
||||||
|
|
||||||
[Madhu]
|
[Madhu]
|
||||||
feed_table = 6
|
feed_table = 6
|
||||||
|
@ -133,7 +133,7 @@ where
|
|||||||
match pkt_receiver.recv_pkts::<R>().await {
|
match pkt_receiver.recv_pkts::<R>().await {
|
||||||
Ok(pkts) => {
|
Ok(pkts) => {
|
||||||
for pkt in pkts {
|
for pkt in pkts {
|
||||||
trace!("[recv from {:?}] {:#?}", client_id, pkt);
|
info!("[recv from {:?}] {:#?}", client_id, pkt);
|
||||||
match state.handle(client_id, pkt).await {
|
match state.handle(client_id, pkt).await {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
for resp in response {
|
for resp in response {
|
||||||
|
@ -96,7 +96,7 @@ pub trait EntityGateway: Send + Sync {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ impl EntityGateway for InMemoryGatewayTransaction {
|
|||||||
self.working_gateway.use_mag_cell(mag_item_id, mag_cell_id).await
|
self.working_gateway.use_mag_cell(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> {
|
||||||
self.working_gateway.add_weapon_modifier(item_id, modifier).await
|
self.working_gateway.add_weapon_modifier(item_id, modifier).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +213,12 @@ impl EntityGatewayTransaction for InMemoryGatewayTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum InventoryItemElement {
|
||||||
|
Individual(ItemEntityId),
|
||||||
|
Stacked(Vec<ItemEntityId>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct InMemoryGateway {
|
pub struct InMemoryGateway {
|
||||||
users: Arc<Mutex<BTreeMap<UserAccountId, UserAccountEntity>>>,
|
users: Arc<Mutex<BTreeMap<UserAccountId, UserAccountEntity>>>,
|
||||||
@ -221,7 +227,7 @@ pub struct InMemoryGateway {
|
|||||||
character_meseta: Arc<Mutex<BTreeMap<CharacterEntityId, Meseta>>>,
|
character_meseta: Arc<Mutex<BTreeMap<CharacterEntityId, Meseta>>>,
|
||||||
bank_meseta: Arc<Mutex<BTreeMap<(CharacterEntityId, BankName), Meseta>>>,
|
bank_meseta: Arc<Mutex<BTreeMap<(CharacterEntityId, BankName), Meseta>>>,
|
||||||
items: Arc<Mutex<BTreeMap<ItemEntityId, ItemEntity>>>,
|
items: Arc<Mutex<BTreeMap<ItemEntityId, ItemEntity>>>,
|
||||||
inventories: Arc<Mutex<BTreeMap<CharacterEntityId, InventoryEntity>>>,
|
inventories: Arc<Mutex<BTreeMap<CharacterEntityId, Vec<InventoryItemElement>>>>,
|
||||||
banks: Arc<Mutex<BTreeMap<CharacterEntityId, BankEntity>>>,
|
banks: Arc<Mutex<BTreeMap<CharacterEntityId, BankEntity>>>,
|
||||||
equips: Arc<Mutex<BTreeMap<CharacterEntityId, EquippedEntity>>>,
|
equips: Arc<Mutex<BTreeMap<CharacterEntityId, EquippedEntity>>>,
|
||||||
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
||||||
@ -522,11 +528,11 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> {
|
async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: &weapon::WeaponModifier) -> Result<(), GatewayError> {
|
||||||
self.weapon_modifiers.lock().await
|
self.weapon_modifiers.lock().await
|
||||||
.entry(*item_id)
|
.entry(*item_id)
|
||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
.push(modifier);
|
.push(modifier.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,7 +544,29 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
Ok(inventories
|
Ok(inventories
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(id, _)| **id == *char_id)
|
.find(|(id, _)| **id == *char_id)
|
||||||
.map(|(_, inv)| inv.clone())
|
.map(|(_, inv)| {
|
||||||
|
InventoryEntity {
|
||||||
|
items: inv
|
||||||
|
.iter()
|
||||||
|
.map(|inv_item_id| {
|
||||||
|
match inv_item_id {
|
||||||
|
InventoryItemElement::Individual(individual_id) => {
|
||||||
|
InventoryItemEntity::Individual(items.get(individual_id).unwrap().clone())
|
||||||
|
},
|
||||||
|
InventoryItemElement::Stacked(stacked_ids) => {
|
||||||
|
InventoryItemEntity::Stacked(
|
||||||
|
stacked_ids.iter()
|
||||||
|
.map(|stacked_id| {
|
||||||
|
items.get(stacked_id).unwrap().clone()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
})
|
||||||
.map(|inv| apply_modifiers(&items, &weapon_modifiers, &mag_modifiers, inv))
|
.map(|inv| apply_modifiers(&items, &weapon_modifiers, &mag_modifiers, inv))
|
||||||
.unwrap_or_default())
|
.unwrap_or_default())
|
||||||
}
|
}
|
||||||
@ -554,7 +582,25 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
|
|
||||||
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> {
|
||||||
let mut inventories = self.inventories.lock().await;
|
let mut inventories = self.inventories.lock().await;
|
||||||
inventories.insert(*char_id, inventory.clone());
|
inventories.insert(*char_id, inventory.items
|
||||||
|
.iter()
|
||||||
|
.map(|inventory_item| {
|
||||||
|
match inventory_item {
|
||||||
|
InventoryItemEntity::Individual(individual) => {
|
||||||
|
InventoryItemElement::Individual(individual.id)
|
||||||
|
},
|
||||||
|
InventoryItemEntity::Stacked(stacked) => {
|
||||||
|
InventoryItemElement::Stacked(
|
||||||
|
stacked.iter()
|
||||||
|
.map(|stacked| {
|
||||||
|
stacked.id
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ async fn use_mag_cell(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId,
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_weapon_modifier(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError>
|
async fn add_weapon_modifier(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, modifier: &weapon::WeaponModifier) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
sqlx::query("insert into weapon_modifier (weapon, modifier) values ($1, $2);")
|
sqlx::query("insert into weapon_modifier (weapon, modifier) values ($1, $2);")
|
||||||
.bind(item_id.0)
|
.bind(item_id.0)
|
||||||
@ -688,7 +688,7 @@ impl<'t> EntityGateway for PostgresGateway<'t> {
|
|||||||
use_mag_cell(&mut *self.pool.acquire().await?, mag_item_id, mag_cell_id).await
|
use_mag_cell(&mut *self.pool.acquire().await?, 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.pool.acquire().await?, item_id, modifier).await
|
add_weapon_modifier(&mut *self.pool.acquire().await?, item_id, modifier).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,7 +814,7 @@ impl<'c> EntityGateway for PostgresTransaction<'c> {
|
|||||||
use_mag_cell(&mut *self.pgtransaction.lock().await, mag_item_id, mag_cell_id).await
|
use_mag_cell(&mut *self.pgtransaction.lock().await, 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.lock().await, item_id, modifier).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1479,44 +1479,52 @@ impl Weapon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_modifier(&mut self, modifier: &WeaponModifier) {
|
pub fn apply_modifier(&mut self, modifier: &WeaponModifier) {
|
||||||
if let WeaponModifier::Tekked{special, percent, grind} = modifier {
|
match modifier {
|
||||||
match special {
|
WeaponModifier::Tekked{special, percent, grind} => {
|
||||||
TekSpecialModifier::Plus => {
|
match special {
|
||||||
self.special = self.special.map(|special| {
|
TekSpecialModifier::Plus => {
|
||||||
special.rank_up()
|
self.special = self.special.map(|special| {
|
||||||
});
|
special.rank_up()
|
||||||
},
|
});
|
||||||
TekSpecialModifier::Minus => {
|
},
|
||||||
self.special = self.special.map(|special| {
|
TekSpecialModifier::Minus => {
|
||||||
special.rank_down()
|
self.special = self.special.map(|special| {
|
||||||
});
|
special.rank_down()
|
||||||
},
|
});
|
||||||
TekSpecialModifier::Neutral => {
|
},
|
||||||
},
|
TekSpecialModifier::Neutral => {
|
||||||
}
|
},
|
||||||
for i in 0..3 {
|
}
|
||||||
self.attrs[i] = self.attrs[i].map(|mut attr| {
|
for i in 0..3 {
|
||||||
match percent {
|
self.attrs[i] = self.attrs[i].map(|mut attr| {
|
||||||
TekPercentModifier::PlusPlus => {
|
match percent {
|
||||||
attr.value += 10;
|
TekPercentModifier::PlusPlus => {
|
||||||
},
|
attr.value += 10;
|
||||||
TekPercentModifier::Plus => {
|
},
|
||||||
attr.value += 5;
|
TekPercentModifier::Plus => {
|
||||||
},
|
attr.value += 5;
|
||||||
TekPercentModifier::MinusMinus => {
|
},
|
||||||
attr.value -= 10;
|
TekPercentModifier::MinusMinus => {
|
||||||
},
|
attr.value -= 10;
|
||||||
TekPercentModifier::Minus => {
|
},
|
||||||
attr.value -= 5;
|
TekPercentModifier::Minus => {
|
||||||
},
|
attr.value -= 5;
|
||||||
TekPercentModifier::Neutral => {
|
},
|
||||||
|
TekPercentModifier::Neutral => {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
attr
|
||||||
attr
|
});
|
||||||
});
|
}
|
||||||
|
self.grind = std::cmp::max(self.grind as i32 + grind, 0) as u8;
|
||||||
|
self.tekked = true;
|
||||||
|
},
|
||||||
|
WeaponModifier::AddGrind {amount, ..} => {
|
||||||
|
self.grind += *amount as u8;
|
||||||
|
},
|
||||||
|
WeaponModifier::AddPercents {..} => {
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
self.grind = std::cmp::max(self.grind as i32 + grind, 0) as u8;
|
|
||||||
self.tekked = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ 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 std::iter::IntoIterator;
|
||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
use libpso::packet::{ship::Message, messages::GameMessage};
|
use libpso::packet::{ship::Message, messages::GameMessage};
|
||||||
use crate::ship::map::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
@ -97,6 +98,31 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(super) fn remove_item_from_inventory<EG, TR>(
|
||||||
|
character_id: CharacterEntityId,
|
||||||
|
item_id: ClientItemId,
|
||||||
|
amount: u32,
|
||||||
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
|
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItemDetail), anyhow::Error>>
|
||||||
|
where
|
||||||
|
EG: EntityGateway,
|
||||||
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
|
{
|
||||||
|
move |(mut item_state, mut transaction), _| {
|
||||||
|
Box::pin(async move {
|
||||||
|
let mut inventory = item_state.inventory(&character_id).await?;
|
||||||
|
let item = inventory.remove_item(&item_id, amount)
|
||||||
|
.await
|
||||||
|
.ok_or_else(|| ItemStateError::NoInventoryItem(item_id))
|
||||||
|
.with_context(|| format!("{inventory:#?}"))?;
|
||||||
|
|
||||||
|
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
|
||||||
|
item_state.set_inventory(inventory).await;
|
||||||
|
|
||||||
|
Ok(((item_state, transaction), item))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn take_item_from_inventory<EG, TR>(
|
pub(super) fn take_item_from_inventory<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
@ -111,7 +137,9 @@ where
|
|||||||
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?;
|
||||||
let item = inventory.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoInventoryItem(item_id))?;
|
let item = inventory.take_item(&item_id, amount)
|
||||||
|
.await
|
||||||
|
.ok_or_else(|| ItemStateError::NoInventoryItem(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).await;
|
||||||
@ -264,6 +292,7 @@ where
|
|||||||
let mut inventory = item_state.inventory(&character_id).await?;
|
let mut inventory = item_state.inventory(&character_id).await?;
|
||||||
inventory.add_meseta_no_overflow(amount)?;
|
inventory.add_meseta_no_overflow(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;
|
||||||
|
|
||||||
Ok(((item_state, transaction), ()))
|
Ok(((item_state, transaction), ()))
|
||||||
})
|
})
|
||||||
@ -306,7 +335,9 @@ where
|
|||||||
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)
|
||||||
|
.await
|
||||||
|
.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).await;
|
||||||
|
|
||||||
@ -471,7 +502,7 @@ where
|
|||||||
|
|
||||||
pub(super) fn use_consumed_item<EG, TR>(
|
pub(super) fn use_consumed_item<EG, TR>(
|
||||||
character: &CharacterEntity,
|
character: &CharacterEntity,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItemDetail)
|
||||||
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<ApplyItemAction>), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<ApplyItemAction>), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + Clone + 'static,
|
EG: EntityGateway + Clone + 'static,
|
||||||
@ -1006,7 +1037,7 @@ where
|
|||||||
match (&mut inventory_item.item, modifier) {
|
match (&mut inventory_item.item, modifier) {
|
||||||
(InventoryItemDetail::Individual(IndividualItemDetail{entity_id, item: ItemDetail::Weapon(ref mut weapon), ..}), ItemModifier::WeaponModifier(modifier)) => {
|
(InventoryItemDetail::Individual(IndividualItemDetail{entity_id, item: ItemDetail::Weapon(ref mut weapon), ..}), ItemModifier::WeaponModifier(modifier)) => {
|
||||||
weapon.apply_modifier(&modifier);
|
weapon.apply_modifier(&modifier);
|
||||||
transaction.gateway().add_weapon_modifier(entity_id, modifier).await?;
|
transaction.gateway().add_weapon_modifier(entity_id, &modifier).await?;
|
||||||
},
|
},
|
||||||
_ => return Err(ItemStateError::InvalidModifier.into())
|
_ => return Err(ItemStateError::InvalidModifier.into())
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,9 @@ use crate::entity::item::mag::{MagCell, MagCellError};
|
|||||||
use crate::entity::item::tool::{Tool, ToolType};
|
use crate::entity::item::tool::{Tool, ToolType};
|
||||||
use crate::entity::item::tech::TechniqueDisk;
|
use crate::entity::item::tech::TechniqueDisk;
|
||||||
use crate::entity::item::{ItemDetail, ItemEntityId};
|
use crate::entity::item::{ItemDetail, ItemEntityId};
|
||||||
|
use crate::entity::item::weapon::WeaponModifier;
|
||||||
use crate::ship::items::state::ItemStateProxy;
|
use crate::ship::items::state::ItemStateProxy;
|
||||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
use crate::ship::items::inventory::InventoryItemDetail;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@ -34,7 +35,7 @@ pub enum ApplyItemError {
|
|||||||
pub enum ApplyItemAction {
|
pub enum ApplyItemAction {
|
||||||
UpdateCharacter(Box<CharacterEntity>),
|
UpdateCharacter(Box<CharacterEntity>),
|
||||||
CreateItem(ItemDetail),
|
CreateItem(ItemDetail),
|
||||||
//TransformItem,
|
//TransformItem(ItemDetail),
|
||||||
//RemoveItem,
|
//RemoveItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,6 +242,30 @@ fn jack_o_lantern() -> Result<Vec<ApplyItemAction>, anyhow::Error>
|
|||||||
Ok(vec![ApplyItemAction::CreateItem(ItemDetail::Tool(Tool {tool: mag_type}))])
|
Ok(vec![ApplyItemAction::CreateItem(ItemDetail::Tool(Tool {tool: mag_type}))])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn weapon_grind<'a, EG>(item_state: &mut ItemStateProxy,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
character: &mut CharacterEntity,
|
||||||
|
entity_id: ItemEntityId,
|
||||||
|
grind: u32,)
|
||||||
|
-> Result<Vec<ApplyItemAction>, anyhow::Error>
|
||||||
|
where
|
||||||
|
EG: EntityGateway + ?Sized,
|
||||||
|
{
|
||||||
|
let modifier = WeaponModifier::AddGrind {
|
||||||
|
amount: grind,
|
||||||
|
grinder: entity_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut inventory = item_state.inventory(&character.id).await?;
|
||||||
|
let (weapon_entity_id, weapon) = inventory.equipped_weapon_mut()
|
||||||
|
.ok_or(ApplyItemError::ItemNotEquipped)?;
|
||||||
|
weapon.apply_modifier(&modifier);
|
||||||
|
entity_gateway.add_weapon_modifier(&weapon_entity_id, &modifier).await?;
|
||||||
|
item_state.set_inventory(inventory).await;
|
||||||
|
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy,
|
async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy,
|
||||||
entity_gateway: &mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &mut CharacterEntity,
|
character: &mut CharacterEntity,
|
||||||
@ -271,6 +296,9 @@ where
|
|||||||
ToolType::Antidote => Ok(Vec::new()),
|
ToolType::Antidote => Ok(Vec::new()),
|
||||||
ToolType::Antiparalysis => Ok(Vec::new()),
|
ToolType::Antiparalysis => Ok(Vec::new()),
|
||||||
ToolType::TrapVision => Ok(Vec::new()),
|
ToolType::TrapVision => Ok(Vec::new()),
|
||||||
|
ToolType::Monogrinder => weapon_grind(item_state, entity_gateway, character, entity_id, 1).await,
|
||||||
|
ToolType::Digrinder => weapon_grind(item_state, entity_gateway, character, entity_id, 2).await,
|
||||||
|
ToolType::Trigrinder => weapon_grind(item_state, entity_gateway, character, entity_id, 3).await,
|
||||||
ToolType::HuntersReport => Ok(Vec::new()),
|
ToolType::HuntersReport => Ok(Vec::new()),
|
||||||
ToolType::CellOfMag502
|
ToolType::CellOfMag502
|
||||||
| ToolType::CellOfMag213
|
| ToolType::CellOfMag213
|
||||||
@ -328,12 +356,12 @@ where
|
|||||||
pub async fn apply_item<'a, EG>(item_state: &mut ItemStateProxy,
|
pub async fn apply_item<'a, EG>(item_state: &mut ItemStateProxy,
|
||||||
entity_gateway: &mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &mut CharacterEntity,
|
character: &mut CharacterEntity,
|
||||||
item: InventoryItem
|
item: InventoryItemDetail
|
||||||
) -> Result<Vec<ApplyItemAction>, anyhow::Error>
|
) -> Result<Vec<ApplyItemAction>, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + ?Sized + Clone + 'static
|
EG: EntityGateway + ?Sized + Clone + 'static
|
||||||
{
|
{
|
||||||
match item.item {
|
match item {
|
||||||
InventoryItemDetail::Individual(individual_item) => {
|
InventoryItemDetail::Individual(individual_item) => {
|
||||||
match individual_item.item {
|
match individual_item.item {
|
||||||
ItemDetail::Tool(tool) => apply_tool(item_state, entity_gateway, character, individual_item.entity_id, tool.tool).await,
|
ItemDetail::Tool(tool) => apply_tool(item_state, entity_gateway, character, individual_item.entity_id, tool.tool).await,
|
||||||
|
@ -3,6 +3,7 @@ use libpso::character::character;
|
|||||||
use crate::ship::items::ClientItemId;
|
use crate::ship::items::ClientItemId;
|
||||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity, BankName};
|
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity, BankName};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use async_std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::entity::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
use crate::ship::items::state::ItemStateError;
|
use crate::ship::items::state::ItemStateError;
|
||||||
@ -96,18 +97,26 @@ impl Bank {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct BankState {
|
pub struct BankState {
|
||||||
pub character_id: CharacterEntityId,
|
pub character_id: CharacterEntityId,
|
||||||
pub item_id_counter: u32,
|
pub item_id_counter: Arc<Mutex<u32>>,
|
||||||
pub name: BankName,
|
pub name: BankName,
|
||||||
pub bank: Bank,
|
pub bank: Bank,
|
||||||
pub meseta: Meseta,
|
pub meseta: Meseta,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn new_item_id(item_id_counter: &Arc<Mutex<u32>>) -> ClientItemId {
|
||||||
|
let mut item_id_counter = item_id_counter.lock().await;
|
||||||
|
let item_id = *item_id_counter;
|
||||||
|
*item_id_counter += 1;
|
||||||
|
|
||||||
|
ClientItemId(item_id)
|
||||||
|
}
|
||||||
|
|
||||||
impl BankState {
|
impl BankState {
|
||||||
pub fn new(character_id: CharacterEntityId, name: BankName, mut bank: Bank, meseta: Meseta) -> BankState {
|
pub fn new(character_id: CharacterEntityId, name: BankName, mut bank: Bank, meseta: Meseta) -> BankState {
|
||||||
bank.0.sort();
|
bank.0.sort();
|
||||||
BankState {
|
BankState {
|
||||||
character_id,
|
character_id,
|
||||||
item_id_counter: 0,
|
item_id_counter: Arc::new(Mutex::new(0)),
|
||||||
name,
|
name,
|
||||||
bank,
|
bank,
|
||||||
meseta,
|
meseta,
|
||||||
@ -118,11 +127,14 @@ impl BankState {
|
|||||||
self.bank.0.len()
|
self.bank.0.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize_item_ids(&mut self, base_item_id: u32) {
|
pub async fn initialize_item_ids(&mut self, base_item_id: Arc<Mutex<u32>>) {
|
||||||
|
self.item_id_counter = base_item_id;
|
||||||
|
let mut bitem_id = self.item_id_counter.lock().await;
|
||||||
for (i, item) in self.bank.0.iter_mut().enumerate() {
|
for (i, item) in self.bank.0.iter_mut().enumerate() {
|
||||||
item.item_id = ClientItemId(base_item_id + i as u32);
|
item.item_id = ClientItemId(*bitem_id + i as u32);
|
||||||
}
|
}
|
||||||
self.item_id_counter = base_item_id + self.bank.0.len() as u32;
|
|
||||||
|
*bitem_id += self.bank.0.len() as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_meseta(&mut self, amount: u32) -> Result<(), anyhow::Error> {
|
pub fn add_meseta(&mut self, amount: u32) -> Result<(), anyhow::Error> {
|
||||||
@ -191,7 +203,7 @@ impl BankState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<BankItem> {
|
pub async fn take_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<BankItem> {
|
||||||
let idx = self.bank.0
|
let idx = self.bank.0
|
||||||
.iter()
|
.iter()
|
||||||
.position(|i| i.item_id == *item_id)?;
|
.position(|i| i.item_id == *item_id)?;
|
||||||
@ -211,9 +223,8 @@ impl BankState {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect();
|
let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect();
|
||||||
self.item_id_counter += 1;
|
|
||||||
Some(BankItem {
|
Some(BankItem {
|
||||||
item_id: ClientItemId(self.item_id_counter),
|
item_id: new_item_id(&self.item_id_counter).await,
|
||||||
item: BankItemDetail::Stacked(StackedItemDetail {
|
item: BankItemDetail::Stacked(StackedItemDetail {
|
||||||
entity_ids,
|
entity_ids,
|
||||||
tool: stacked_item.tool,
|
tool: stacked_item.tool,
|
||||||
|
@ -3,10 +3,12 @@ use libpso::character::character;
|
|||||||
use crate::ship::items::ClientItemId;
|
use crate::ship::items::ClientItemId;
|
||||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity};
|
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use async_std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::entity::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
use crate::entity::item::tool::ToolType;
|
use crate::entity::item::tool::ToolType;
|
||||||
use crate::entity::item::mag::Mag;
|
use crate::entity::item::mag::Mag;
|
||||||
|
use crate::entity::item::weapon::Weapon;
|
||||||
use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem};
|
use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem};
|
||||||
use crate::ship::items::state::ItemStateError;
|
use crate::ship::items::state::ItemStateError;
|
||||||
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||||
@ -116,22 +118,12 @@ impl InventoryItemDetail {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct InventoryItem {
|
|
||||||
pub item_id: ClientItemId,
|
|
||||||
pub item: InventoryItemDetail,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InventoryItem {
|
|
||||||
pub async fn with_entity_id<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, anyhow::Error>
|
pub async fn with_entity_id<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, anyhow::Error>
|
||||||
where
|
where
|
||||||
F: FnMut(T, ItemEntityId) -> Fut,
|
F: FnMut(T, ItemEntityId) -> Fut,
|
||||||
Fut: Future<Output=Result<T, anyhow::Error>>,
|
Fut: Future<Output=Result<T, anyhow::Error>>,
|
||||||
{
|
{
|
||||||
match &self.item {
|
match &self {
|
||||||
InventoryItemDetail::Individual(individual_item) => {
|
InventoryItemDetail::Individual(individual_item) => {
|
||||||
param = func(param, individual_item.entity_id).await?;
|
param = func(param, individual_item.entity_id).await?;
|
||||||
},
|
},
|
||||||
@ -144,6 +136,23 @@ impl InventoryItem {
|
|||||||
|
|
||||||
Ok(param)
|
Ok(param)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct InventoryItem {
|
||||||
|
pub item_id: ClientItemId,
|
||||||
|
pub item: InventoryItemDetail,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InventoryItem {
|
||||||
|
pub async fn with_entity_id<F, Fut, T>(&self, param: T, func: F) -> Result<T, anyhow::Error>
|
||||||
|
where
|
||||||
|
F: FnMut(T, ItemEntityId) -> Fut,
|
||||||
|
Fut: Future<Output=Result<T, anyhow::Error>>,
|
||||||
|
{
|
||||||
|
self.item.with_entity_id(param, func).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn with_mag<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, anyhow::Error>
|
pub async fn with_mag<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, anyhow::Error>
|
||||||
where
|
where
|
||||||
@ -182,23 +191,38 @@ pub enum InventoryError {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct InventoryState {
|
pub struct InventoryState {
|
||||||
pub character_id: CharacterEntityId,
|
pub character_id: CharacterEntityId,
|
||||||
pub item_id_counter: u32,
|
pub item_id_counter: Arc<Mutex<u32>>,
|
||||||
pub inventory: Inventory,
|
pub inventory: Inventory,
|
||||||
pub equipped: EquippedEntity,
|
pub equipped: EquippedEntity,
|
||||||
pub meseta: Meseta,
|
pub meseta: Meseta,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn new_item_id(item_id_counter: &Arc<Mutex<u32>>) -> ClientItemId {
|
||||||
|
let mut item_id_counter = item_id_counter.lock().await;
|
||||||
|
let item_id = *item_id_counter;
|
||||||
|
*item_id_counter += 1;
|
||||||
|
|
||||||
|
ClientItemId(item_id)
|
||||||
|
}
|
||||||
|
|
||||||
impl InventoryState {
|
impl InventoryState {
|
||||||
pub fn initialize_item_ids(&mut self, base_item_id: u32) {
|
pub async fn initialize_item_ids(&mut self, base_item_id: Arc<Mutex<u32>>) {
|
||||||
|
self.item_id_counter = base_item_id;
|
||||||
|
let mut bitem_id = self.item_id_counter.lock().await;
|
||||||
|
|
||||||
for (i, item) in self.inventory.0.iter_mut().enumerate() {
|
for (i, item) in self.inventory.0.iter_mut().enumerate() {
|
||||||
item.item_id = ClientItemId(base_item_id + i as u32);
|
item.item_id = ClientItemId(*bitem_id + i as u32);
|
||||||
}
|
}
|
||||||
self.item_id_counter = base_item_id + self.inventory.0.len() as u32 + 1;
|
|
||||||
|
*bitem_id += self.inventory.0.len() as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_item_id(&mut self) -> ClientItemId {
|
pub async fn new_item_id(&mut self) -> ClientItemId {
|
||||||
self.item_id_counter += 1;
|
let mut item_id_counter = self.item_id_counter.lock().await;
|
||||||
ClientItemId(self.item_id_counter)
|
let item_id = *item_id_counter;
|
||||||
|
*item_id_counter += 1;
|
||||||
|
|
||||||
|
ClientItemId(item_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
@ -325,7 +349,36 @@ impl InventoryState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<InventoryItem> {
|
pub async fn remove_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<InventoryItemDetail> {
|
||||||
|
let idx = self.inventory.0
|
||||||
|
.iter()
|
||||||
|
.position(|i| i.item_id == *item_id)?;
|
||||||
|
match &mut self.inventory.0[idx].item {
|
||||||
|
InventoryItemDetail::Individual(_individual_item) => {
|
||||||
|
Some(self.inventory.0.remove(idx).item)
|
||||||
|
},
|
||||||
|
InventoryItemDetail::Stacked(stacked_item) => {
|
||||||
|
let remove_all = (amount == 0) || match stacked_item.entity_ids.len().cmp(&(amount as usize)) {
|
||||||
|
Ordering::Equal => true,
|
||||||
|
Ordering::Greater => false,
|
||||||
|
Ordering::Less => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if remove_all {
|
||||||
|
Some(self.inventory.0.remove(idx).item)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect();
|
||||||
|
Some(InventoryItemDetail::Stacked(StackedItemDetail {
|
||||||
|
entity_ids,
|
||||||
|
tool: stacked_item.tool,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn take_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<InventoryItem> {
|
||||||
let idx = self.inventory.0
|
let idx = self.inventory.0
|
||||||
.iter()
|
.iter()
|
||||||
.position(|i| i.item_id == *item_id)?;
|
.position(|i| i.item_id == *item_id)?;
|
||||||
@ -345,9 +398,8 @@ impl InventoryState {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect();
|
let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect();
|
||||||
self.item_id_counter += 1;
|
|
||||||
Some(InventoryItem {
|
Some(InventoryItem {
|
||||||
item_id: ClientItemId(self.item_id_counter),
|
item_id: new_item_id(&self.item_id_counter).await,
|
||||||
item: InventoryItemDetail::Stacked(StackedItemDetail {
|
item: InventoryItemDetail::Stacked(StackedItemDetail {
|
||||||
entity_ids,
|
entity_ids,
|
||||||
tool: stacked_item.tool,
|
tool: stacked_item.tool,
|
||||||
@ -453,6 +505,18 @@ impl InventoryState {
|
|||||||
.find(|(entity_id, _)| *entity_id == mag_id)
|
.find(|(entity_id, _)| *entity_id == mag_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn equipped_weapon_mut(&mut self) -> Option<(ItemEntityId, &mut Weapon)> {
|
||||||
|
let weapon_id = self.equipped.weapon?;
|
||||||
|
self.inventory.0
|
||||||
|
.iter_mut()
|
||||||
|
.filter_map(|i| {
|
||||||
|
let individual = i.item.as_individual_mut()?;
|
||||||
|
let entity_id = individual.entity_id;
|
||||||
|
Some((entity_id, individual.as_weapon_mut()?))
|
||||||
|
})
|
||||||
|
.find(|(entity_id, _)| *entity_id == weapon_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sort(&mut self, item_ids: &[ClientItemId]) {
|
pub fn sort(&mut self, item_ids: &[ClientItemId]) {
|
||||||
self.inventory.0.sort_by(|a, b| {
|
self.inventory.0.sort_by(|a, b| {
|
||||||
let a_index = item_ids.iter().position(|item_id| *item_id == a.item_id);
|
let a_index = item_ids.iter().position(|item_id| *item_id == a.item_id);
|
||||||
|
@ -91,6 +91,14 @@ impl IndividualItemDetail {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_weapon_mut(&mut self) -> Option<&mut Weapon> {
|
||||||
|
match &mut self.item {
|
||||||
|
ItemDetail::Weapon(weapon) => Some(weapon),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn as_client_bytes(&self) -> [u8; 16] {
|
pub fn as_client_bytes(&self) -> [u8; 16] {
|
||||||
match &self.item {
|
match &self.item {
|
||||||
ItemDetail::Weapon(w) => w.as_bytes(),
|
ItemDetail::Weapon(w) => w.as_bytes(),
|
||||||
@ -126,15 +134,40 @@ pub enum AddItemResult {
|
|||||||
Meseta,
|
Meseta,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct RoomGemItemIdCounter {
|
||||||
|
inventory: [Arc<Mutex<u32>>; 4],
|
||||||
|
bank: [Arc<Mutex<u32>>; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RoomGemItemIdCounter {
|
||||||
|
fn default() -> RoomGemItemIdCounter {
|
||||||
|
RoomGemItemIdCounter {
|
||||||
|
inventory: core::array::from_fn(|gem| Arc::new(Mutex::new(((gem as u32) << 21) | 0x10000))),
|
||||||
|
bank: core::array::from_fn(|gem| Arc::new(Mutex::new(((gem as u32) << 21) | 0x20000))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoomGemItemIdCounter {
|
||||||
|
fn inventory(&self, area_client: &AreaClient) -> Arc<Mutex<u32>> {
|
||||||
|
self.inventory[area_client.local_client.id() as usize].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bank(&self, area_client: &AreaClient) -> Arc<Mutex<u32>> {
|
||||||
|
self.bank[area_client.local_client.id() as usize].clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
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>>>>,
|
||||||
|
|
||||||
character_room: Arc<RwLock<HashMap<CharacterEntityId, RoomId>>>,
|
character_room: Arc<RwLock<HashMap<CharacterEntityId, RoomId>>>,
|
||||||
character_floor: Arc<RwLock<HashMap<CharacterEntityId, RwLock<LocalFloor>>>>,
|
character_floor: Arc<RwLock<HashMap<CharacterEntityId, RwLock<LocalFloor>>>>,
|
||||||
room_floor: Arc<RwLock<HashMap<RoomId, RwLock<SharedFloor>>>>,
|
room_floor: Arc<RwLock<HashMap<RoomId, RwLock<SharedFloor>>>>,
|
||||||
|
room_gem_item_ids: Arc<RwLock<HashMap<RoomId, RoomGemItemIdCounter>>>,
|
||||||
|
|
||||||
room_item_id_counter: Arc<RwLock<u32>>,
|
room_item_id_counter: Arc<RwLock<u32>>,
|
||||||
}
|
}
|
||||||
@ -147,6 +180,7 @@ impl Default for ItemState {
|
|||||||
character_room: Arc::new(RwLock::new(HashMap::new())),
|
character_room: Arc::new(RwLock::new(HashMap::new())),
|
||||||
character_floor: Arc::new(RwLock::new(HashMap::new())),
|
character_floor: Arc::new(RwLock::new(HashMap::new())),
|
||||||
room_floor: Arc::new(RwLock::new(HashMap::new())),
|
room_floor: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
room_gem_item_ids: Arc::new(RwLock::new(HashMap::new())),
|
||||||
room_item_id_counter: Arc::new(RwLock::new(0x00810000)),
|
room_item_id_counter: Arc::new(RwLock::new(0x00810000)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,12 +256,12 @@ impl ItemState {
|
|||||||
let character_meseta = entity_gateway.get_character_meseta(&character.id).await?;
|
let character_meseta = entity_gateway.get_character_meseta(&character.id).await?;
|
||||||
let inventory_state = InventoryState {
|
let inventory_state = InventoryState {
|
||||||
character_id: character.id,
|
character_id: character.id,
|
||||||
item_id_counter: 0,
|
item_id_counter: Arc::new(Mutex::new(0)),
|
||||||
inventory: Inventory::new(inventory_items),
|
inventory: Inventory::new(inventory_items),
|
||||||
equipped,
|
equipped,
|
||||||
meseta: character_meseta,
|
meseta: character_meseta,
|
||||||
};
|
};
|
||||||
|
|
||||||
let bank_items = join_all(
|
let bank_items = join_all(
|
||||||
bank.items.into_iter()
|
bank.items.into_iter()
|
||||||
.map(|item| {
|
.map(|item| {
|
||||||
@ -263,7 +297,7 @@ impl ItemState {
|
|||||||
.await
|
.await
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Result<Vec<_>, anyhow::Error>>()?;
|
.collect::<Result<Vec<_>, anyhow::Error>>()?;
|
||||||
|
|
||||||
let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?;
|
let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?;
|
||||||
let bank_state = BankState::new(character.id, BankName("".into()), Bank::new(bank_items), bank_meseta);
|
let bank_state = BankState::new(character.id, BankName("".into()), Bank::new(bank_items), bank_meseta);
|
||||||
|
|
||||||
@ -279,7 +313,13 @@ impl ItemState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) {
|
pub async fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) {
|
||||||
let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000;
|
let mut base_item_ids = self.room_gem_item_ids
|
||||||
|
.write()
|
||||||
|
.await;
|
||||||
|
let base_item_ids = base_item_ids
|
||||||
|
.entry(room_id)
|
||||||
|
.or_insert_with(RoomGemItemIdCounter::default);
|
||||||
|
|
||||||
self.character_inventory
|
self.character_inventory
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
@ -287,8 +327,8 @@ impl ItemState {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.write()
|
.write()
|
||||||
.await
|
.await
|
||||||
.initialize_item_ids(base_inventory_id);
|
.initialize_item_ids(base_item_ids.inventory(&area_client).clone())
|
||||||
let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000;
|
.await;
|
||||||
self.character_bank
|
self.character_bank
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
@ -296,7 +336,8 @@ impl ItemState {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.write()
|
.write()
|
||||||
.await
|
.await
|
||||||
.initialize_item_ids(base_bank_id);
|
.initialize_item_ids(base_item_ids.bank(&area_client))
|
||||||
|
.await;
|
||||||
self.character_room
|
self.character_room
|
||||||
.write()
|
.write()
|
||||||
.await
|
.await
|
||||||
@ -478,16 +519,22 @@ impl ItemStateProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result<FloorState, anyhow::Error> {
|
pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result<FloorState, anyhow::Error> {
|
||||||
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)
|
||||||
|
.ok_or_else(|| anyhow::Error::from(ItemStateError::NoCharacter(*character_id)))
|
||||||
|
.with_context(|| format!("character {character_id}\nrooms: {:#?}", self.item_state.character_room))?;
|
||||||
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, &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?,
|
.with_context(|| format!("no local_floor state: {character_id:?} {:#?}\nproxy: {:#?}", self.item_state.character_floor, self.proxied_state.character_floor))?,
|
||||||
|
shared: get_or_clone(&self.item_state.room_floor, &self.proxied_state.room_floor, room_id, ItemStateError::NoRoom).await
|
||||||
|
.with_context(|| format!("no share_floor state: {character_id:?} {:#?}\nproxy: {:#?}", self.item_state.room_floor, self.proxied_state.room_floor))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
.ok_or_else(|| anyhow::Error::from(ItemStateError::NoCharacter(floor.character_id)))
|
||||||
|
.with_context(|| format!("character {}\nrooms: {:#?}", floor.character_id, self.item_state.character_room)).unwrap();
|
||||||
self.proxied_state.character_floor.lock().await.insert(floor.character_id, floor.local);
|
self.proxied_state.character_floor.lock().await.insert(floor.character_id, floor.local);
|
||||||
self.proxied_state.room_floor.lock().await.insert(room_id, floor.shared);
|
self.proxied_state.room_floor.lock().await.insert(room_id, floor.shared);
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,7 @@ where
|
|||||||
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.clone());
|
||||||
let ((item_state_proxy, transaction), (pkts, new_character)) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), (pkts, new_character)) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
.act(actions::remove_item_from_inventory(character.id, *item_id, amount))
|
||||||
.act(actions::use_consumed_item(character))
|
.act(actions::use_consumed_item(character))
|
||||||
.act(actions::fork(
|
.act(actions::fork(
|
||||||
actions::foreach(actions::apply_item_action_packets(character.id, area_client)),
|
actions::foreach(actions::apply_item_action_packets(character.id, area_client)),
|
||||||
|
@ -489,7 +489,6 @@ impl Blocks {
|
|||||||
.get_mut(block)
|
.get_mut(block)
|
||||||
.ok_or_else(|| ShipError::InvalidBlock(block).into())
|
.ok_or_else(|| ShipError::InvalidBlock(block).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1072,7 +1072,7 @@ async fn test_withdraw_partial_stacked_item() {
|
|||||||
|
|
||||||
assert!(packets.len() == 2);
|
assert!(packets.len() == 2);
|
||||||
assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::CreateItem(create_item)}))
|
assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::CreateItem(create_item)}))
|
||||||
if create_item.item_id == 0x20002
|
if create_item.item_id == 0x20001
|
||||||
));
|
));
|
||||||
|
|
||||||
let bank_items = entity_gateway.get_character_bank(&char1.id, &item::BankName("".into())).await.unwrap();
|
let bank_items = entity_gateway.get_character_bank(&char1.id, &item::BankName("".into())).await.unwrap();
|
||||||
@ -1579,3 +1579,57 @@ async fn test_withdraw_meseta_inventory_is_maxed() {
|
|||||||
assert!(c1_meseta.0 == 999999);
|
assert!(c1_meseta.0 == 999999);
|
||||||
assert!(c1_bank_meseta.0 == 300);
|
assert!(c1_bank_meseta.0 == 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_withdraw_meseta_and_buy_a_few_monomates_with_it() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::default();
|
||||||
|
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
||||||
|
entity_gateway.set_character_meseta(&char1.id, item::Meseta(100)).await.unwrap();
|
||||||
|
entity_gateway.set_bank_meseta(&char1.id, &item::BankName("".into()), item::Meseta(300)).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::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
unknown: 0,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0xFFFFFFFF,
|
||||||
|
action: 1,
|
||||||
|
item_amount: 0,
|
||||||
|
meseta_amount: 60,
|
||||||
|
unknown: 0,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest {
|
||||||
|
client: 255,
|
||||||
|
target: 255,
|
||||||
|
shop_type: 0,
|
||||||
|
})))).await.unwrap();
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem {
|
||||||
|
client: 255,
|
||||||
|
target: 255,
|
||||||
|
item_id: 0x10000,
|
||||||
|
shop_type: 0,
|
||||||
|
shop_index: 0,
|
||||||
|
amount: 3,
|
||||||
|
unknown1: 0,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
//let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap();
|
||||||
|
//let c1_bank_meseta = entity_gateway.get_bank_meseta(&char1.id, &item::BankName("".into())).await.unwrap();
|
||||||
|
//assert!(c1_meseta.0 == 23);
|
||||||
|
//assert!(c1_bank_meseta.0 == 277);
|
||||||
|
}
|
||||||
|
373
tests/test_item_id.rs
Normal file
373
tests/test_item_id.rs
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
use elseware::common::serverstate::{ClientId, ServerState};
|
||||||
|
use elseware::entity::gateway::{EntityGateway, InMemoryGateway};
|
||||||
|
use elseware::entity::item;
|
||||||
|
use elseware::ship::ship::{ShipServerState, RecvShipPacket};
|
||||||
|
use elseware::entity::character::TechLevel;
|
||||||
|
//use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType};
|
||||||
|
|
||||||
|
use libpso::packet::ship::*;
|
||||||
|
use libpso::packet::messages::*;
|
||||||
|
|
||||||
|
#[path = "common.rs"]
|
||||||
|
mod common;
|
||||||
|
use common::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_use_monomate_after_leaving_and_rejoining_room() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::default();
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
||||||
|
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
|
||||||
|
|
||||||
|
let mut p1_items = Vec::new();
|
||||||
|
for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() {
|
||||||
|
let mut item = Vec::new();
|
||||||
|
for _ in 0..2usize {
|
||||||
|
item.push(entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: tool
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap());
|
||||||
|
}
|
||||||
|
p1_items.push(item::InventoryItemEntity::Stacked(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap();
|
||||||
|
|
||||||
|
let mut p2_items = Vec::new();
|
||||||
|
for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() {
|
||||||
|
let mut item = Vec::new();
|
||||||
|
for _ in 0..2usize {
|
||||||
|
item.push(entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: tool
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap());
|
||||||
|
}
|
||||||
|
p2_items.push(item::InventoryItemEntity::Stacked(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_items)).await.unwrap();
|
||||||
|
|
||||||
|
let mut ship = Box::new(ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build());
|
||||||
|
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
||||||
|
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
|
||||||
|
join_lobby(&mut ship, ClientId(1)).await;
|
||||||
|
join_lobby(&mut ship, ClientId(2)).await;
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
|
||||||
|
leave_room(&mut ship, ClientId(1)).await;
|
||||||
|
join_room(&mut ship, ClientId(1), 0).await;
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10003,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x210006,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
|
||||||
|
assert_eq!(inventory_items.items.len(), 2);
|
||||||
|
inventory_items.items[0].with_stacked(|items| {
|
||||||
|
assert_eq!(items.len(), 2)
|
||||||
|
}).unwrap();
|
||||||
|
inventory_items.items[1].with_stacked(|items| {
|
||||||
|
assert_eq!(items.len(), 1)
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
let inventory_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
|
||||||
|
assert_eq!(inventory_items.items.len(), 2);
|
||||||
|
inventory_items.items[0].with_stacked(|items| {
|
||||||
|
assert_eq!(items.len(), 1)
|
||||||
|
}).unwrap();
|
||||||
|
inventory_items.items[1].with_stacked(|items| {
|
||||||
|
assert_eq!(items.len(), 2)
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::default();
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
||||||
|
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
|
||||||
|
let (_user3, char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).await;
|
||||||
|
|
||||||
|
let mut p1_items = Vec::new();
|
||||||
|
for tool in vec![item::tool::ToolType::Monofluid, item::tool::ToolType::Difluid, item::tool::ToolType::Trifluid].into_iter() {
|
||||||
|
let mut item = Vec::new();
|
||||||
|
for _ in 0..2usize {
|
||||||
|
item.push(entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: tool
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap());
|
||||||
|
}
|
||||||
|
p1_items.push(item::InventoryItemEntity::Stacked(item));
|
||||||
|
}
|
||||||
|
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap();
|
||||||
|
|
||||||
|
let mut p2_items = Vec::new();
|
||||||
|
for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() {
|
||||||
|
let mut item = Vec::new();
|
||||||
|
for _ in 0..6usize {
|
||||||
|
item.push(entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: tool
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap());
|
||||||
|
}
|
||||||
|
p2_items.push(item::InventoryItemEntity::Stacked(item));
|
||||||
|
}
|
||||||
|
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_items)).await.unwrap();
|
||||||
|
|
||||||
|
let mut p3_items = Vec::new();
|
||||||
|
for _ in 0..5usize {
|
||||||
|
p3_items.push(
|
||||||
|
item::InventoryItemEntity::Individual(
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Weapon(
|
||||||
|
item::weapon::Weapon {
|
||||||
|
weapon: item::weapon::WeaponType::Saber,
|
||||||
|
grind: 0,
|
||||||
|
special: None,
|
||||||
|
attrs: [None, None, None],
|
||||||
|
tekked: true,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
entity_gateway.set_character_inventory(&char3.id, &item::InventoryEntity::new(p3_items)).await.unwrap();
|
||||||
|
|
||||||
|
let mut ship = Box::new(ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build());
|
||||||
|
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
||||||
|
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
|
||||||
|
log_in_char(&mut ship, ClientId(3), "a3", "a").await;
|
||||||
|
join_lobby(&mut ship, ClientId(1)).await;
|
||||||
|
join_lobby(&mut ship, ClientId(2)).await;
|
||||||
|
join_lobby(&mut ship, ClientId(3)).await;
|
||||||
|
|
||||||
|
// so lets trace the item_ids here as it is dumb:
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x010003
|
||||||
|
// g2 : ; 0x210000
|
||||||
|
// g3 : ; 0x410000
|
||||||
|
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x10003
|
||||||
|
// g2/p2: 0x210000 0x210001 ; 0x210002
|
||||||
|
// g3 : ; 0x410000
|
||||||
|
|
||||||
|
ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x210000,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
join_room(&mut ship, ClientId(3), 0).await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x010003
|
||||||
|
// g2/p2: 0x210000 0x210001 ; 0x210002
|
||||||
|
// g3/p3: 0x410000 0x410001 0x410002 0x410003 0x0410004 ; 0x410005
|
||||||
|
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x010003
|
||||||
|
// g2 : ; 0x210002
|
||||||
|
// g3/p3: 0x410000 0x410001 0x410002 0x410003 0x410004 ; 0x410005
|
||||||
|
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x010003
|
||||||
|
// g2/p2: 0x210002 0x210003 ; 0x210004
|
||||||
|
// g3/p3: 0x410000 0x410001 0x410002 0x410003 0x410004 ; 0x410005
|
||||||
|
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x010003
|
||||||
|
// g2 : ; 0x210004
|
||||||
|
// g3/p3: 0x410000 0x410001 0x410002 0x410003 0x410004 ; 0x410005
|
||||||
|
|
||||||
|
leave_room(&mut ship, ClientId(3)).await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x010003
|
||||||
|
// g2 : ; 0x210004
|
||||||
|
// g3 : ; 0x410005
|
||||||
|
|
||||||
|
join_room(&mut ship, ClientId(3), 0).await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x010003
|
||||||
|
// g2/p3: 0x210004 0x210005 0x210006 0x210007 0x210008 ; 0x210009
|
||||||
|
// g3 : ; 0x410007
|
||||||
|
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
// g1/p1: 0x010000 0x010001 0x010002 ; 0x010003
|
||||||
|
// g2/p3: 0x210004 0x210005 0x210006 0x210007 0x210008 ; 0x210009
|
||||||
|
// g3/p2: 0x410005 0x410006 ; 0x410007
|
||||||
|
|
||||||
|
ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x410005,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
leave_room(&mut ship, ClientId(1)).await;
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
// g1 : ; 0x010003
|
||||||
|
// g2/p3: 0x210004 0x210005 0x210006 0x210007 0x210008 ; 0x210009
|
||||||
|
// g3 : ; 0x410007
|
||||||
|
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
// g1/p2: 0x010003 0x010004 ; 0x010005
|
||||||
|
// g2/p3: 0x210004 0x210005 0x210006 0x210007 0x210008 ; 0x210009
|
||||||
|
// g3 : ; 0x410007
|
||||||
|
|
||||||
|
join_room(&mut ship, ClientId(1), 0).await;
|
||||||
|
// g1/p2: 0x010003 0x010004 ; 0x010005
|
||||||
|
// g2/p3: 0x210004 0x210005 0x210006 0x210007 0x210008 ; 0x210009
|
||||||
|
// g3/p1: 0x410008 0x410009 0x41000A ; 0x41000B
|
||||||
|
|
||||||
|
ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x010003,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
leave_room(&mut ship, ClientId(3)).await;
|
||||||
|
join_room(&mut ship, ClientId(3), 0).await;
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
// g1/p3: 0x010005 0x010006 0x010007 0x010008 0x010009 ; 0x010009
|
||||||
|
// g2/p2: 0x210009 0x21000A ; 0x21000B
|
||||||
|
// g3/p1: 0x410008 0x410009 0x41000A ; 0x41000B
|
||||||
|
|
||||||
|
ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x210009,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
join_room(&mut ship, ClientId(2), 0).await;
|
||||||
|
// g1/p3: 0x010005 0x010006 0x010007 0x010008 0x010009 ; 0x010009
|
||||||
|
// g2/p2: 0x21000B 0x21000C ; 0x21000D
|
||||||
|
// g3/p1: 0x410008 0x410009 0x401000A ; 0x41000B
|
||||||
|
|
||||||
|
ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x21000B,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
let inventory_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
|
||||||
|
assert_eq!(inventory_items.items.len(), 2);
|
||||||
|
inventory_items.items[0].with_stacked(|items| {
|
||||||
|
assert_eq!(items.len(), 1)
|
||||||
|
}).unwrap();
|
||||||
|
inventory_items.items[1].with_stacked(|items| {
|
||||||
|
assert_eq!(items.len(), 6)
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_depositing_a_full_stack_then_withdrawing_part() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::default();
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
||||||
|
|
||||||
|
let mut p1_items = Vec::new();
|
||||||
|
for tool in vec![item::tool::ToolType::Monofluid, item::tool::ToolType::Difluid, item::tool::ToolType::Trifluid].into_iter() {
|
||||||
|
let mut item = Vec::new();
|
||||||
|
for _ in 0..5usize {
|
||||||
|
item.push(entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: tool
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap());
|
||||||
|
}
|
||||||
|
p1_items.push(item::InventoryItemEntity::Stacked(item));
|
||||||
|
}
|
||||||
|
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap();
|
||||||
|
|
||||||
|
let mut monomates = Vec::new();
|
||||||
|
for _ in 0..3usize {
|
||||||
|
monomates.push(entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: item::tool::ToolType::Monomate,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap());
|
||||||
|
}
|
||||||
|
entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankName("".into())).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::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
unknown: 0,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10001,
|
||||||
|
action: 0,
|
||||||
|
item_amount: 5,
|
||||||
|
meseta_amount: 0,
|
||||||
|
unknown: 0,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10001,
|
||||||
|
action: 1,
|
||||||
|
item_amount: 3,
|
||||||
|
meseta_amount: 0,
|
||||||
|
unknown: 0,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x20001,
|
||||||
|
})))).await.unwrap();
|
||||||
|
}
|
@ -734,7 +734,7 @@ async fn test_player_drops_partial_stack_and_other_player_picks_it_up() {
|
|||||||
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem {
|
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
target: 0,
|
target: 0,
|
||||||
item_id: 0x10003,
|
item_id: 0x10001,
|
||||||
map_area: 0,
|
map_area: 0,
|
||||||
unknown: [0; 3]
|
unknown: [0; 3]
|
||||||
})))).await.unwrap();
|
})))).await.unwrap();
|
||||||
|
@ -312,22 +312,6 @@ async fn test_use_barta_1() {
|
|||||||
|
|
||||||
let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
||||||
|
|
||||||
/*
|
|
||||||
let mut p1_inv = Vec::new();
|
|
||||||
for tool in vec![item::tool::ToolType::PowerMaterial, item::tool::ToolType::].into_iter() {
|
|
||||||
let mut item = Vec::new();
|
|
||||||
for _ in 0..5usize {
|
|
||||||
item.push(entity_gateway.create_item(
|
|
||||||
item::NewItemEntity {
|
|
||||||
item: item::ItemDetail::Tool(
|
|
||||||
item::tool::Tool {
|
|
||||||
tool: tool
|
|
||||||
}
|
|
||||||
),
|
|
||||||
}).await.unwrap());
|
|
||||||
}
|
|
||||||
p1_inv.push(item::InventoryItemEntity::Stacked(item));
|
|
||||||
}*/
|
|
||||||
let inv = vec![
|
let inv = vec![
|
||||||
entity_gateway.create_item(
|
entity_gateway.create_item(
|
||||||
item::NewItemEntity {
|
item::NewItemEntity {
|
||||||
@ -391,6 +375,77 @@ async fn test_use_barta_1() {
|
|||||||
assert!(char.techs.techs.get(&item::tech::Technique::Barta).is_none());
|
assert!(char.techs.techs.get(&item::tech::Technique::Barta).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_use_monogrinder() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::default();
|
||||||
|
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
||||||
|
|
||||||
|
let saber = entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Weapon(
|
||||||
|
item::weapon::Weapon {
|
||||||
|
weapon: item::weapon::WeaponType::Saber,
|
||||||
|
grind: 0,
|
||||||
|
special: None,
|
||||||
|
attrs: [None, None, None],
|
||||||
|
tekked: true,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
let mut grinders = Vec::new();
|
||||||
|
for _ in 0..3usize {
|
||||||
|
grinders.push(entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: item::tool::ToolType::Monogrinder,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let equipped = item::EquippedEntity {
|
||||||
|
weapon: Some(saber.id),
|
||||||
|
armor: None,
|
||||||
|
shield: None,
|
||||||
|
unit: [None; 4],
|
||||||
|
mag: None,
|
||||||
|
};
|
||||||
|
entity_gateway.set_character_equips(&char1.id, &equipped).await.unwrap();
|
||||||
|
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![item::InventoryItemEntity::Individual(saber),
|
||||||
|
item::InventoryItemEntity::Stacked(grinders)])).await.unwrap();
|
||||||
|
|
||||||
|
let mut ship = Box::new(ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build());
|
||||||
|
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: 0x10001,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10001,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
|
||||||
|
assert_eq!(inventory_items.items.len(), 2);
|
||||||
|
|
||||||
|
assert!(matches!(inventory_items.items[0], item::InventoryItemEntity::Individual(item::ItemEntity{ item: item::ItemDetail::Weapon(item::weapon::Weapon {grind: 2, ..}), ..})));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: tests for ALL ITEMS WOW
|
// TODO: tests for ALL ITEMS WOW
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -12,113 +12,6 @@ mod common;
|
|||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
|
|
||||||
#[async_std::test]
|
|
||||||
async fn test_item_ids_reset_when_rejoining_rooms() {
|
|
||||||
let mut entity_gateway = InMemoryGateway::default();
|
|
||||||
|
|
||||||
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
|
||||||
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
|
|
||||||
|
|
||||||
let mut p1_inv = Vec::new();
|
|
||||||
for _ in 0..3usize {
|
|
||||||
p1_inv.push(entity_gateway.create_item(
|
|
||||||
item::NewItemEntity {
|
|
||||||
item: item::ItemDetail::Weapon(
|
|
||||||
item::weapon::Weapon {
|
|
||||||
weapon: item::weapon::WeaponType::Saber,
|
|
||||||
grind: 0,
|
|
||||||
special: None,
|
|
||||||
attrs: [None, None, None],
|
|
||||||
tekked: true,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
}).await.unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut p2_inv = Vec::new();
|
|
||||||
for _ in 0..10usize {
|
|
||||||
p2_inv.push(entity_gateway.create_item(
|
|
||||||
item::NewItemEntity {
|
|
||||||
item: item::ItemDetail::Weapon(
|
|
||||||
item::weapon::Weapon {
|
|
||||||
weapon: item::weapon::WeaponType::Saber,
|
|
||||||
grind: 0,
|
|
||||||
special: None,
|
|
||||||
attrs: [None, None, None],
|
|
||||||
tekked: true,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
}).await.unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
|
|
||||||
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap();
|
|
||||||
|
|
||||||
let mut ship = Box::new(ShipServerState::builder()
|
|
||||||
.gateway(entity_gateway.clone())
|
|
||||||
.build());
|
|
||||||
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
|
||||||
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
|
|
||||||
|
|
||||||
join_lobby(&mut ship, ClientId(1)).await;
|
|
||||||
join_lobby(&mut ship, ClientId(2)).await;
|
|
||||||
|
|
||||||
create_room(&mut ship, ClientId(1), "room", "").await;
|
|
||||||
let p = ship.handle(ClientId(2), RecvShipPacket::MenuSelect(MenuSelect {
|
|
||||||
menu: ROOM_MENU_ID,
|
|
||||||
item: 0,
|
|
||||||
})).await.unwrap();
|
|
||||||
ship.handle(ClientId(2), RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap();
|
|
||||||
|
|
||||||
match &p[1].1 {
|
|
||||||
SendShipPacket::AddToRoom(add_to) => {
|
|
||||||
println!("addto {:?}", add_to);
|
|
||||||
assert_eq!(add_to.playerinfo.inventory.items.iter().map(|k| k.item_id).collect::<Vec<_>>(),
|
|
||||||
vec![0x210000,0x210001,0x210002,0x210003,0x210004,0x210005,0x210006,0x210007,0x210008,0x210009,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
|
|
||||||
},
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_room(&mut ship, ClientId(2)).await;
|
|
||||||
|
|
||||||
let p = ship.handle(ClientId(2), RecvShipPacket::MenuSelect(MenuSelect {
|
|
||||||
menu: ROOM_MENU_ID,
|
|
||||||
item: 0,
|
|
||||||
})).await.unwrap();
|
|
||||||
|
|
||||||
match &p[1].1 {
|
|
||||||
SendShipPacket::AddToRoom(add_to) => {
|
|
||||||
assert_eq!(add_to.playerinfo.inventory.items.iter().map(|k| k.item_id).collect::<Vec<_>>(),
|
|
||||||
vec![0x210000,0x210001,0x210002,0x210003,0x210004,0x210005,0x210006,0x210007,0x210008,0x210009,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
|
|
||||||
},
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
#[async_std::test]
|
|
||||||
async fn test_load_rare_monster_default_appear_rates() {
|
|
||||||
let mut entity_gateway = InMemoryGateway::default();
|
|
||||||
let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
|
||||||
let mut ship = Box::new(ShipServerState::builder()
|
|
||||||
.gateway(entity_gateway.clone())
|
|
||||||
.build());
|
|
||||||
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;
|
|
||||||
|
|
||||||
// assume episode 1
|
|
||||||
ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move {
|
|
||||||
let rates = &*room.rare_monster_table;
|
|
||||||
for (_monster, rate) in rates.clone().appear_rate {
|
|
||||||
assert_eq!(rate, 0.001953125f32); // 1/512 = 0.001953125
|
|
||||||
}
|
|
||||||
})).await.unwrap();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_set_valid_quest_group() {
|
async fn test_set_valid_quest_group() {
|
||||||
let mut entity_gateway = InMemoryGateway::default();
|
let mut entity_gateway = InMemoryGateway::default();
|
||||||
@ -227,3 +120,6 @@ async fn test_cannot_join_room_after_its_closed() {
|
|||||||
msg: _expectedmsg, // wow yes cool rust is so great literally the best i can't put a String::from() directly in here.
|
msg: _expectedmsg, // wow yes cool rust is so great literally the best i can't put a String::from() directly in here.
|
||||||
}))));
|
}))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: test joining twice errors not hangs forever
|
||||||
|
Loading…
x
Reference in New Issue
Block a user