move partial drops over to item_state
This commit is contained in:
parent
573e1ff60b
commit
c7fdd5e58b
@ -1,12 +1,12 @@
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::ItemNote;
|
||||
use crate::entity::item::{Meseta, ItemNote};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||
use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, ItemAction, ItemStateError, FloorItem, InventoryItem, AddItemResult};
|
||||
use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, ItemAction, ItemStateError, FloorItem, InventoryItem, AddItemResult, FloorItemDetail, StackedItemDetail};
|
||||
|
||||
pub enum TriggerCreateItem {ItemAction,
|
||||
Yes,
|
||||
@ -112,7 +112,7 @@ fn take_item_from_inventory(character_id: CharacterEntityId, item_id: ClientItem
|
||||
}
|
||||
|
||||
|
||||
fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId, item_id: ClientItemId, map_area: MapArea, drop_position: (f32, f32, f32))
|
||||
fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId, map_area: MapArea, drop_position: (f32, f32, f32))
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -134,6 +134,7 @@ fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId, item_id:
|
||||
|
||||
let mut floor = item_state.floor(&character_id)?;
|
||||
floor.add_inventory_item(inventory_item, map_area, drop_position);
|
||||
item_state.set_floor(floor);
|
||||
|
||||
Ok(((item_state, transaction), ()))
|
||||
})
|
||||
@ -155,7 +156,151 @@ where
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_item_from_inventory(character.id, *item_id))
|
||||
.act(add_inventory_item_to_shared_floor(character.id, *item_id, map_area, drop_position))
|
||||
.act(add_inventory_item_to_shared_floor(character.id, map_area, drop_position))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn take_partial_item_from_inventory(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), StackedItemDetail), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
move |(mut item_state, mut transaction), _| {
|
||||
Box::pin(async move {
|
||||
let mut inventory = item_state.inventory(&character_id)?;
|
||||
let item = inventory.take_partial_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?;
|
||||
item_state.set_inventory(inventory);
|
||||
|
||||
Ok(((item_state, transaction), item))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn add_partial_inventory_item_to_shared_floor(character_id: CharacterEntityId, map_area: MapArea, drop_position: (f32, f32))
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), StackedItemDetail)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
move |(mut item_state, transaction), stacked_item| {
|
||||
Box::pin(async move {
|
||||
let floor_item = FloorItem {
|
||||
item_id: item_state.new_item_id()?,
|
||||
item: FloorItemDetail::Stacked(stacked_item),
|
||||
map_area,
|
||||
x: drop_position.0,
|
||||
y: 0.0,
|
||||
z: drop_position.1,
|
||||
};
|
||||
|
||||
let transaction = floor_item.with_entity_id(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id| {
|
||||
async move {
|
||||
if let Ok(transaction) = &mut transaction {
|
||||
transaction.gateway().add_item_note(&entity_id, ItemNote::PlayerDrop {
|
||||
character_id,
|
||||
map_area,
|
||||
x: drop_position.0,
|
||||
y: 0.0,
|
||||
z: drop_position.1,
|
||||
}).await?;
|
||||
}
|
||||
transaction
|
||||
}}).await?;
|
||||
|
||||
let mut floor = item_state.floor(&character_id)?;
|
||||
let floor_item = floor.add_item(floor_item).clone();
|
||||
item_state.set_floor(floor);
|
||||
|
||||
Ok(((item_state, transaction), floor_item))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn drop_partial_item<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
map_area: MapArea,
|
||||
drop_position: (f32, f32),
|
||||
amount: u32)
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_partial_item_from_inventory(character.id, *item_id, amount))
|
||||
.act(add_partial_inventory_item_to_shared_floor(character.id, map_area, drop_position))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn take_meseta_from_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), u32), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
move |(mut item_state, mut transaction), _| {
|
||||
Box::pin(async move {
|
||||
let mut inventory = item_state.inventory(&character_id)?;
|
||||
inventory.remove_meseta(amount)?;
|
||||
transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?;
|
||||
|
||||
Ok(((item_state, transaction), amount))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn add_meseta_to_shared_floor(character_id: CharacterEntityId, map_area: MapArea, drop_position: (f32, f32))
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), u32)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
|
||||
move |(mut item_state, transaction), amount| {
|
||||
Box::pin(async move {
|
||||
let floor_item = FloorItem {
|
||||
item_id: item_state.new_item_id()?,
|
||||
item: FloorItemDetail::Meseta(Meseta(amount)),
|
||||
map_area: map_area,
|
||||
x: drop_position.0,
|
||||
y: 0.0,
|
||||
z: drop_position.1,
|
||||
};
|
||||
|
||||
let mut floor = item_state.floor(&character_id)?;
|
||||
let floor_item = floor.add_item(floor_item).clone();
|
||||
item_state.set_floor(floor);
|
||||
|
||||
Ok(((item_state, transaction), floor_item))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn drop_meseta<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
map_area: MapArea,
|
||||
drop_position: (f32, f32),
|
||||
amount: u32)
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_meseta_from_inventory(character.id, amount))
|
||||
.act(add_meseta_to_shared_floor(character.id, map_area, drop_position))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
|
@ -1,3 +1,4 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity};
|
||||
@ -7,7 +8,6 @@ use crate::ship::map::MapArea;
|
||||
use crate::ship::location::RoomId;
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::entity::gateway::GatewayError;
|
||||
use crate::entity::gateway::entitygateway::EntityGatewayTransaction;
|
||||
use crate::entity::item::tool::Tool;
|
||||
use crate::entity::item::mag::Mag;
|
||||
use crate::ship::drops::ItemDrop;
|
||||
@ -33,6 +33,9 @@ pub enum ItemStateError {
|
||||
|
||||
#[error("gateway")]
|
||||
GatewayError(#[from] GatewayError),
|
||||
|
||||
#[error("tried to drop more meseta than in inventory: {0}")]
|
||||
InvalidMesetaDrop(u32),
|
||||
}
|
||||
|
||||
|
||||
@ -163,7 +166,7 @@ where
|
||||
type Start = T;
|
||||
type Error = E;
|
||||
|
||||
async fn action(&self, s: Self::Start, i: Self::Input) -> Result<(Self::Start, Self::Output), Self::Error> {
|
||||
async fn action(&self, s: Self::Start, _i: Self::Input) -> Result<(Self::Start, Self::Output), Self::Error> {
|
||||
Ok((s, ()))
|
||||
}
|
||||
|
||||
@ -252,12 +255,12 @@ impl FloorItemDetail {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FloorItem {
|
||||
item_id: ClientItemId,
|
||||
item: FloorItemDetail,
|
||||
map_area: MapArea,
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
pub item_id: ClientItemId,
|
||||
pub item: FloorItemDetail,
|
||||
pub map_area: MapArea,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
impl FloorItem {
|
||||
@ -293,6 +296,20 @@ impl FloorItem {
|
||||
}
|
||||
param
|
||||
}
|
||||
|
||||
pub fn as_client_bytes(&self) -> [u8; 16] {
|
||||
match &self.item {
|
||||
FloorItemDetail::Individual(individual_floor_item) => {
|
||||
individual_floor_item.item.as_client_bytes()
|
||||
},
|
||||
FloorItemDetail::Stacked(stacked_floor_item) => {
|
||||
stacked_floor_item.tool.as_stacked_bytes(stacked_floor_item.entity_ids.len())
|
||||
},
|
||||
FloorItemDetail::Meseta(meseta_floor_item) => {
|
||||
meseta_floor_item.as_bytes()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -326,7 +343,7 @@ pub struct RoomFloorItems(Vec<FloorItem>);
|
||||
pub struct InventoryState {
|
||||
character_id: CharacterEntityId,
|
||||
inventory: Inventory,
|
||||
meseta: Meseta,
|
||||
pub meseta: Meseta,
|
||||
}
|
||||
|
||||
impl InventoryState {
|
||||
@ -374,13 +391,13 @@ impl InventoryState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
FloorItemDetail::Meseta(meseta) => {
|
||||
if self.meseta == Meseta(999999) {
|
||||
Err(InventoryError::MesetaFull)
|
||||
}
|
||||
else {
|
||||
else {
|
||||
self.meseta.0 = std::cmp::min(self.meseta.0 + meseta.0 ,999999);
|
||||
Ok(AddItemResult::Meseta)
|
||||
}
|
||||
@ -394,6 +411,40 @@ impl InventoryState {
|
||||
.next()
|
||||
}
|
||||
|
||||
pub fn take_partial_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<StackedItemDetail> {
|
||||
let amount = amount as usize;
|
||||
let (idx, _, stacked_item) = self.inventory.0
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.filter_map(|(k, item)| {
|
||||
match item.item {
|
||||
InventoryItemDetail::Stacked(ref mut stacked_item) => Some((k, item.item_id, stacked_item)),
|
||||
_ => None
|
||||
}
|
||||
})
|
||||
.find(|(_, id, _)| *id == *item_id)?;
|
||||
|
||||
|
||||
let remove_all = match stacked_item.entity_ids.len().cmp(&amount) {
|
||||
Ordering::Equal => true,
|
||||
Ordering::Greater => false,
|
||||
Ordering::Less => return None,
|
||||
};
|
||||
|
||||
if remove_all {
|
||||
let stacked_item = stacked_item.clone();
|
||||
self.inventory.0.remove(idx);
|
||||
Some(stacked_item)
|
||||
}
|
||||
else {
|
||||
let entity_ids = stacked_item.entity_ids.drain(..amount).collect();
|
||||
Some(StackedItemDetail {
|
||||
entity_ids: entity_ids,
|
||||
tool: stacked_item.tool,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_inventory_entity(&self, _character_id: &CharacterEntityId) -> InventoryEntity {
|
||||
InventoryEntity {
|
||||
items: self.inventory.0.iter()
|
||||
@ -420,6 +471,14 @@ impl InventoryState {
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> {
|
||||
if amount > self.meseta.0 {
|
||||
return Err(ItemStateError::InvalidMesetaDrop(amount))
|
||||
}
|
||||
self.meseta.0 -= amount;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FloorState {
|
||||
@ -444,7 +503,7 @@ impl FloorState {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_inventory_item(&mut self, inventory_item: InventoryItem, map_area: MapArea, position: (f32, f32, f32)) {
|
||||
pub fn add_inventory_item(&mut self, inventory_item: InventoryItem, map_area: MapArea, position: (f32, f32, f32)) -> &FloorItem {
|
||||
let floor_item = FloorItem {
|
||||
item_id: inventory_item.item_id,
|
||||
item: match inventory_item.item {
|
||||
@ -458,6 +517,12 @@ impl FloorState {
|
||||
};
|
||||
|
||||
self.shared.0.push(floor_item);
|
||||
&self.shared.0[self.shared.0.len()-1]
|
||||
}
|
||||
|
||||
pub fn add_item(&mut self, floor_item: FloorItem) -> &FloorItem {
|
||||
self.shared.0.push(floor_item);
|
||||
&self.shared.0[self.shared.0.len()-1]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ use crate::entity::item;
|
||||
use crate::common::leveltable::CharacterStats;
|
||||
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::location::AreaClient;
|
||||
use std::convert::TryInto;
|
||||
use crate::ship::shops::ShopItem;
|
||||
@ -89,7 +90,7 @@ pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Resu
|
||||
})
|
||||
}
|
||||
|
||||
pub fn drop_split_stack(area_client: AreaClient, item: &StackedFloorItem) -> Result<DropSplitStack, ShipError> {
|
||||
pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem2) -> Result<DropSplitStack, ShipError> {
|
||||
let item_bytes = item.as_client_bytes();
|
||||
Ok(DropSplitStack {
|
||||
client: area_client.local_client.id(),
|
||||
@ -106,18 +107,18 @@ pub fn drop_split_stack(area_client: AreaClient, item: &StackedFloorItem) -> Res
|
||||
})
|
||||
}
|
||||
|
||||
pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> Result<DropSplitStack, ShipError> {
|
||||
pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem2) -> Result<DropSplitStack, ShipError> {
|
||||
let item_bytes = item.as_client_bytes();
|
||||
Ok(DropSplitStack {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
variety: 0,
|
||||
unknown1: 0,
|
||||
map_area: item.map_area().area_value(),
|
||||
x: item.x(),
|
||||
z: item.z(),
|
||||
map_area: item.map_area.area_value(),
|
||||
x: item.x,
|
||||
z: item.z,
|
||||
item_bytes: item_bytes[0..12].try_into()?,
|
||||
item_id: item.item_id().0,
|
||||
item_id: item.item_id.0,
|
||||
item_bytes2: item_bytes[12..16].try_into()?,
|
||||
unknown2: 0,
|
||||
})
|
||||
|
@ -8,7 +8,7 @@ use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||
use crate::ship::items::{ItemManager, ClientItemId};
|
||||
use crate::ship::packet::builder;
|
||||
use crate::ship::items::state::ItemState;
|
||||
use crate::ship::items::actions::{drop_item, pick_up_item};
|
||||
use crate::ship::items::actions::{drop_item, drop_partial_item, drop_meseta};
|
||||
|
||||
pub async fn request_exp<EG: EntityGateway>(id: ClientId,
|
||||
request_exp: &RequestExp,
|
||||
@ -120,7 +120,7 @@ pub async fn no_longer_has_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
|
||||
@ -134,7 +134,7 @@ where
|
||||
}
|
||||
|
||||
if no_longer_has_item.item_id == 0xFFFFFFFF {
|
||||
let dropped_meseta = item_manager.player_drops_meseta_on_shared_floor(entity_gateway, &mut client.character, drop_location, no_longer_has_item.amount as u32).await?;
|
||||
let dropped_meseta = drop_meseta(item_state, entity_gateway, &client.character, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await?;
|
||||
|
||||
let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?;
|
||||
let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount as u32);
|
||||
@ -158,9 +158,9 @@ where
|
||||
))
|
||||
}
|
||||
else {
|
||||
let dropped_item = item_manager.player_drops_partial_stack_on_shared_floor(entity_gateway, &client.character, drop_location.item_id, drop_location, no_longer_has_item.amount as usize).await?;
|
||||
let dropped_item = drop_partial_item(item_state, entity_gateway, &client.character, &drop_location.item_id, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await?;
|
||||
|
||||
let dropped_item_pkt = builder::message::drop_split_stack(area_client, dropped_item)?;
|
||||
let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item)?;
|
||||
client.item_drop_location = None;
|
||||
|
||||
let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
|
@ -488,7 +488,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
},
|
||||
GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||
handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
|
||||
},
|
||||
GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) |
|
||||
GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) |
|
||||
|
Loading…
x
Reference in New Issue
Block a user