|
@ -134,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>>,
|
|
|
}
|
|
|
}
|
|
@ -155,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)),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@ -230,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| {
|
|
@ -271,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);
|
|
|
|
|
|
|
|
@ -287,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
|
|
@ -295,8 +327,8 @@ impl ItemState { |
|
|
.unwrap()
|
|
|
.unwrap()
|
|
|
.write()
|
|
|
.write()
|
|
|
.await
|
|
|
.await
|
|
|
.initialize_item_ids(base_inventory_id);
|
|
|
|
|
|
let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000;
|
|
|
|
|
|
|
|
|
.initialize_item_ids(base_item_ids.inventory(&area_client).clone())
|
|
|
|
|
|
.await;
|
|
|
self.character_bank
|
|
|
self.character_bank
|
|
|
.read()
|
|
|
.read()
|
|
|
.await
|
|
|
.await
|
|
@ -304,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
|
|
@ -486,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?,
|
|
|
|
|
|
shared: get_or_clone(&self.item_state.room_floor, &self.proxied_state.room_floor, room_id, ItemStateError::NoRoom).await?,
|
|
|
|
|
|
|
|
|
local: get_or_clone(&self.item_state.character_floor, &self.proxied_state.character_floor, *character_id, ItemStateError::NoCharacter).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);
|
|
|
}
|
|
|
}
|
|
|