2022-04-30 21:40:46 -06:00
use std ::cmp ::Ordering ;
2022-04-19 23:20:50 -06:00
use std ::collections ::HashMap ;
2022-05-01 21:59:34 -06:00
use libpso ::character ::character ;
2022-04-19 23:20:50 -06:00
use crate ::ship ::items ::ClientItemId ;
2022-05-14 13:06:40 -06:00
use crate ::entity ::item ::{ Meseta , ItemEntityId , ItemDetail , ItemEntity , InventoryEntity , InventoryItemEntity , BankEntity , BankItemEntity , BankName , EquippedEntity } ;
2022-04-19 23:20:50 -06:00
use std ::future ::Future ;
2022-04-30 11:40:21 -06:00
use crate ::ship ::map ::MapArea ;
2022-05-01 21:59:34 -06:00
use crate ::ship ::location ::{ AreaClient , RoomId } ;
use crate ::entity ::character ::{ CharacterEntity , CharacterEntityId } ;
use crate ::entity ::gateway ::{ EntityGateway , GatewayError } ;
2022-04-27 23:53:26 -06:00
use crate ::entity ::item ::tool ::Tool ;
2022-04-27 20:57:47 -06:00
use crate ::entity ::item ::mag ::Mag ;
2022-04-19 23:20:50 -06:00
use crate ::ship ::drops ::ItemDrop ;
2022-05-14 13:06:40 -06:00
// TODO: Commit trait that ItemStateProxy and EntityTransaction implement that .commit requires and acts on upon everything succeeding (like 3 less lines of code!)
2022-04-19 23:20:50 -06:00
#[ derive(thiserror::Error, Debug) ]
2022-04-27 20:57:47 -06:00
pub enum ItemStateError {
2022-04-19 23:20:50 -06:00
#[ error( " character {0} not found " ) ]
NoCharacter ( CharacterEntityId ) ,
#[ error( " room {0} not found " ) ]
NoRoom ( RoomId ) ,
#[ error( " floor item {0} not found " ) ]
NoFloorItem ( ClientItemId ) ,
2022-05-14 13:06:40 -06:00
#[ error( " bank item {0} not found " ) ]
NoBankItem ( ClientItemId ) ,
2022-04-19 23:20:50 -06:00
#[ error( " inventory error {0} " ) ]
InventoryError ( #[ from ] InventoryError ) ,
2022-05-14 13:06:40 -06:00
#[ error( " bank error {0} " ) ]
BankError ( #[ from ] BankError ) ,
2022-04-19 23:20:50 -06:00
#[ error( " invalid drop? {0:?} (this shouldn't occur) " ) ]
BadItemDrop ( ItemDrop ) ,
#[ error( " idk " ) ]
Dummy ,
#[ error( " gateway " ) ]
2022-04-20 18:35:24 -06:00
GatewayError ( #[ from ] GatewayError ) ,
2022-04-30 21:40:46 -06:00
2022-05-14 13:06:40 -06:00
#[ error( " tried to remove more meseta than exists: {0} " ) ]
InvalidMesetaRemoval ( u32 ) ,
#[ error( " tried to add meseta when there is no more room " ) ]
FullOfMeseta ,
2022-05-01 21:59:34 -06:00
#[ error( " stacked item " ) ]
StackedItemError ( Vec < ItemEntity > ) ,
}
pub enum FloorType {
Local ,
Shared ,
2022-04-19 23:20:50 -06:00
}
#[ async_trait::async_trait ]
2022-04-27 20:57:47 -06:00
pub trait ItemAction {
2022-04-19 23:20:50 -06:00
type Input ;
type Output ;
type Start ;
type Error ;
async fn action ( & self , s : Self ::Start , i : Self ::Input ) -> Result < ( Self ::Start , Self ::Output ) , Self ::Error > ;
async fn commit ( & self , v : Self ::Start ) -> Result < ( Self ::Start , Self ::Output ) , Self ::Error > ;
}
2022-04-27 20:57:47 -06:00
pub struct ItemStateAction < T , S , E > {
2022-04-19 23:20:50 -06:00
_t : std ::marker ::PhantomData < T > ,
_s : std ::marker ::PhantomData < S > ,
_e : std ::marker ::PhantomData < E > ,
}
impl < T , S , E > Default for ItemStateAction < T , S , E > {
fn default ( ) -> ItemStateAction < T , S , E > {
ItemStateAction {
_t : std ::marker ::PhantomData ,
_s : std ::marker ::PhantomData ,
_e : std ::marker ::PhantomData ,
}
}
}
impl < T , S , E > ItemStateAction < T , S , E >
where
T : Send + Sync ,
S : Send + Sync ,
E : Send + Sync ,
{
2022-04-27 20:56:39 -06:00
pub fn act < O , F , Fut > ( self , f : F ) -> ItemActionStage < O , ItemStateAction < T , S , E > , F , Fut , S , E >
2022-04-19 23:20:50 -06:00
where
2022-04-27 20:56:39 -06:00
F : Fn ( S , ( ) ) -> Fut + Send + Sync ,
Fut : Future < Output = Result < ( S , O ) , E > > + Send
2022-04-19 23:20:50 -06:00
{
ItemActionStage {
_s : Default ::default ( ) ,
_e : std ::marker ::PhantomData ,
prev : self ,
actionf : f ,
}
}
}
2022-04-27 20:56:39 -06:00
pub struct ItemActionStage < O , P , F , Fut , S , E >
2022-04-19 23:20:50 -06:00
where
P : ItemAction ,
2022-04-27 20:56:39 -06:00
F : Fn ( S , P ::Output ) -> Fut + Send + Sync ,
Fut : Future < Output = Result < ( S , O ) , E > > + Send ,
2022-04-19 23:20:50 -06:00
{
_s : std ::marker ::PhantomData < S > ,
_e : std ::marker ::PhantomData < E > ,
prev : P ,
actionf : F ,
}
#[ async_trait::async_trait ]
2022-04-27 20:56:39 -06:00
impl < O , P : ItemAction , F , Fut , S , E > ItemAction for ItemActionStage < O , P , F , Fut , S , E >
2022-04-19 23:20:50 -06:00
where
P : ItemAction + ItemAction < Start = S , Error = E > + Send + Sync ,
2022-04-27 20:56:39 -06:00
F : Fn ( S , P ::Output ) -> Fut + Send + Sync ,
Fut : Future < Output = Result < ( S , O ) , E > > + Send ,
2022-04-19 23:20:50 -06:00
S : Send + Sync ,
P ::Output : Send + Sync ,
E : Send + Sync ,
O : Send + Sync ,
P ::Error : Send + Sync ,
{
type Input = P ::Output ;
type Output = O ;
type Start = S ;
type Error = P ::Error ;
async fn action ( & self , s : Self ::Start , i : Self ::Input ) -> Result < ( Self ::Start , Self ::Output ) , Self ::Error > {
( self . actionf ) ( s , i ) . await
}
async fn commit ( & self , i : Self ::Start ) -> Result < ( Self ::Start , Self ::Output ) , Self ::Error > {
let ( i , prev ) = self . prev . commit ( i ) . await ? ;
self . action ( i , prev ) . await
}
}
2022-04-27 20:56:39 -06:00
impl < O , P : ItemAction , F , Fut , S , E > ItemActionStage < O , P , F , Fut , S , E >
2022-04-19 23:20:50 -06:00
where
P : ItemAction < Start = S , Error = E > + Send + Sync ,
2022-04-27 20:56:39 -06:00
F : Fn ( S , P ::Output ) -> Fut + Send + Sync ,
Fut : Future < Output = Result < ( S , O ) , E > > + Send ,
2022-04-19 23:20:50 -06:00
S : Send + Sync ,
P ::Output : Send + Sync ,
E : Send + Sync ,
O : Send + Sync ,
P ::Error : Send + Sync ,
{
2022-04-27 23:53:26 -06:00
#[ allow(clippy::type_complexity) ]
2022-04-27 20:56:39 -06:00
pub fn act < O2 , G , GFut > ( self , g : G ) -> ItemActionStage < O2 , ItemActionStage < O , P , F , Fut , S , E > , G , GFut , S , E >
2022-04-19 23:20:50 -06:00
where
S : Send + Sync ,
2022-04-27 20:56:39 -06:00
G : Fn ( S , < ItemActionStage < O , P , F , Fut , S , E > as ItemAction > ::Output ) -> GFut + Send + Sync ,
GFut : Future < Output = Result < ( S , O2 ) , E > > + Send ,
2022-04-19 23:20:50 -06:00
O2 : Send + Sync ,
{
ItemActionStage {
_s : Default ::default ( ) ,
_e : Default ::default ( ) ,
prev : self ,
actionf : g ,
}
}
}
#[ async_trait::async_trait ]
impl < T , S , E > ItemAction for ItemStateAction < T , S , E >
where
T : Send + Sync ,
S : Send + Sync ,
E : Send + Sync ,
{
type Input = T ;
type Output = ( ) ;
type Start = T ;
type Error = E ;
2022-04-30 21:40:46 -06:00
async fn action ( & self , s : Self ::Start , _i : Self ::Input ) -> Result < ( Self ::Start , Self ::Output ) , Self ::Error > {
2022-04-19 23:20:50 -06:00
Ok ( ( s , ( ) ) )
}
async fn commit ( & self , i : Self ::Start ) -> Result < ( Self ::Start , Self ::Output ) , Self ::Error > {
Ok ( ( i , ( ) ) )
}
}
2022-04-27 20:57:47 -06:00
#[ derive(Clone, Debug) ]
pub struct IndividualItemDetail {
2022-05-01 21:59:34 -06:00
pub entity_id : ItemEntityId ,
pub item : ItemDetail ,
2022-04-19 23:20:50 -06:00
}
2022-04-27 20:57:47 -06:00
#[ derive(Clone, Debug) ]
2022-04-19 23:20:50 -06:00
pub struct StackedItemDetail {
pub entity_ids : Vec < ItemEntityId > ,
pub tool : Tool ,
}
2022-05-01 21:59:34 -06:00
impl StackedItemDetail {
pub fn count ( & self ) -> usize {
self . entity_ids . len ( )
}
}
2022-04-27 20:57:47 -06:00
#[ derive(Clone, Debug) ]
pub enum InventoryItemDetail {
2022-04-19 23:20:50 -06:00
Individual ( IndividualItemDetail ) ,
Stacked ( StackedItemDetail ) ,
}
impl InventoryItemDetail {
2022-04-27 23:53:26 -06:00
fn stacked ( & self ) -> Option < & StackedItemDetail > {
2022-04-19 23:20:50 -06:00
match self {
InventoryItemDetail ::Stacked ( sitem ) = > Some ( sitem ) ,
_ = > None ,
}
}
2022-04-27 23:53:26 -06:00
fn stacked_mut ( & mut self ) -> Option < & mut StackedItemDetail > {
2022-04-19 23:20:50 -06:00
match self {
InventoryItemDetail ::Stacked ( sitem ) = > Some ( sitem ) ,
_ = > None ,
}
}
2022-05-01 21:59:34 -06:00
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 ( ) ,
}
} ,
InventoryItemDetail ::Stacked ( item ) = > {
item . tool . as_stacked_bytes ( item . entity_ids . len ( ) )
} ,
}
}
2022-04-19 23:20:50 -06:00
}
2022-04-27 20:57:47 -06:00
#[ derive(Clone, Debug) ]
pub struct InventoryItem {
2022-05-14 13:06:40 -06:00
pub item_id : ClientItemId ,
pub item : InventoryItemDetail ,
2022-04-19 23:20:50 -06:00
}
2022-04-27 20:57:47 -06:00
impl InventoryItem {
pub async fn with_entity_id < F , Fut , T > ( & self , mut param : T , mut func : F ) -> T
where
F : FnMut ( T , ItemEntityId ) -> Fut ,
Fut : Future < Output = T > ,
{
match & self . item {
InventoryItemDetail ::Individual ( individual_item ) = > {
2022-04-27 23:53:26 -06:00
param = func ( param , individual_item . entity_id ) . await ;
2022-04-27 20:57:47 -06:00
} ,
InventoryItemDetail ::Stacked ( stacked_item ) = > {
for entity_id in & stacked_item . entity_ids {
2022-04-27 23:53:26 -06:00
param = func ( param , * entity_id ) . await ;
2022-04-27 20:57:47 -06:00
}
}
}
param
}
2022-05-14 13:06:40 -06:00
pub async fn with_mag < F , Fut , T > ( & self , mut param : T , mut func : F ) -> T
where
F : FnMut ( T , ItemEntityId , Mag ) -> Fut ,
Fut : Future < Output = T > ,
{
if let InventoryItemDetail ::Individual ( individual_item ) = & self . item {
if let ItemDetail ::Mag ( mag ) = & individual_item . item {
param = func ( param , individual_item . entity_id , mag . clone ( ) ) . await ;
}
}
param
}
2022-04-27 20:57:47 -06:00
}
2022-05-01 21:59:34 -06:00
#[ derive(Clone, Debug) ]
pub enum BankItemDetail {
Individual ( IndividualItemDetail ) ,
Stacked ( StackedItemDetail ) ,
}
impl BankItemDetail {
2022-05-14 13:06:40 -06:00
fn stacked_mut ( & mut self ) -> Option < & mut StackedItemDetail > {
match self {
BankItemDetail ::Stacked ( sitem ) = > Some ( sitem ) ,
_ = > None ,
}
}
2022-05-01 21:59:34 -06:00
pub fn as_client_bytes ( & self ) -> [ u8 ; 16 ] {
match self {
BankItemDetail ::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 ( ) ,
}
} ,
BankItemDetail ::Stacked ( item ) = > {
item . tool . as_stacked_bytes ( item . entity_ids . len ( ) )
} ,
}
}
}
#[ derive(Clone, Debug) ]
pub struct BankItem {
2022-05-14 13:06:40 -06:00
pub item_id : ClientItemId ,
pub item : BankItemDetail ,
}
impl BankItem {
pub async fn with_entity_id < F , Fut , T > ( & self , mut param : T , mut func : F ) -> T
where
F : FnMut ( T , ItemEntityId ) -> Fut ,
Fut : Future < Output = T > ,
{
match & self . item {
BankItemDetail ::Individual ( individual_item ) = > {
param = func ( param , individual_item . entity_id ) . await ;
} ,
BankItemDetail ::Stacked ( stacked_item ) = > {
for entity_id in & stacked_item . entity_ids {
param = func ( param , * entity_id ) . await ;
}
}
}
param
}
2022-05-01 21:59:34 -06:00
}
2022-04-19 23:20:50 -06:00
#[ derive(Clone) ]
2022-04-27 20:57:47 -06:00
pub enum FloorItemDetail {
2022-04-19 23:20:50 -06:00
Individual ( IndividualItemDetail ) ,
Stacked ( StackedItemDetail ) ,
Meseta ( Meseta ) ,
}
impl FloorItemDetail {
2022-04-27 23:53:26 -06:00
fn stacked ( & self ) -> Option < & StackedItemDetail > {
2022-04-19 23:20:50 -06:00
match self {
FloorItemDetail ::Stacked ( sitem ) = > Some ( sitem ) ,
_ = > None ,
}
}
}
#[ derive(Clone) ]
2022-04-27 20:57:47 -06:00
pub struct FloorItem {
2022-04-30 21:40:46 -06:00
pub item_id : ClientItemId ,
pub item : FloorItemDetail ,
pub map_area : MapArea ,
pub x : f32 ,
pub y : f32 ,
pub z : f32 ,
2022-04-19 23:20:50 -06:00
}
2022-04-27 20:57:47 -06:00
impl FloorItem {
pub async fn with_entity_id < F , Fut , T > ( & self , mut param : T , mut func : F ) -> T
where
F : FnMut ( T , ItemEntityId ) -> Fut ,
Fut : Future < Output = T > ,
{
match & self . item {
FloorItemDetail ::Individual ( individual_item ) = > {
2022-04-27 23:53:26 -06:00
param = func ( param , individual_item . entity_id ) . await ;
2022-04-27 20:57:47 -06:00
} ,
FloorItemDetail ::Stacked ( stacked_item ) = > {
for entity_id in & stacked_item . entity_ids {
2022-04-27 23:53:26 -06:00
param = func ( param , * entity_id ) . await ;
2022-04-27 20:57:47 -06:00
}
} ,
FloorItemDetail ::Meseta ( _meseta ) = > { } ,
}
param
}
pub async fn with_mag < F , Fut , T > ( & self , mut param : T , mut func : F ) -> T
where
F : FnMut ( T , ItemEntityId , Mag ) -> Fut ,
Fut : Future < Output = T > ,
{
2022-04-27 23:53:26 -06:00
if let FloorItemDetail ::Individual ( individual_item ) = & self . item {
if let ItemDetail ::Mag ( mag ) = & individual_item . item {
param = func ( param , individual_item . entity_id , mag . clone ( ) ) . await ;
}
2022-04-27 20:57:47 -06:00
}
param
}
2022-04-30 21:40:46 -06:00
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 ( )
}
}
}
2022-04-27 20:57:47 -06:00
}
2022-04-19 23:20:50 -06:00
2022-04-27 20:57:47 -06:00
#[ derive(Clone, Debug) ]
pub struct Inventory ( Vec < InventoryItem > ) ;
2022-04-19 23:20:50 -06:00
#[ derive(thiserror::Error, Debug) ]
2022-04-27 20:57:47 -06:00
pub enum InventoryError {
2022-04-19 23:20:50 -06:00
#[ error( " inventory full " ) ]
InventoryFull ,
#[ error( " stack full " ) ]
StackFull ,
#[ error( " meseta full " ) ]
MesetaFull ,
}
2022-05-14 13:06:40 -06:00
#[ derive(thiserror::Error, Debug) ]
pub enum BankError {
#[ error( " bank full " ) ]
BankFull ,
#[ error( " stack full " ) ]
StackFull ,
#[ error( " meseta full " ) ]
MesetaFull ,
}
2022-05-01 21:59:34 -06:00
#[ derive(Clone) ]
2022-04-27 20:57:47 -06:00
pub enum AddItemResult {
2022-04-19 23:20:50 -06:00
NewItem ,
AddToStack ,
Meseta ,
}
2022-05-01 21:59:34 -06:00
#[ derive(Clone, Default) ]
2022-04-27 20:57:47 -06:00
pub struct LocalFloor ( Vec < FloorItem > ) ;
2022-05-01 21:59:34 -06:00
#[ derive(Clone, Default) ]
2022-04-27 20:57:47 -06:00
pub struct SharedFloor ( Vec < FloorItem > ) ;
2022-04-19 23:20:50 -06:00
#[ derive(Clone) ]
2022-04-27 20:57:47 -06:00
pub struct RoomFloorItems ( Vec < FloorItem > ) ;
2022-04-19 23:20:50 -06:00
2022-05-01 21:59:34 -06:00
#[ derive(Clone) ]
2022-04-27 20:57:47 -06:00
pub struct InventoryState {
2022-04-19 23:20:50 -06:00
character_id : CharacterEntityId ,
2022-05-01 21:59:34 -06:00
item_id_counter : u32 ,
pub inventory : Inventory ,
equipped : EquippedEntity ,
2022-04-30 21:40:46 -06:00
pub meseta : Meseta ,
2022-04-19 23:20:50 -06:00
}
impl InventoryState {
2022-05-01 21:59:34 -06:00
pub fn initialize_item_ids ( & mut self , base_item_id : u32 ) {
for ( i , item ) in self . inventory . 0. iter_mut ( ) . enumerate ( ) {
item . item_id = ClientItemId ( base_item_id + i as u32 ) ;
}
self . item_id_counter = base_item_id + self . inventory . 0. len ( ) as u32 + 1 ;
}
2022-05-14 13:06:40 -06:00
pub fn new_item_id ( & mut self ) -> ClientItemId {
self . item_id_counter + = 1 ;
ClientItemId ( self . item_id_counter )
}
2022-05-01 21:59:34 -06:00
pub fn count ( & self ) -> usize {
self . inventory . 0. len ( )
}
2022-04-27 20:57:47 -06:00
pub fn add_floor_item ( & mut self , item : FloorItem ) -> Result < AddItemResult , InventoryError > {
2022-04-19 23:20:50 -06:00
match item . item {
FloorItemDetail ::Individual ( iitem ) = > {
if self . inventory . 0. len ( ) > = 30 {
2022-04-27 23:53:26 -06:00
Err ( InventoryError ::InventoryFull )
2022-04-19 23:20:50 -06:00
}
else {
self . inventory . 0. push ( InventoryItem {
item_id : item . item_id ,
item : InventoryItemDetail ::Individual ( iitem )
} ) ;
Ok ( AddItemResult ::NewItem )
}
} ,
FloorItemDetail ::Stacked ( sitem ) = > {
let existing_stack = self . inventory . 0
. iter_mut ( )
. filter_map ( | item | item . item . stacked_mut ( ) )
. find ( | item | {
item . tool = = sitem . tool
} ) ;
match existing_stack {
Some ( existing_stack ) = > {
if existing_stack . entity_ids . len ( ) + sitem . entity_ids . len ( ) > sitem . tool . max_stack ( ) {
2022-04-27 23:53:26 -06:00
Err ( InventoryError ::StackFull )
2022-04-19 23:20:50 -06:00
}
else {
existing_stack . entity_ids . append ( & mut sitem . entity_ids . clone ( ) ) ;
Ok ( AddItemResult ::AddToStack )
}
} ,
None = > {
if self . inventory . 0. len ( ) > = 30 {
2022-04-27 23:53:26 -06:00
Err ( InventoryError ::InventoryFull )
2022-04-19 23:20:50 -06:00
}
else {
self . inventory . 0. push ( InventoryItem {
item_id : item . item_id ,
item : InventoryItemDetail ::Stacked ( sitem )
} ) ;
Ok ( AddItemResult ::NewItem )
}
}
}
2022-04-30 21:40:46 -06:00
2022-04-19 23:20:50 -06:00
} ,
FloorItemDetail ::Meseta ( meseta ) = > {
if self . meseta = = Meseta ( 999999 ) {
Err ( InventoryError ::MesetaFull )
}
2022-04-30 21:40:46 -06:00
else {
2022-04-19 23:20:50 -06:00
self . meseta . 0 = std ::cmp ::min ( self . meseta . 0 + meseta . 0 , 999999 ) ;
Ok ( AddItemResult ::Meseta )
}
} ,
}
}
2022-04-30 11:40:21 -06:00
2022-05-14 13:06:40 -06:00
pub fn add_item ( & mut self , item : InventoryItem ) -> Result < AddItemResult , InventoryError > {
match & item . item {
InventoryItemDetail ::Individual ( _ ) = > {
if self . inventory . 0. len ( ) > = 30 {
Err ( InventoryError ::InventoryFull )
}
else {
self . inventory . 0. push ( item ) ;
Ok ( AddItemResult ::NewItem )
}
} ,
InventoryItemDetail ::Stacked ( sitem ) = > {
let existing_stack = self . inventory . 0
. iter_mut ( )
. filter_map ( | item | item . item . stacked_mut ( ) )
. find ( | item | {
item . tool = = sitem . tool
} ) ;
match existing_stack {
Some ( existing_stack ) = > {
if existing_stack . entity_ids . len ( ) + sitem . entity_ids . len ( ) > sitem . tool . max_stack ( ) {
Err ( InventoryError ::StackFull )
}
else {
existing_stack . entity_ids . append ( & mut sitem . entity_ids . clone ( ) ) ;
Ok ( AddItemResult ::AddToStack )
}
} ,
None = > {
if self . inventory . 0. len ( ) > = 30 {
Err ( InventoryError ::InventoryFull )
}
else {
self . inventory . 0. push ( item ) ;
Ok ( AddItemResult ::NewItem )
}
}
}
}
}
2022-04-30 11:40:21 -06:00
}
2022-05-14 13:06:40 -06:00
pub fn take_item ( & mut self , item_id : & ClientItemId , amount : u32 ) -> Option < InventoryItem > {
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 ) )
} ,
InventoryItemDetail ::Stacked ( stacked_item ) = > {
let remove_all = 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 ) )
2022-04-30 21:40:46 -06:00
}
2022-05-14 13:06:40 -06:00
else {
let entity_ids = stacked_item . entity_ids . drain ( .. ( amount as usize ) ) . collect ( ) ;
self . item_id_counter + = 1 ;
Some ( InventoryItem {
item_id : ClientItemId ( self . item_id_counter ) ,
item : InventoryItemDetail ::Stacked ( StackedItemDetail {
entity_ids : entity_ids ,
tool : stacked_item . tool ,
} ) } )
}
}
2022-04-30 21:40:46 -06:00
}
}
2022-04-30 11:40:21 -06:00
pub fn as_inventory_entity ( & self , _character_id : & CharacterEntityId ) -> InventoryEntity {
InventoryEntity {
items : self . inventory . 0. iter ( )
. map ( | item | {
match & item . item {
InventoryItemDetail ::Individual ( item ) = > {
InventoryItemEntity ::Individual ( ItemEntity {
id : item . entity_id ,
item : item . item . clone ( ) ,
} )
} ,
InventoryItemDetail ::Stacked ( items ) = > {
InventoryItemEntity ::Stacked ( items . entity_ids . iter ( )
. map ( | id | {
ItemEntity {
id : * id ,
item : ItemDetail ::Tool ( items . tool )
}
} )
. collect ( ) )
} ,
}
} )
. collect ( )
}
}
2022-04-30 21:40:46 -06:00
2022-05-14 13:06:40 -06:00
pub fn add_meseta ( & mut self , amount : u32 ) -> Result < ( ) , ItemStateError > {
if self . meseta . 0 = = 999999 {
return Err ( ItemStateError ::FullOfMeseta )
}
self . meseta . 0 = std ::cmp ::min ( self . meseta . 0 + amount , 999999 ) ;
Ok ( ( ) )
}
pub fn add_meseta_no_overflow ( & mut self , amount : u32 ) -> Result < ( ) , ItemStateError > {
if self . meseta . 0 + amount > 999999 {
return Err ( ItemStateError ::FullOfMeseta )
}
self . meseta . 0 + = amount ;
Ok ( ( ) )
}
2022-04-30 21:40:46 -06:00
pub fn remove_meseta ( & mut self , amount : u32 ) -> Result < ( ) , ItemStateError > {
if amount > self . meseta . 0 {
2022-05-14 13:06:40 -06:00
return Err ( ItemStateError ::InvalidMesetaRemoval ( amount ) )
2022-04-30 21:40:46 -06:00
}
self . meseta . 0 - = amount ;
Ok ( ( ) )
}
2022-05-01 21:59:34 -06:00
pub fn as_client_inventory_items ( & self ) -> [ character ::InventoryItem ; 30 ] {
self . inventory . 0. iter ( )
. enumerate ( )
. fold ( [ character ::InventoryItem ::default ( ) ; 30 ] , | mut inventory , ( slot , item ) | {
let bytes = item . item . as_client_bytes ( ) ;
inventory [ slot ] . data1 . copy_from_slice ( & bytes [ 0 .. 12 ] ) ;
inventory [ slot ] . data2 . copy_from_slice ( & bytes [ 12 .. 16 ] ) ;
inventory [ slot ] . item_id = item . item_id . 0 ;
inventory [ slot ] . equipped = 0 ;
inventory [ slot ] . flags = 0 ;
if let InventoryItemDetail ::Individual ( individual_item ) = & item . item {
if self . equipped . is_equipped ( & individual_item . entity_id ) {
if let ItemDetail ::Unit ( _ ) = individual_item . item {
inventory [ slot ] . data1 [ 4 ] = self . equipped . unit . iter ( )
. enumerate ( )
. find ( | ( _ , u_id ) | * * u_id = = Some ( individual_item . entity_id ) )
. map ( | ( a , _ ) | a )
. unwrap_or ( 0 ) as u8
}
inventory [ slot ] . equipped = 1 ;
inventory [ slot ] . flags | = 8 ;
}
}
inventory
} )
}
}
#[ derive(Clone, Debug) ]
pub struct Bank ( Vec < BankItem > ) ;
#[ derive(Clone, Debug) ]
pub struct BankState {
character_id : CharacterEntityId ,
item_id_counter : u32 ,
2022-05-14 13:06:40 -06:00
pub name : BankName ,
2022-05-01 21:59:34 -06:00
bank : Bank ,
pub meseta : Meseta ,
}
impl BankState {
2022-05-14 13:06:40 -06:00
pub fn new ( character_id : CharacterEntityId , name : BankName , mut bank : Bank , meseta : Meseta ) -> BankState {
bank . 0. sort ( ) ;
BankState {
character_id ,
item_id_counter : 0 ,
name ,
bank ,
meseta ,
}
}
pub fn count ( & self ) -> usize {
self . bank . 0. len ( )
}
2022-05-01 21:59:34 -06:00
pub fn initialize_item_ids ( & mut self , base_item_id : u32 ) {
for ( i , item ) in self . bank . 0. iter_mut ( ) . enumerate ( ) {
item . item_id = ClientItemId ( base_item_id + i as u32 ) ;
}
2022-05-14 13:06:40 -06:00
self . item_id_counter = base_item_id + self . bank . 0. len ( ) as u32 ;
}
pub fn add_meseta ( & mut self , amount : u32 ) -> Result < ( ) , ItemStateError > {
if self . meseta . 0 + amount > 999999 {
return Err ( ItemStateError ::FullOfMeseta )
}
self . meseta . 0 + = self . meseta . 0 + amount ;
Ok ( ( ) )
}
pub fn remove_meseta ( & mut self , amount : u32 ) -> Result < ( ) , ItemStateError > {
if amount > self . meseta . 0 {
return Err ( ItemStateError ::InvalidMesetaRemoval ( amount ) )
}
self . meseta . 0 - = amount ;
Ok ( ( ) )
}
pub fn add_inventory_item ( & mut self , item : InventoryItem ) -> Result < AddItemResult , BankError > {
match item . item {
InventoryItemDetail ::Individual ( iitem ) = > {
if self . bank . 0. len ( ) > = 30 {
Err ( BankError ::BankFull )
}
else {
self . bank . 0. push ( BankItem {
item_id : item . item_id ,
item : BankItemDetail ::Individual ( iitem )
} ) ;
self . bank . 0. sort ( ) ;
Ok ( AddItemResult ::NewItem )
}
} ,
InventoryItemDetail ::Stacked ( sitem ) = > {
let existing_stack = self . bank . 0
. iter_mut ( )
. filter_map ( | item | item . item . stacked_mut ( ) )
. find ( | item | {
item . tool = = sitem . tool
} ) ;
match existing_stack {
Some ( existing_stack ) = > {
if existing_stack . entity_ids . len ( ) + sitem . entity_ids . len ( ) > sitem . tool . max_stack ( ) {
Err ( BankError ::StackFull )
}
else {
existing_stack . entity_ids . append ( & mut sitem . entity_ids . clone ( ) ) ;
Ok ( AddItemResult ::AddToStack )
}
} ,
None = > {
if self . bank . 0. len ( ) > = 30 {
Err ( BankError ::BankFull )
}
else {
self . bank . 0. push ( BankItem {
item_id : item . item_id ,
item : BankItemDetail ::Stacked ( sitem )
} ) ;
self . bank . 0. sort ( ) ;
Ok ( AddItemResult ::NewItem )
}
}
}
}
}
}
pub fn take_item ( & mut self , item_id : & ClientItemId , amount : u32 ) -> Option < BankItem > {
let idx = self . bank . 0
. iter ( )
. position ( | i | i . item_id = = * item_id ) ? ;
match & mut self . bank . 0 [ idx ] . item {
BankItemDetail ::Individual ( _individual_item ) = > {
Some ( self . bank . 0. remove ( idx ) )
} ,
BankItemDetail ::Stacked ( stacked_item ) = > {
let remove_all = 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 . bank . 0. remove ( idx ) )
}
else {
let entity_ids = stacked_item . entity_ids . drain ( .. ( amount as usize ) ) . collect ( ) ;
self . item_id_counter + = 1 ;
Some ( BankItem {
item_id : ClientItemId ( self . item_id_counter ) ,
item : BankItemDetail ::Stacked ( StackedItemDetail {
entity_ids : entity_ids ,
tool : stacked_item . tool ,
} ) } )
}
}
}
2022-05-01 21:59:34 -06:00
}
pub fn as_client_bank_items ( & self ) -> character ::Bank {
self . bank . 0. iter ( )
. enumerate ( )
. fold ( character ::Bank ::default ( ) , | mut bank , ( slot , item ) | {
bank . item_count = ( slot + 1 ) as u32 ;
let bytes = item . item . as_client_bytes ( ) ;
bank . items [ slot ] . data1 . copy_from_slice ( & bytes [ 0 .. 12 ] ) ;
bank . items [ slot ] . data2 . copy_from_slice ( & bytes [ 12 .. 16 ] ) ;
bank . items [ slot ] . item_id = item . item_id . 0 ;
bank
} )
}
2022-05-14 13:06:40 -06:00
pub fn as_client_bank_request ( & self ) -> Vec < character ::BankItem > {
self . bank . 0. iter ( )
. map ( | item | {
let bytes = item . item . as_client_bytes ( ) ;
let mut data1 = [ 0 ; 12 ] ;
let mut data2 = [ 0 ; 4 ] ;
data1 . copy_from_slice ( & bytes [ 0 .. 12 ] ) ;
data2 . copy_from_slice ( & bytes [ 12 .. 16 ] ) ;
let amount = match & item . item {
BankItemDetail ::Individual ( _individual_bank_item ) = > {
1
} ,
BankItemDetail ::Stacked ( stacked_bank_item ) = > {
stacked_bank_item . count ( )
} ,
} ;
character ::BankItem {
data1 ,
data2 ,
item_id : item . item_id . 0 ,
amount : amount as u16 ,
flags : 1 ,
}
} )
. collect ( )
}
pub fn as_bank_entity ( & self ) -> BankEntity {
BankEntity {
items : self . bank . 0. iter ( )
. map ( | item | {
match & item . item {
BankItemDetail ::Individual ( item ) = > {
BankItemEntity ::Individual ( ItemEntity {
id : item . entity_id ,
item : item . item . clone ( ) ,
} )
} ,
BankItemDetail ::Stacked ( items ) = > {
BankItemEntity ::Stacked ( items . entity_ids . iter ( )
. map ( | id | {
ItemEntity {
id : * id ,
item : ItemDetail ::Tool ( items . tool )
}
} )
. collect ( ) )
} ,
}
} )
. collect ( )
}
}
}
impl std ::cmp ::PartialEq for BankItem {
fn eq ( & self , other : & BankItem ) -> bool {
let mut self_bytes = [ 0 u8 ; 4 ] ;
let mut other_bytes = [ 0 u8 ; 4 ] ;
self_bytes . copy_from_slice ( & self . item . as_client_bytes ( ) [ 0 .. 4 ] ) ;
other_bytes . copy_from_slice ( & other . item . as_client_bytes ( ) [ 0 .. 4 ] ) ;
let self_value = u32 ::from_be_bytes ( self_bytes ) ;
let other_value = u32 ::from_be_bytes ( other_bytes ) ;
self_value . eq ( & other_value )
}
}
impl std ::cmp ::Eq for BankItem { }
impl std ::cmp ::PartialOrd for BankItem {
fn partial_cmp ( & self , other : & BankItem ) -> Option < std ::cmp ::Ordering > {
let mut self_bytes = [ 0 u8 ; 4 ] ;
let mut other_bytes = [ 0 u8 ; 4 ] ;
self_bytes . copy_from_slice ( & self . item . as_client_bytes ( ) [ 0 .. 4 ] ) ;
other_bytes . copy_from_slice ( & other . item . as_client_bytes ( ) [ 0 .. 4 ] ) ;
let self_value = u32 ::from_be_bytes ( self_bytes ) ;
let other_value = u32 ::from_be_bytes ( other_bytes ) ;
self_value . partial_cmp ( & other_value )
}
}
impl std ::cmp ::Ord for BankItem {
fn cmp ( & self , other : & BankItem ) -> std ::cmp ::Ordering {
let mut self_bytes = [ 0 u8 ; 4 ] ;
let mut other_bytes = [ 0 u8 ; 4 ] ;
self_bytes . copy_from_slice ( & self . item . as_client_bytes ( ) [ 0 .. 4 ] ) ;
other_bytes . copy_from_slice ( & other . item . as_client_bytes ( ) [ 0 .. 4 ] ) ;
let self_value = u32 ::from_le_bytes ( self_bytes ) ;
let other_value = u32 ::from_le_bytes ( other_bytes ) ;
self_value . cmp ( & other_value )
}
2022-04-19 23:20:50 -06:00
}
2022-04-27 20:57:47 -06:00
pub struct FloorState {
2022-04-19 23:20:50 -06:00
character_id : CharacterEntityId ,
local : LocalFloor ,
shared : SharedFloor ,
}
impl FloorState {
2022-04-27 20:57:47 -06:00
pub fn take_item ( & mut self , item_id : & ClientItemId ) -> Option < FloorItem > {
2022-04-19 23:20:50 -06:00
let item = self . local . 0
. drain_filter ( | item | {
item . item_id = = * item_id
} )
. next ( ) ;
item . or_else ( | | {
self . shared . 0
. drain_filter ( | item | {
item . item_id = = * item_id
} )
. next ( )
} )
}
2022-04-30 11:40:21 -06:00
2022-04-30 21:40:46 -06:00
pub fn add_inventory_item ( & mut self , inventory_item : InventoryItem , map_area : MapArea , position : ( f32 , f32 , f32 ) ) -> & FloorItem {
2022-04-30 11:40:21 -06:00
let floor_item = FloorItem {
item_id : inventory_item . item_id ,
item : match inventory_item . item {
InventoryItemDetail ::Individual ( individual_item ) = > FloorItemDetail ::Individual ( individual_item ) ,
InventoryItemDetail ::Stacked ( stacked_item ) = > FloorItemDetail ::Stacked ( stacked_item ) ,
} ,
map_area : map_area ,
x : position . 0 ,
y : position . 1 ,
z : position . 2 ,
} ;
self . shared . 0. push ( floor_item ) ;
2022-04-30 21:40:46 -06:00
& 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 ]
2022-04-30 11:40:21 -06:00
}
2022-04-19 23:20:50 -06:00
}
2022-04-27 20:57:47 -06:00
pub struct ItemState {
2022-05-01 21:59:34 -06:00
character_inventory : HashMap < CharacterEntityId , InventoryState > ,
character_bank : HashMap < CharacterEntityId , BankState > ,
2022-04-19 23:20:50 -06:00
character_room : HashMap < CharacterEntityId , RoomId > ,
character_floor : HashMap < CharacterEntityId , LocalFloor > ,
room_floor : HashMap < RoomId , SharedFloor > ,
room_item_id_counter : u32 ,
}
impl Default for ItemState {
fn default ( ) -> ItemState {
ItemState {
character_inventory : HashMap ::new ( ) ,
2022-05-01 21:59:34 -06:00
character_bank : HashMap ::new ( ) ,
2022-04-19 23:20:50 -06:00
character_room : HashMap ::new ( ) ,
character_floor : HashMap ::new ( ) ,
room_floor : HashMap ::new ( ) ,
room_item_id_counter : 0x00810000 ,
}
}
}
2022-05-01 21:59:34 -06:00
impl ItemState {
pub fn get_character_inventory ( & self , character : & CharacterEntity ) -> Result < & InventoryState , ItemStateError > {
Ok ( self . character_inventory . get ( & character . id )
. ok_or ( ItemStateError ::NoCharacter ( character . id ) ) ? )
}
pub fn get_character_bank ( & self , character : & CharacterEntity ) -> Result < & BankState , ItemStateError > {
Ok ( self . character_bank . get ( & character . id )
. ok_or ( ItemStateError ::NoCharacter ( character . id ) ) ? )
}
}
impl ItemState {
fn new_item_id ( & mut self ) -> Result < ClientItemId , ItemStateError > {
self . room_item_id_counter + = 1 ;
Ok ( ClientItemId ( self . room_item_id_counter ) )
}
pub async fn load_character < EG : EntityGateway > ( & mut self , entity_gateway : & mut EG , character : & CharacterEntity ) -> Result < ( ) , ItemStateError > {
let inventory = entity_gateway . get_character_inventory ( & character . id ) . await ? ;
2022-05-14 13:02:23 -06:00
let bank = entity_gateway . get_character_bank ( & character . id , & BankName ( " " . into ( ) ) ) . await ? ;
2022-05-01 21:59:34 -06:00
let equipped = entity_gateway . get_character_equips ( & character . id ) . await ? ;
let inventory_items = inventory . items . into_iter ( )
. map ( | item | -> Result < InventoryItem , ItemStateError > {
Ok ( match item {
InventoryItemEntity ::Individual ( item ) = > {
InventoryItem {
item_id : self . new_item_id ( ) ? ,
item : InventoryItemDetail ::Individual ( IndividualItemDetail {
entity_id : item . id ,
item : item . item ,
} ) ,
}
} ,
InventoryItemEntity ::Stacked ( items ) = > {
InventoryItem {
item_id : self . new_item_id ( ) ? ,
item : InventoryItemDetail ::Stacked ( StackedItemDetail {
entity_ids : items . iter ( ) . map ( | i | i . id ) . collect ( ) ,
tool : items . get ( 0 )
. ok_or_else ( | | ItemStateError ::StackedItemError ( items . clone ( ) ) ) ?
. item
. clone ( )
. as_tool ( )
. ok_or_else ( | | ItemStateError ::StackedItemError ( items . clone ( ) ) ) ?
} )
}
} ,
} )
} )
. collect ::< Result < Vec < _ > , _ > > ( ) ? ;
let character_meseta = entity_gateway . get_character_meseta ( & character . id ) . await ? ;
let inventory_state = InventoryState {
character_id : character . id ,
item_id_counter : 0 ,
inventory : Inventory ( inventory_items ) ,
equipped : equipped ,
meseta : character_meseta ,
} ;
let bank_items = bank . items . into_iter ( )
. map ( | item | -> Result < BankItem , ItemStateError > {
Ok ( match item {
BankItemEntity ::Individual ( item ) = > {
BankItem {
item_id : self . new_item_id ( ) ? ,
item : BankItemDetail ::Individual ( IndividualItemDetail {
entity_id : item . id ,
item : item . item ,
} )
}
} ,
BankItemEntity ::Stacked ( items ) = > {
BankItem {
item_id : self . new_item_id ( ) ? ,
item : BankItemDetail ::Stacked ( StackedItemDetail {
entity_ids : items . iter ( ) . map ( | i | i . id ) . collect ( ) ,
tool : items . get ( 0 )
. ok_or_else ( | | ItemStateError ::StackedItemError ( items . clone ( ) ) ) ?
. item
. clone ( )
. as_tool ( )
. ok_or_else ( | | ItemStateError ::StackedItemError ( items . clone ( ) ) ) ?
} )
}
} ,
} )
} )
. collect ::< Result < Vec < _ > , _ > > ( ) ? ;
2022-05-14 13:06:40 -06:00
let bank_meseta = entity_gateway . get_bank_meseta ( & character . id , & BankName ( " " . into ( ) ) ) . await ? ;
let bank_state = BankState ::new ( character . id , BankName ( " " . into ( ) ) , Bank ( bank_items ) , bank_meseta ) ;
2022-05-01 21:59:34 -06:00
self . character_inventory . insert ( character . id , inventory_state ) ;
self . character_bank . insert ( character . id , bank_state ) ;
Ok ( ( ) )
}
pub 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 inventory = self . character_inventory . get_mut ( & character . id ) . unwrap ( ) ;
inventory . initialize_item_ids ( base_inventory_id ) ;
let base_bank_id = ( ( area_client . local_client . id ( ) as u32 ) < < 21 ) | 0x20000 ;
let default_bank = self . character_bank . get_mut ( & character . id ) ;
if let Some ( default_bank ) = default_bank {
default_bank . initialize_item_ids ( base_bank_id ) ;
}
self . character_room . insert ( character . id , room_id ) ;
self . character_floor . insert ( character . id , LocalFloor ::default ( ) ) ;
self . room_floor . entry ( room_id ) . or_insert_with ( SharedFloor ::default ) ;
}
pub fn remove_character_from_room ( & mut self , character : & CharacterEntity ) {
self . character_inventory . remove ( & character . id ) ;
self . character_floor . remove ( & character . id ) ;
if let Some ( room ) = self . character_room . remove ( & character . id ) . as_ref ( ) {
if self . character_room . iter ( ) . any ( | ( _ , r ) | r = = room ) {
self . room_floor . remove ( room ) ;
}
}
}
pub fn get_floor_item ( & self , character_id : & CharacterEntityId , item_id : & ClientItemId ) -> Result < ( & FloorItem , FloorType ) , ItemStateError > {
let local_floor = self . character_floor . get ( character_id ) . ok_or ( ItemStateError ::NoCharacter ( * character_id ) ) ? ;
let room = self . character_room . get ( character_id ) . ok_or ( ItemStateError ::NoCharacter ( * character_id ) ) ? ;
let shared_floor = self . room_floor . get ( room ) . ok_or ( ItemStateError ::NoCharacter ( * character_id ) ) ? ;
local_floor . 0
. iter ( )
. find ( | item | item . item_id = = * item_id )
. map ( | item | ( item , FloorType ::Local ) )
. or_else ( | | {
shared_floor . 0
. iter ( )
. find ( | item | item . item_id = = * item_id )
. map ( | item | ( item , FloorType ::Shared ) )
} )
. ok_or_else ( | | ItemStateError ::NoFloorItem ( * item_id ) )
}
}
2022-04-19 23:20:50 -06:00
2022-04-27 23:53:26 -06:00
#[ derive(Default) ]
2022-04-19 23:20:50 -06:00
struct ProxiedItemState {
2022-05-01 21:59:34 -06:00
character_inventory : HashMap < CharacterEntityId , InventoryState > ,
character_bank : HashMap < CharacterEntityId , BankState > ,
2022-04-19 23:20:50 -06:00
character_room : HashMap < CharacterEntityId , RoomId > ,
character_floor : HashMap < CharacterEntityId , LocalFloor > ,
room_floor : HashMap < RoomId , SharedFloor > ,
}
2022-04-27 20:57:47 -06:00
pub struct ItemStateProxy < ' a > {
2022-04-19 23:20:50 -06:00
item_state : & ' a mut ItemState ,
proxied_state : ProxiedItemState ,
}
2022-04-27 20:57:47 -06:00
impl < ' a > ItemStateProxy < ' a > {
pub fn commit ( self ) {
self . item_state . character_inventory . extend ( self . proxied_state . character_inventory . clone ( ) ) ;
2022-05-01 21:59:34 -06:00
self . item_state . character_bank . extend ( self . proxied_state . character_bank . clone ( ) ) ;
2022-04-27 20:57:47 -06:00
self . item_state . character_room . extend ( self . proxied_state . character_room . clone ( ) ) ;
self . item_state . character_floor . extend ( self . proxied_state . character_floor . clone ( ) ) ;
self . item_state . room_floor . extend ( self . proxied_state . room_floor . clone ( ) ) ;
}
}
2022-04-19 23:20:50 -06:00
fn get_or_clone < K , V > ( master : & HashMap < K , V > , proxy : & mut HashMap < K , V > , key : K , err : fn ( K ) -> ItemStateError ) -> Result < V , ItemStateError >
where
K : Eq + std ::hash ::Hash + Copy ,
V : Clone
{
let existing_element = master . get ( & key ) . ok_or_else ( | | err ( key ) ) ? ;
Ok ( proxy . entry ( key )
2022-04-27 23:53:26 -06:00
. or_insert_with ( | | existing_element . clone ( ) ) . clone ( ) )
2022-04-19 23:20:50 -06:00
}
impl < ' a > ItemStateProxy < ' a > {
2022-04-27 21:16:04 -06:00
pub fn new ( item_state : & ' a mut ItemState ) -> Self {
2022-04-19 23:20:50 -06:00
ItemStateProxy {
item_state ,
proxied_state : Default ::default ( ) ,
}
}
2022-04-27 20:57:47 -06:00
pub fn inventory ( & mut self , character_id : & CharacterEntityId ) -> Result < InventoryState , ItemStateError > {
2022-05-01 21:59:34 -06:00
get_or_clone ( & self . item_state . character_inventory , & mut self . proxied_state . character_inventory , * character_id , ItemStateError ::NoCharacter )
2022-04-19 23:20:50 -06:00
}
2022-04-27 20:57:47 -06:00
pub fn set_inventory ( & mut self , inventory : InventoryState ) {
2022-05-01 21:59:34 -06:00
self . proxied_state . character_inventory . insert ( inventory . character_id , inventory ) ;
2022-05-14 13:06:40 -06:00
}
pub fn bank ( & mut self , character_id : & CharacterEntityId ) -> Result < BankState , ItemStateError > {
get_or_clone ( & self . item_state . character_bank , & mut self . proxied_state . character_bank , * character_id , ItemStateError ::NoCharacter )
}
pub fn set_bank ( & mut self , bank : BankState ) {
self . proxied_state . character_bank . insert ( bank . character_id , bank ) ;
2022-04-19 23:20:50 -06:00
}
2022-04-27 20:57:47 -06:00
pub fn floor ( & mut self , character_id : & CharacterEntityId ) -> Result < FloorState , ItemStateError > {
2022-04-27 23:53:26 -06:00
let room_id = get_or_clone ( & self . item_state . character_room , & mut self . proxied_state . character_room , * character_id , ItemStateError ::NoCharacter ) ? ;
2022-04-19 23:20:50 -06:00
Ok ( FloorState {
character_id : * character_id ,
2022-04-27 23:53:26 -06:00
local : get_or_clone ( & self . item_state . character_floor , & mut self . proxied_state . character_floor , * character_id , ItemStateError ::NoCharacter ) ? ,
shared : get_or_clone ( & self . item_state . room_floor , & mut self . proxied_state . room_floor , room_id , ItemStateError ::NoRoom ) ? ,
2022-04-19 23:20:50 -06:00
} )
}
2022-04-27 20:57:47 -06:00
pub fn set_floor ( & mut self , floor : FloorState ) {
2022-04-27 23:53:26 -06:00
let room_id = get_or_clone ( & self . item_state . character_room , & mut self . proxied_state . character_room , floor . character_id , ItemStateError ::NoCharacter ) . unwrap ( ) ;
2022-04-19 23:20:50 -06:00
self . proxied_state . character_floor . insert ( floor . character_id , floor . local ) ;
self . proxied_state . room_floor . insert ( room_id , floor . shared ) ;
}
2022-04-27 20:57:47 -06:00
pub fn new_item_id ( & mut self ) -> Result < ClientItemId , ItemStateError > {
2022-05-01 21:59:34 -06:00
self . item_state . new_item_id ( )
2022-04-19 23:20:50 -06:00
}
}