Browse Source

refactor tekking

pull/113/head
jake 2 years ago
parent
commit
8f44ca9d18
  1. 5
      src/entity/item/mod.rs
  2. 64
      src/ship/items/actions.rs
  3. 39
      src/ship/items/state.rs
  4. 4
      src/ship/packet/builder/message.rs
  5. 27
      src/ship/packet/handler/direct_message.rs
  6. 2
      src/ship/packet/handler/trade.rs
  7. 4
      src/ship/ship.rs

5
src/entity/item/mod.rs

@ -334,3 +334,8 @@ pub struct TradeEntity {
pub character1: CharacterEntityId,
pub character2: CharacterEntityId,
}
#[derive(Clone, Debug)]
pub enum ItemModifier {
WeaponModifier(weapon::WeaponModifier),
}

64
src/ship/items/actions.rs

@ -11,6 +11,8 @@ use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, Item
use crate::ship::items::apply_item::apply_item;
use crate::entity::item::{ItemDetail, NewItemEntity, TradeId};
use crate::entity::item::tool::Tool;
use crate::entity::item::weapon::WeaponModifier;
use crate::entity::item::ItemModifier;
use crate::ship::shops::ShopItem;
use crate::ship::trade::TradeItem;
use crate::ship::location::{AreaClient, RoomId};
@ -1281,3 +1283,65 @@ where
Ok((transaction, floor_item))
}).await
}
fn apply_modifier_to_inventory_item(character_id: CharacterEntityId, modifier: ItemModifier)
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
{
move |(item_state, mut transaction), mut inventory_item| {
let modifier = modifier.clone();
Box::pin(async move {
match (&inventory_item.item, modifier) {
(InventoryItemDetail::Individual(IndividualItemDetail{entity_id, item: ItemDetail::Weapon(mut weapon), ..}), ItemModifier::WeaponModifier(modifier)) => {
weapon.apply_modifier(&modifier);
transaction.gateway().add_weapon_modifier(&entity_id, modifier).await?;
},
_ => return Err(ItemStateError::InvalidModifier)
}
Ok(((item_state, transaction), inventory_item))
})
}
}
fn as_individual_item()
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), IndividualItemDetail), ItemStateError>> + Send + 'a>>
{
move |(item_state, transaction), inventory_item| {
Box::pin(async move {
let item = match inventory_item.item {
InventoryItemDetail::Individual(individual_item) => individual_item,
_ => return Err(ItemStateError::WrongItemType(inventory_item.item_id))
};
Ok(((item_state, transaction), item))
})
}
}
pub async fn apply_modifier<'a, EG> (
item_state: &'a mut ItemState,
entity_gateway: &mut EG,
character: &CharacterEntity,
item_id: ClientItemId,
modifier: ItemModifier)
-> Result<IndividualItemDetail, ItemStateError>
where
EG: EntityGateway,
{
entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), item) = ItemStateAction::default()
.act(take_item_from_inventory(character.id, item_id, 1))
.act(apply_modifier_to_inventory_item(character.id, modifier))
.act(add_item_to_inventory(character.clone()))
.act(as_individual_item())
.commit((item_state_proxy, transaction))
.await?;
item_state_proxy.commit();
Ok((transaction, item))
}).await
}

39
src/ship/items/state.rs

@ -10,6 +10,7 @@ use crate::ship::location::{AreaClient, RoomId};
use crate::entity::character::{CharacterEntity, CharacterEntityId};
use crate::entity::gateway::{EntityGateway, GatewayError};
use crate::entity::item::tool::{Tool, ToolType};
use crate::entity::item::weapon::Weapon;
use crate::entity::item::mag::Mag;
use crate::ship::drops::ItemDrop;
use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem};
@ -69,6 +70,12 @@ pub enum ItemStateError {
#[error("item is not sellable")]
ItemNotSellable,
#[error("could not modify item")]
InvalidModifier,
#[error("wrong item type ")]
WrongItemType(ClientItemId),
}
pub enum FloorType {
@ -221,6 +228,13 @@ pub struct IndividualItemDetail {
}
impl IndividualItemDetail {
pub fn as_weapon(&self) -> Option<&Weapon> {
match &self.item {
ItemDetail::Weapon(weapon) => Some(weapon),
_ => None
}
}
pub fn as_mag(&self) -> Option<&Mag> {
match &self.item {
ItemDetail::Mag(mag) => Some(mag),
@ -234,6 +248,20 @@ impl IndividualItemDetail {
_ => None
}
}
pub fn as_client_bytes(&self) -> [u8; 16] {
match &self.item {
ItemDetail::Weapon(w) => w.as_bytes(),
ItemDetail::Armor(a) => a.as_bytes(),
ItemDetail::Shield(s) => s.as_bytes(),
ItemDetail::Unit(u) => u.as_bytes(),
ItemDetail::Tool(t) => t.as_individual_bytes(),
ItemDetail::TechniqueDisk(d) => d.as_bytes(),
ItemDetail::Mag(m) => m.as_bytes(),
ItemDetail::ESWeapon(e) => e.as_bytes(),
}
}
}
#[derive(Clone, Debug)]
@ -287,16 +315,7 @@ impl InventoryItemDetail {
pub fn as_client_bytes(&self) -> [u8; 16] {
match self {
InventoryItemDetail::Individual(item) => {
match &item.item {
ItemDetail::Weapon(w) => w.as_bytes(),
ItemDetail::Armor(a) => a.as_bytes(),
ItemDetail::Shield(s) => s.as_bytes(),
ItemDetail::Unit(u) => u.as_bytes(),
ItemDetail::Tool(t) => t.as_individual_bytes(),
ItemDetail::TechniqueDisk(d) => d.as_bytes(),
ItemDetail::Mag(m) => m.as_bytes(),
ItemDetail::ESWeapon(e) => e.as_bytes(),
}
item.as_client_bytes()
},
InventoryItemDetail::Stacked(item) => {
item.tool.as_stacked_bytes(item.entity_ids.len())

4
src/ship/packet/builder/message.rs

@ -6,7 +6,7 @@ use crate::ship::ship::{ShipError};
use crate::ship::items::{ClientItemId, InventoryItem, StackedFloorItem, FloorItem, CharacterBank};
use crate::ship::items::state::FloorItem as FloorItem2;
use crate::ship::items::state::InventoryItem as InventoryItem2;
use crate::ship::items::state::{BankState};
use crate::ship::items::state::{BankState, IndividualItemDetail};
use crate::ship::location::AreaClient;
use std::convert::TryInto;
use crate::ship::shops::ShopItem;
@ -31,7 +31,7 @@ pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem2) -> Result<ItemD
}
// TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &item::ItemDetail) -> Result<CreateItem, ShipError> {
pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &IndividualItemDetail) -> Result<CreateItem, ShipError> {
let bytes = item.as_client_bytes();
Ok(CreateItem {
client: area_client.local_client.id(),

27
src/ship/packet/handler/direct_message.rs

@ -15,7 +15,7 @@ use libpso::utf8_to_utf16_array;
use crate::ship::packet::builder;
use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem};
use crate::ship::items::state::{ItemState, FloorType, FloorItemDetail};
use crate::ship::items::actions::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, TriggerCreateItem};
use crate::ship::items::actions::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, take_meseta, apply_modifier, TriggerCreateItem};
const BANK_ACTION_DEPOSIT: u8 = 0;
const BANK_ACTION_WITHDRAW: u8 = 1;
@ -151,7 +151,7 @@ where
let (item, floor_type) = item_state.get_floor_item(&client.character.id, &ClientItemId(pickup_item.item_id))?;
let remove_item = builder::message::remove_item_from_floor(area_client, item)?;
let create_item = match &item.item {
FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, &individual_floor_item.item)?),
FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, individual_floor_item)?),
FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())?),
FloorItemDetail::Meseta(_) => None,
//_ => Some(builder::message::create_item(area_client, &item)?),
@ -411,7 +411,7 @@ pub async fn request_tek_item<EG>(id: ClientId,
tek_request: &TekRequest,
entity_gateway: &mut EG,
clients: &mut Clients,
item_manager: &mut ItemManager)
item_state: &mut ItemState)
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
where
EG: EntityGateway
@ -429,13 +429,14 @@ where
client.tek = Some((ClientItemId(tek_request.item_id), special_mod, percent_mod, grind_mod));
let inventory = item_manager.get_character_inventory(&client.character)?;
let item = inventory.get_item_by_id(ClientItemId(tek_request.item_id))
let inventory = item_state.get_character_inventory(&client.character)?;
let item = inventory.get_by_client_id(&ClientItemId(tek_request.item_id))
.ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))?;
let mut weapon = *item.individual()
let mut weapon = item.item.as_individual()
.ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))?
.weapon()
.ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))?;
.as_weapon()
.ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))?
.clone();
weapon.apply_modifier(&item::weapon::WeaponModifier::Tekked {
special: special_mod,
@ -443,9 +444,7 @@ where
grind: grind_mod,
});
let character_meseta = item_manager.get_character_meseta_mut(&client.character.id)?;
character_meseta.0 -= 100;
entity_gateway.set_character_meseta(&client.character.id, *character_meseta).await?;
take_meseta(item_state, entity_gateway, &client.character.id, item::Meseta(100)).await?;
let preview_pkt = builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)?;
@ -457,7 +456,7 @@ pub async fn accept_tek_item<EG>(id: ClientId,
entity_gateway: &mut EG,
client_location: &ClientLocation,
clients: &mut Clients,
item_manager: &mut ItemManager)
item_state: &mut ItemState)
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
where
EG: EntityGateway
@ -475,9 +474,9 @@ where
percent: percent_mod,
grind: grind_mod,
};
let weapon = item_manager.replace_item_with_tekked(entity_gateway, &client.character, item_id, modifier).await?;
let weapon = apply_modifier(item_state, entity_gateway, &client.character, item_id, item::ItemModifier::WeaponModifier(modifier)).await?;
let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &item::ItemDetail::Weapon(weapon))?;
let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon)?;
let neighbors = client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError { err.into() })?;
Ok(Box::new(neighbors.into_iter()

2
src/ship/packet/handler/trade.rs

@ -512,7 +512,7 @@ where
.map(|(client, item)| {
match item.item {
InventoryItemDetail::Individual(individual_item) => {
GameMessage::CreateItem(builder::message::create_individual_item(client, item.item_id, &individual_item.item).unwrap())
GameMessage::CreateItem(builder::message::create_individual_item(client, item.item_id, &individual_item).unwrap())
},
InventoryItemDetail::Stacked(stacked_item) => {
GameMessage::CreateItem(builder::message::create_stacked_item(client, item.item_id, &stacked_item.tool, stacked_item.count()).unwrap())

4
src/ship/ship.rs

@ -567,10 +567,10 @@ impl<EG: EntityGateway> ShipServerState<EG> {
handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
},
GameMessage::TekRequest(tek_request) => {
handler::direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await?
handler::direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &mut self.clients, &mut self.item_state).await?
},
GameMessage::TekAccept(tek_accept) => {
handler::direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
handler::direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
},
GameMessage::TradeRequest(trade_request) => {
handler::trade::trade_request(id, trade_request, target, &block.client_location, &mut self.clients, &mut self.item_state, &mut self.trades).await?

Loading…
Cancel
Save