redo items to account for client ignoring the assigned item_id and using its own. also item picking up
This commit is contained in:
parent
580a21d9fc
commit
ac28354dd7
@ -2,6 +2,7 @@
|
||||
#![feature(const_generics)]
|
||||
#![feature(maybe_uninit_extra)]
|
||||
#![feature(const_in_array_repeat_expressions)]
|
||||
#![feature(drain_filter)]
|
||||
|
||||
|
||||
|
||||
|
@ -80,7 +80,7 @@ pub struct FullCharacterBytesBuilder<'a> {
|
||||
character: Option<&'a CharacterEntity>,
|
||||
stats: Option<&'a CharacterStats>,
|
||||
level: Option<u32>,
|
||||
inventory: Option<&'a CharacterInventory>,
|
||||
inventory: Option<&'a CharacterInventory<'a>>,
|
||||
key_config: Option<&'a [u8; 0x16C]>,
|
||||
joystick_config: Option<&'a [u8; 0x38]>,
|
||||
symbol_chat: Option<&'a [u8; 1248]>,
|
||||
|
@ -1,27 +1,34 @@
|
||||
#![allow(dead_code)]
|
||||
use std::collections::{HashMap, BTreeMap};
|
||||
use libpso::character::character;//::InventoryItem;
|
||||
use thiserror::Error;
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use crate::entity::character::CharacterEntity;
|
||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use crate::entity::item::{ItemEntityId, ItemEntity, ItemDetail, ItemLocation};
|
||||
use crate::entity::item::{Meseta, NewItemEntity};
|
||||
use crate::entity::item::tool::Tool;
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||
use crate::ship::ship::ClientState;
|
||||
use crate::ship::location::{AreaClient, RoomId};
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ActiveItemId(pub u32);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
struct RoomItemId(RoomId, u32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ClientItemId(pub u32);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum ActiveItemEntityId {
|
||||
Individual(ItemEntityId),
|
||||
Stacked(Vec<ItemEntityId>),
|
||||
Meseta(Meseta),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum HeldItemType {
|
||||
Individual(ItemDetail),
|
||||
Stacked(Tool, usize),
|
||||
@ -48,21 +55,7 @@ impl HeldItemType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InventoryItem {
|
||||
id: ActiveItemId,
|
||||
item: HeldItemType,
|
||||
//slot: usize,
|
||||
equipped: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BankItem {
|
||||
id: ActiveItemId,
|
||||
item: HeldItemType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FloorItemType {
|
||||
Individual(ItemDetail),
|
||||
Stacked(Tool, usize),
|
||||
@ -93,9 +86,18 @@ impl FloorItemType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InventoryItem {
|
||||
entity_id: ActiveItemEntityId,
|
||||
item_id: ClientItemId,
|
||||
item: HeldItemType,
|
||||
equipped: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FloorItem {
|
||||
pub id: ActiveItemId,
|
||||
entity_id: ActiveItemEntityId,
|
||||
pub item_id: ClientItemId,
|
||||
pub item: FloorItemType,
|
||||
pub map_area: MapArea,
|
||||
pub x: f32,
|
||||
@ -104,12 +106,15 @@ pub struct FloorItem {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InventoryError {
|
||||
pub struct BankItem {
|
||||
id: ActiveItemId,
|
||||
item: HeldItemType,
|
||||
}
|
||||
|
||||
pub struct CharacterInventory(Vec<InventoryItem>);
|
||||
|
||||
impl CharacterInventory {
|
||||
pub struct CharacterInventory<'a>(&'a Vec<InventoryItem>);
|
||||
|
||||
impl<'a> CharacterInventory<'a> {
|
||||
pub fn as_client_inventory_items(&self) -> [character::InventoryItem; 30] {
|
||||
self.0.iter()
|
||||
.enumerate()
|
||||
@ -117,7 +122,7 @@ impl CharacterInventory {
|
||||
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.id.0;
|
||||
inventory[slot].item_id = item.item_id.0;
|
||||
// does this do anything?
|
||||
inventory[slot].equipped = if item.equipped { 1 } else { 0 };
|
||||
// because this actually equips the item
|
||||
@ -126,42 +131,60 @@ impl CharacterInventory {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_item(&mut self, item: InventoryItem) -> Result<usize, InventoryError> {
|
||||
self.0.push(item);
|
||||
Ok(self.count() - 1)
|
||||
}
|
||||
|
||||
pub fn count(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Error, Debug)]
|
||||
#[error("")]
|
||||
pub enum ItemManagerError {
|
||||
EntityGatewayError,
|
||||
NoSuchItemId(ClientItemId),
|
||||
NoCharacter(CharacterEntityId),
|
||||
CouldNotAddToInventory(FloorItem),
|
||||
//ItemBelongsToOtherPlayer,
|
||||
Idunnoman,
|
||||
}
|
||||
|
||||
pub struct ItemManager {
|
||||
id: usize,
|
||||
active_to_entity: HashMap<ActiveItemId, ActiveItemEntityId>,
|
||||
id_counter: u32,
|
||||
|
||||
character_inventory: HashMap<CharacterEntityId, Vec<InventoryItem>>,
|
||||
character_floor: HashMap<CharacterEntityId, Vec<FloorItem>>,
|
||||
character_item_id_counter: HashMap<CharacterEntityId, u32>,
|
||||
|
||||
character_room: HashMap<CharacterEntityId, RoomId>,
|
||||
room_floor: HashMap<RoomId, Vec<FloorItem>>,
|
||||
room_item_id_counter: HashMap<RoomId, u32>,
|
||||
}
|
||||
|
||||
impl ItemManager {
|
||||
pub fn new() -> ItemManager {
|
||||
ItemManager {
|
||||
id: 0,
|
||||
active_to_entity: HashMap::new()
|
||||
id_counter: 0,
|
||||
character_inventory: HashMap::new(),
|
||||
character_floor: HashMap::new(),
|
||||
character_item_id_counter: HashMap::new(),
|
||||
character_room: HashMap::new(),
|
||||
room_floor: HashMap::new(),
|
||||
room_item_id_counter: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_id(&mut self) -> ActiveItemId {
|
||||
self.id += 1;
|
||||
ActiveItemId(self.id as u32)
|
||||
pub fn next_global_item_id(&mut self) -> ClientItemId {
|
||||
self.id_counter += 1;
|
||||
ClientItemId(self.id_counter)
|
||||
}
|
||||
|
||||
pub fn get_character_inventory<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> CharacterInventory {
|
||||
pub fn next_drop_item_id(&mut self, room_id: RoomId) -> ClientItemId {
|
||||
let next_id = self.room_item_id_counter.entry(room_id).or_insert(0xF0000000);
|
||||
*next_id += 1;
|
||||
ClientItemId(*next_id)
|
||||
}
|
||||
|
||||
// TODO: Result
|
||||
pub fn load_character<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) {
|
||||
let items = entity_gateway.get_items_by_character(&character);
|
||||
let inventory_items = items.into_iter()
|
||||
.filter_map(|item| {
|
||||
@ -190,18 +213,151 @@ impl ItemManager {
|
||||
})
|
||||
.into_iter()
|
||||
.map(|(_slot, (held_item, entity_id, equipped))| {
|
||||
let id = self.next_id();
|
||||
self.active_to_entity.insert(id, entity_id);
|
||||
let id = self.next_global_item_id();
|
||||
InventoryItem {
|
||||
id: id,
|
||||
entity_id: entity_id,
|
||||
item_id: id,
|
||||
item: held_item,
|
||||
equipped: equipped,
|
||||
}
|
||||
});
|
||||
CharacterInventory(inventory_items.take(30).collect())
|
||||
let k = inventory_items.take(30).collect();
|
||||
self.character_inventory.insert(character.id, k);
|
||||
}
|
||||
|
||||
pub fn drop_item_on_local_floor<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, item_drop: ItemDrop) -> Result<FloorItem, ItemManagerError> {
|
||||
|
||||
pub fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) {
|
||||
let base_id = ((area_client.local_client.id() as u32) << 21) | 0x10000;
|
||||
let inventory = self.character_inventory.get_mut(&character.id).unwrap();
|
||||
for (i, item) in inventory.iter_mut().enumerate() {
|
||||
item.item_id = ClientItemId(base_id + i as u32);
|
||||
}
|
||||
self.character_room.insert(character.id, room_id);
|
||||
self.character_floor.insert(character.id, Vec::new());
|
||||
self.room_floor.entry(room_id).or_insert(Vec::new());
|
||||
self.character_item_id_counter.insert(character.id, base_id + inventory.len() as u32);
|
||||
}
|
||||
|
||||
pub fn get_character_inventory(&self, character: &CharacterEntity) -> Result<CharacterInventory, ItemManagerError> {
|
||||
Ok(CharacterInventory(self.character_inventory.get(&character.id)
|
||||
.ok_or(ItemManagerError::NoCharacter(character.id))?))
|
||||
}
|
||||
|
||||
pub fn remove_character_from_room(&mut self, character: &CharacterEntity) {
|
||||
self.character_inventory.remove(&character.id);
|
||||
self.character_floor.remove(&character.id);
|
||||
self.character_room.remove(&character.id)
|
||||
.as_ref()
|
||||
.map(|room| {
|
||||
if self.character_room.iter().find(|(_, r)| *r == room).is_none() {
|
||||
self.room_floor.remove(room);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_inventory_item_by_id(&self, character: &CharacterEntity, item_id: ClientItemId) -> Result<InventoryItem, ItemManagerError> {
|
||||
let inventory = self.character_inventory.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
inventory.iter()
|
||||
.filter(|item| {
|
||||
item.item_id == item_id
|
||||
})
|
||||
.nth(0)
|
||||
.ok_or(ItemManagerError::NoSuchItemId(item_id))
|
||||
.map(Clone::clone)
|
||||
}
|
||||
|
||||
pub fn get_floor_item_by_id(&self, character: &CharacterEntity, item_id: ClientItemId) -> Result<FloorItem, ItemManagerError> {
|
||||
let floor = self.character_floor.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
let room = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
let shared_floor = self.room_floor.get(room).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
floor.iter()
|
||||
.chain(shared_floor.iter())
|
||||
.filter(|item| {
|
||||
item.item_id == item_id
|
||||
})
|
||||
.nth(0)
|
||||
.ok_or(ItemManagerError::NoSuchItemId(item_id))
|
||||
.map(Clone::clone)
|
||||
}
|
||||
|
||||
pub fn character_picks_up_item<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &mut CharacterEntity, floor_item: FloorItem) -> Result<(), ItemManagerError> {
|
||||
let local_floor = self.character_floor.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
let shared_floor = self.room_floor.get_mut(&room_id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
|
||||
if let Some(_) = local_floor.iter().find(|i| i.item_id == floor_item.item_id) {
|
||||
local_floor.retain(|item| {
|
||||
item.item_id != floor_item.item_id
|
||||
});
|
||||
}
|
||||
else if let Some(_) = shared_floor.iter().find(|i| i.item_id == floor_item.item_id) {
|
||||
shared_floor.retain(|item| {
|
||||
item.item_id != floor_item.item_id
|
||||
});
|
||||
}
|
||||
else {
|
||||
return Err(ItemManagerError::NoSuchItemId(floor_item.item_id))
|
||||
}
|
||||
|
||||
if inventory.len() >= 30 {
|
||||
return Err(ItemManagerError::CouldNotAddToInventory(floor_item));
|
||||
}
|
||||
|
||||
match floor_item.item {
|
||||
FloorItemType::Individual(item) => {
|
||||
let inventory_item = InventoryItem {
|
||||
entity_id: floor_item.entity_id,
|
||||
item_id: floor_item.item_id,
|
||||
item: HeldItemType::Individual(item.clone()),
|
||||
equipped: false,
|
||||
};
|
||||
|
||||
if let ActiveItemEntityId::Individual(item_id) = &inventory_item.entity_id {
|
||||
entity_gateway.save_item(&ItemEntity {
|
||||
id: *item_id,
|
||||
item: item,
|
||||
location: ItemLocation::Inventory {
|
||||
character_id: character.id,
|
||||
slot: inventory.len(),
|
||||
equipped: false,
|
||||
},
|
||||
}); // TODO: error check
|
||||
inventory.push(inventory_item);
|
||||
} // else something went very wrong TODO: log it
|
||||
},
|
||||
FloorItemType::Stacked(tool, usize) => {
|
||||
let inventory_item = InventoryItem {
|
||||
entity_id: floor_item.entity_id,
|
||||
item_id: floor_item.item_id,
|
||||
item: HeldItemType::Stacked(tool, usize),
|
||||
equipped: false,
|
||||
};
|
||||
|
||||
if let ActiveItemEntityId::Stacked(item_ids) = &inventory_item.entity_id {
|
||||
for item_id in item_ids {
|
||||
entity_gateway.save_item(&ItemEntity {
|
||||
id: *item_id,
|
||||
item: ItemDetail::Tool(tool),
|
||||
location: ItemLocation::Inventory {
|
||||
character_id: character.id,
|
||||
slot: inventory.len(),
|
||||
equipped: false,
|
||||
},
|
||||
}); // TODO: error check
|
||||
};
|
||||
inventory.push(inventory_item);
|
||||
} // else something went very wrong TODO: log it
|
||||
},
|
||||
FloorItemType::Meseta(meseta) => {
|
||||
character.meseta += meseta.0;
|
||||
entity_gateway.save_character(&character);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enemy_drop_item_on_local_floor<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, item_drop: ItemDrop) -> Result<&FloorItem, ItemManagerError> {
|
||||
let item = match item_drop.item {
|
||||
ItemDropType::Weapon(w) => FloorItemType::Individual(ItemDetail::Weapon(w)),
|
||||
ItemDropType::Armor(w) => FloorItemType::Individual(ItemDetail::Armor(w)),
|
||||
@ -214,8 +370,8 @@ impl ItemManager {
|
||||
//ItemDropType::Tool(t) if !t.is_stackable() => FloorItemType::Individual(ItemDetail::Tool(w)),
|
||||
ItemDropType::Meseta(m) => FloorItemType::Meseta(Meseta(m))
|
||||
};
|
||||
|
||||
let active_entity_ids = match &item {
|
||||
|
||||
let entity_id = match &item {
|
||||
FloorItemType::Individual(i) => {
|
||||
let entity = entity_gateway.create_item(NewItemEntity {
|
||||
item: i.clone(),
|
||||
@ -250,70 +406,86 @@ impl ItemManager {
|
||||
FloorItemType::Meseta(m) => ActiveItemEntityId::Meseta(m.clone()),
|
||||
};
|
||||
|
||||
let id = self.next_id();
|
||||
self.active_to_entity.insert(id, active_entity_ids);
|
||||
Ok(FloorItem {
|
||||
id: id,
|
||||
let room_id = *self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
let item_id = self.next_drop_item_id(room_id);
|
||||
|
||||
let floor_item = FloorItem {
|
||||
entity_id: entity_id,
|
||||
item_id: item_id,
|
||||
item: item,
|
||||
map_area: item_drop.map_area,
|
||||
x: item_drop.x,
|
||||
y: item_drop.y,
|
||||
z: item_drop.z,
|
||||
})
|
||||
};
|
||||
|
||||
self.character_floor.entry(character.id).or_insert(Vec::new()).push(floor_item);
|
||||
self.character_floor.get(&character.id).ok_or(ItemManagerError::Idunnoman)?.last().ok_or(ItemManagerError::Idunnoman)
|
||||
}
|
||||
|
||||
pub fn move_item_from_floor_to_inventory<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, client: &mut ClientState, floor_item: FloorItem) -> Result<(), ItemManagerError> {
|
||||
match floor_item.item {
|
||||
FloorItemType::Individual(item) => {
|
||||
let inventory_item = InventoryItem {
|
||||
id: floor_item.id,
|
||||
item: HeldItemType::Individual(item.clone()),
|
||||
equipped: false,
|
||||
};
|
||||
pub fn player_drop_item_on_shared_floor<EG: EntityGateway>(&mut self,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
inventory_item: InventoryItem,
|
||||
item_drop_location: (MapArea, f32, f32, f32))
|
||||
-> Result<(), ItemManagerError> {
|
||||
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
let shared_floor = self.room_floor.get_mut(&room_id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||
|
||||
let item_entity_id = self.active_to_entity.get(&floor_item.id).unwrap(); // TODO: unwrap
|
||||
if let ActiveItemEntityId::Individual(item_id) = item_entity_id {
|
||||
let slot = client.inventory.add_item(inventory_item).unwrap(); // TODO: unwrap
|
||||
inventory
|
||||
.drain_filter(|i| i.item_id == inventory_item.item_id)
|
||||
.nth(0)
|
||||
.ok_or(ItemManagerError::NoSuchItemId(inventory_item.item_id))?;
|
||||
|
||||
let room_floor_item = FloorItem {
|
||||
entity_id: inventory_item.entity_id,
|
||||
item_id: inventory_item.item_id,
|
||||
item: match inventory_item.item {
|
||||
HeldItemType::Individual(item) => FloorItemType::Individual(item),
|
||||
HeldItemType::Stacked(tool, count) => FloorItemType::Stacked(tool, count),
|
||||
},
|
||||
map_area: item_drop_location.0,
|
||||
x: item_drop_location.1,
|
||||
y: item_drop_location.2,
|
||||
z: item_drop_location.3,
|
||||
};
|
||||
|
||||
match &room_floor_item.item {
|
||||
FloorItemType::Individual(item) => {
|
||||
if let ActiveItemEntityId::Individual(item_id) = &room_floor_item.entity_id {
|
||||
entity_gateway.save_item(&ItemEntity {
|
||||
id: *item_id,
|
||||
item: item,
|
||||
location: ItemLocation::Inventory {
|
||||
character_id: client.character.id,
|
||||
slot: slot,
|
||||
equipped: false,
|
||||
},
|
||||
item: item.clone(),
|
||||
location: ItemLocation::SharedFloor {
|
||||
map_area: item_drop_location.0,
|
||||
x: item_drop_location.1,
|
||||
y: item_drop_location.2,
|
||||
z: item_drop_location.3,
|
||||
}
|
||||
}); // TODO: error check
|
||||
} // else something went very wrong TODO: log it
|
||||
} // else something went very wrong: TODO: log it
|
||||
},
|
||||
FloorItemType::Stacked(tool, usize) => {
|
||||
let inventory_item = InventoryItem {
|
||||
id: floor_item.id,
|
||||
item: HeldItemType::Stacked(tool, usize),
|
||||
equipped: false,
|
||||
};
|
||||
|
||||
let item_entity_id = self.active_to_entity.get(&floor_item.id).unwrap(); // TODO: unwrap
|
||||
if let ActiveItemEntityId::Stacked(item_ids) = item_entity_id {
|
||||
let slot = client.inventory.add_item(inventory_item).unwrap(); // TODO: unwrap
|
||||
FloorItemType::Stacked(tool, _count) => {
|
||||
if let ActiveItemEntityId::Stacked(item_ids) = &room_floor_item.entity_id {
|
||||
for item_id in item_ids {
|
||||
entity_gateway.save_item(&ItemEntity {
|
||||
id: *item_id,
|
||||
item: ItemDetail::Tool(tool),
|
||||
location: ItemLocation::Inventory {
|
||||
character_id: client.character.id,
|
||||
slot: slot,
|
||||
equipped: false,
|
||||
item: ItemDetail::Tool(*tool),
|
||||
location: ItemLocation::SharedFloor {
|
||||
map_area: item_drop_location.0,
|
||||
x: item_drop_location.1,
|
||||
y: item_drop_location.2,
|
||||
z: item_drop_location.3,
|
||||
},
|
||||
}); // TODO: error check
|
||||
}
|
||||
} // else something went very wrong TODO: log it
|
||||
},
|
||||
FloorItemType::Meseta(meseta) => {
|
||||
client.character.meseta += meseta.0;
|
||||
entity_gateway.save_character(&client.character);
|
||||
}
|
||||
_ => {}, // can meseta get here?
|
||||
}
|
||||
|
||||
shared_floor.push(room_floor_item);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,8 @@ pub enum AreaType {
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct LobbyId(pub usize);
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct RoomId(pub usize);
|
||||
|
||||
impl LobbyId {
|
||||
|
@ -4,19 +4,21 @@ use crate::common::leveltable::CharacterLevelTable;
|
||||
use crate::ship::ship::{ShipError, Clients};
|
||||
use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError};
|
||||
use crate::ship::packet::builder::{player_info};
|
||||
use crate::ship::items::ItemManager;
|
||||
|
||||
|
||||
pub fn join_lobby(id: ClientId,
|
||||
lobby: LobbyId,
|
||||
client_location: &ClientLocation,
|
||||
clients: &Clients,
|
||||
item_manager: &ItemManager,
|
||||
level_table: &CharacterLevelTable)
|
||||
-> Result<JoinLobby, ShipError> {
|
||||
let lobby_clients = client_location.get_clients_in_lobby(lobby).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let playerinfo = lobby_clients.iter()
|
||||
.map(|area_client| {
|
||||
let client = clients.get(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client)).unwrap();
|
||||
player_info(0x100, &client, area_client, level_table)
|
||||
player_info(0x100, &client, area_client, item_manager, level_table)
|
||||
});
|
||||
|
||||
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap();
|
||||
@ -38,6 +40,7 @@ pub fn add_to_lobby(id: ClientId,
|
||||
lobby: LobbyId,
|
||||
client_location: &ClientLocation,
|
||||
clients: &Clients,
|
||||
item_manager: &ItemManager,
|
||||
level_table: &CharacterLevelTable)
|
||||
-> Result<AddToLobby, ShipError> {
|
||||
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap();
|
||||
@ -52,7 +55,7 @@ pub fn add_to_lobby(id: ClientId,
|
||||
block: client.block as u16,
|
||||
event: 0,
|
||||
padding: 0,
|
||||
playerinfo: player_info(0x100, &client, &area_client, level_table),
|
||||
playerinfo: player_info(0x100, &client, &area_client, item_manager, level_table),
|
||||
})
|
||||
}
|
||||
|
||||
@ -68,4 +71,4 @@ pub fn remove_from_lobby(id: ClientId,
|
||||
leader: prev_area_leader_index,
|
||||
_padding: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDr
|
||||
z: item_drop.z,
|
||||
y: item_drop.y,
|
||||
item_bytes: item_bytes[0..12].try_into()?,
|
||||
item_id: item_drop.id.0,
|
||||
item_id: item_drop.item_id.0,
|
||||
item_bytes2: item_bytes[12..16].try_into()?,
|
||||
unknown2: 0,
|
||||
})
|
||||
@ -29,7 +29,7 @@ pub fn create_item(area_client: AreaClient, item: &FloorItem) -> Result<CreateIt
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
item_data: bytes[0..12].try_into()?,
|
||||
item_id: item.id.0,
|
||||
item_id: item.item_id.0,
|
||||
item_data2: bytes[12..16].try_into()?,
|
||||
unknown: 0,
|
||||
})
|
||||
@ -43,6 +43,6 @@ pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Resu
|
||||
unknown: 0,
|
||||
area: item.map_area.area_value(),
|
||||
unknown2: 0,
|
||||
item_id: item.id.0,
|
||||
item_id: item.item_id.0,
|
||||
})
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use crate::common::leveltable::CharacterLevelTable;
|
||||
use crate::ship::character::CharacterBytesBuilder;
|
||||
use crate::ship::ship::ClientState;
|
||||
use crate::ship::location::AreaClient;
|
||||
use crate::ship::items::ItemManager;
|
||||
|
||||
pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader {
|
||||
PlayerHeader {
|
||||
@ -20,8 +21,9 @@ pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -
|
||||
}
|
||||
}
|
||||
|
||||
pub fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, level_table: &CharacterLevelTable) -> PlayerInfo {
|
||||
pub fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, item_manager: &ItemManager, level_table: &CharacterLevelTable) -> PlayerInfo {
|
||||
let (level, stats) = level_table.get_stats_from_exp(client.character.char_class, client.character.exp);
|
||||
let inventory = item_manager.get_character_inventory(&client.character).unwrap();
|
||||
let character = CharacterBytesBuilder::new()
|
||||
.character(&client.character)
|
||||
.stats(&stats)
|
||||
@ -30,11 +32,11 @@ pub fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, lev
|
||||
PlayerInfo {
|
||||
header: player_header(tag, client, area_client),
|
||||
inventory: Inventory {
|
||||
item_count: client.inventory.count() as u8,
|
||||
item_count: inventory.count() as u8,
|
||||
hp_mats_used: 0, // TODO: materials
|
||||
tp_mats_used: 0, // TODO: materials
|
||||
language: 0, // TODO: account language
|
||||
items: client.inventory.as_client_inventory_items(),
|
||||
items: inventory.as_client_inventory_items(),
|
||||
},
|
||||
character: character,
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use crate::common::leveltable::CharacterLevelTable;
|
||||
use crate::ship::ship::{ShipError, ClientState, Clients};
|
||||
use crate::ship::location::{ClientLocation, RoomId, AreaClient, ClientLocationError};
|
||||
use crate::ship::room::RoomState;
|
||||
use crate::ship::items::ItemManager;
|
||||
use crate::ship::packet::builder::{player_header, player_info};
|
||||
|
||||
pub fn join_room(id: ClientId,
|
||||
@ -51,6 +52,7 @@ pub fn add_to_room(_id: ClientId,
|
||||
client: &ClientState,
|
||||
area_client: &AreaClient,
|
||||
leader: &AreaClient,
|
||||
item_manager: &ItemManager,
|
||||
level_table: &CharacterLevelTable,
|
||||
_room_id: RoomId,
|
||||
)
|
||||
@ -65,7 +67,7 @@ pub fn add_to_room(_id: ClientId,
|
||||
block: 0,
|
||||
event: 0,
|
||||
padding: 0,
|
||||
playerinfo: player_info(0x10000, client, &area_client, level_table),
|
||||
playerinfo: player_info(0x10000, client, &area_client, item_manager, level_table),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,9 @@ pub fn validate_login<EG: EntityGateway>(id: ClientId,
|
||||
.clone();
|
||||
let settings = entity_gateway.get_user_settings_by_user(&user)
|
||||
.ok_or(ShipError::ClientNotFound(id))?;
|
||||
let inventory = item_manager.get_character_inventory(entity_gateway, &character);
|
||||
|
||||
clients.insert(id, ClientState::new(user, settings, character, inventory, pkt.session));
|
||||
item_manager.load_character(entity_gateway, &character);
|
||||
clients.insert(id, ClientState::new(user, settings, character, pkt.session));
|
||||
vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(&&ship_name, 3))]
|
||||
},
|
||||
Err(err) => {
|
||||
|
@ -5,7 +5,7 @@ use crate::common::serverstate::ClientId;
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms};
|
||||
use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||
use crate::ship::drops::ItemDrop;
|
||||
use crate::ship::items::{ItemManager, ItemManagerError, FloorItemType};
|
||||
use crate::ship::items::{ItemManager, FloorItemType, ClientItemId};
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use libpso::utf8_to_utf16_array;
|
||||
use crate::ship::packet::builder;
|
||||
@ -84,9 +84,8 @@ where
|
||||
item: item_drop_type,
|
||||
};
|
||||
let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?;
|
||||
let floor_item = item_manager.drop_item_on_local_floor(entity_gateway, &client.character, item_drop).unwrap(); // TODO: unwrap
|
||||
let floor_item = item_manager.enemy_drop_item_on_local_floor(entity_gateway, &client.character, item_drop).unwrap(); // TODO: unwrap
|
||||
let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &floor_item)?;
|
||||
client.floor_items.push(floor_item);
|
||||
Ok((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg)))))
|
||||
})
|
||||
.filter_map(|item_drop_pkt| {
|
||||
@ -103,81 +102,40 @@ pub fn pickup_item<EG>(id: ClientId,
|
||||
entity_gateway: &mut EG,
|
||||
client_location: &ClientLocation,
|
||||
clients: &mut Clients,
|
||||
rooms: &mut Rooms,
|
||||
item_manager: &mut ItemManager)
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError>
|
||||
where
|
||||
EG: EntityGateway
|
||||
{
|
||||
#[derive(Copy, Clone)]
|
||||
enum ItemFloor {
|
||||
Local,
|
||||
Shared
|
||||
}
|
||||
|
||||
let mut client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let room = rooms.get_mut(room_id.0)
|
||||
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
|
||||
.as_mut()
|
||||
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?;
|
||||
let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
|
||||
let (item_index, (_, floor)) = client.floor_items.iter()
|
||||
.zip(std::iter::repeat(ItemFloor::Local))
|
||||
.enumerate()
|
||||
.filter(|(_, (item, _))| item.id.0 == pickup_item.item_id)
|
||||
.next()
|
||||
.or_else(|| {
|
||||
room.floor_items.iter()
|
||||
.zip(std::iter::repeat(ItemFloor::Shared))
|
||||
.enumerate()
|
||||
.filter(|(_, (item, _))| item.id.0 == pickup_item.item_id)
|
||||
.next()
|
||||
})
|
||||
.ok_or(ShipError::PickUpInvalidItemId(pickup_item.item_id))?;
|
||||
|
||||
let item = match floor {
|
||||
ItemFloor::Local => client.floor_items.remove(item_index),
|
||||
ItemFloor::Shared => room.floor_items.remove(item_index),
|
||||
};
|
||||
|
||||
let item = item_manager.get_floor_item_by_id(&client.character, ClientItemId(pickup_item.item_id))?;
|
||||
let remove_item = builder::message::remove_item_from_floor(area_client, &item)?;
|
||||
let create_item = match item.item {
|
||||
FloorItemType::Meseta(_) => None,
|
||||
_ => Some(builder::message::create_item(area_client, &item)?),
|
||||
};
|
||||
match item_manager.move_item_from_floor_to_inventory(entity_gateway, &mut client, item) {
|
||||
|
||||
match item_manager.character_picks_up_item(entity_gateway, &mut client.character, item) {
|
||||
Ok(_) => {
|
||||
Ok(Box::new(Vec::new().into_iter()
|
||||
.chain(clients_in_area.clone().into_iter()
|
||||
.filter(move |c| {
|
||||
match floor {
|
||||
ItemFloor::Local => c.client == id,
|
||||
ItemFloor::Shared => true,
|
||||
}
|
||||
})
|
||||
.map(move |c| {
|
||||
(c.client, SendShipPacket::Message(Message::new(GameMessage::RemoveItemFromFloor(remove_item.clone()))))
|
||||
}))
|
||||
.chain(clients_in_area.into_iter().filter_map(move |c| {
|
||||
//(c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item.clone()))))
|
||||
create_item.clone().map(|ci| (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(ci)))))
|
||||
}
|
||||
.chain(clients_in_area.into_iter().
|
||||
filter_map(move |c| {
|
||||
create_item.clone().map(|ci| (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(ci)))))
|
||||
}
|
||||
)))
|
||||
)
|
||||
},
|
||||
Err(err) => {
|
||||
// inventory full, probably
|
||||
if let ItemManagerError::CouldNotAddToInventory(item) = err {
|
||||
match floor {
|
||||
ItemFloor::Local => client.floor_items.push(item),
|
||||
ItemFloor::Shared => room.floor_items.push(item),
|
||||
}
|
||||
}
|
||||
warn!("character {:?} could not pick up item: {:?}", client.character.id, err);
|
||||
Ok(Box::new(None.into_iter()))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,24 +4,29 @@ use crate::common::leveltable::CharacterLevelTable;
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms};
|
||||
use crate::ship::character::{FullCharacterBytesBuilder};
|
||||
use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError};
|
||||
//use crate::ship::items::;
|
||||
use crate::ship::packet;
|
||||
use crate::ship::items::ItemManager;
|
||||
|
||||
// this function needs a better home
|
||||
pub fn block_selected(id: ClientId,
|
||||
pkt: &MenuSelect,
|
||||
clients: &mut Clients,
|
||||
level_table: &CharacterLevelTable)
|
||||
-> Result<Vec<SendShipPacket>, ShipError> {
|
||||
pkt: &MenuSelect,
|
||||
clients: &mut Clients,
|
||||
item_manager: &ItemManager,
|
||||
level_table: &CharacterLevelTable)
|
||||
-> Result<Vec<SendShipPacket>, ShipError> {
|
||||
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
client.block = pkt.item as u32;
|
||||
|
||||
let (level, stats) = level_table.get_stats_from_exp(client.character.char_class, client.character.exp);
|
||||
|
||||
let inventory = item_manager.get_character_inventory(&client.character).unwrap();
|
||||
|
||||
let fc = FullCharacterBytesBuilder::new()
|
||||
.character(&client.character)
|
||||
.stats(&stats)
|
||||
.level(level)
|
||||
.inventory(&client.inventory)
|
||||
.inventory(&inventory)
|
||||
.key_config(&client.settings.settings.key_config)
|
||||
.joystick_config(&client.settings.settings.joystick_config)
|
||||
.symbol_chat(&client.settings.settings.symbol_chats)
|
||||
@ -41,11 +46,12 @@ pub fn send_player_to_lobby(id: ClientId,
|
||||
_pkt: &CharData,
|
||||
client_location: &mut ClientLocation,
|
||||
clients: &Clients,
|
||||
item_manager: &ItemManager,
|
||||
level_table: &CharacterLevelTable)
|
||||
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
|
||||
let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).map_err(|_| ShipError::TooManyClients)?;
|
||||
let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, level_table)?;
|
||||
let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, level_table)?;
|
||||
let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_manager, level_table)?;
|
||||
let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_manager, level_table)?;
|
||||
let neighbors = client_location.get_client_neighbors(id).unwrap();
|
||||
Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))]
|
||||
.into_iter()
|
||||
@ -57,9 +63,11 @@ pub fn change_lobby(id: ClientId,
|
||||
requested_lobby: u32,
|
||||
client_location: &mut ClientLocation,
|
||||
clients: &Clients,
|
||||
item_manager: &mut ItemManager,
|
||||
level_table: &CharacterLevelTable,
|
||||
ship_rooms: &mut Rooms)
|
||||
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
|
||||
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let prev_area = client_location.get_area(id).map_err(|err| -> ClientLocationError {err.into()})?;
|
||||
match prev_area {
|
||||
RoomLobby::Lobby(old_lobby) => {
|
||||
@ -71,6 +79,7 @@ pub fn change_lobby(id: ClientId,
|
||||
if client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError {err.into()})?.len() == 0 {
|
||||
ship_rooms[old_room.0] = None;
|
||||
}
|
||||
item_manager.remove_character_from_room(&client.character);
|
||||
},
|
||||
}
|
||||
let leave_lobby = packet::builder::lobby::remove_from_lobby(id, client_location)?;
|
||||
@ -87,8 +96,8 @@ pub fn change_lobby(id: ClientId,
|
||||
}
|
||||
}
|
||||
}
|
||||
let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, level_table)?;
|
||||
let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, level_table)?;
|
||||
let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_manager, level_table)?;
|
||||
let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_manager, level_table)?;
|
||||
let neighbors = client_location.get_client_neighbors(id).unwrap();
|
||||
Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))]
|
||||
.into_iter()
|
||||
|
@ -1,8 +1,12 @@
|
||||
use log::warn;
|
||||
use libpso::packet::ship::*;
|
||||
use libpso::packet::messages::*;
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use crate::common::serverstate::ClientId;
|
||||
use crate::ship::ship::{SendShipPacket, Rooms};
|
||||
use crate::ship::location::{ClientLocation, RoomLobby};
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients};
|
||||
use crate::ship::location::{ClientLocation, ClientLocationError, RoomLobby};
|
||||
use crate::ship::map::{MapArea};
|
||||
use crate::ship::items::{ItemManager, ClientItemId};
|
||||
|
||||
pub fn request_exp(id: ClientId,
|
||||
request_exp: &RequestExp,
|
||||
@ -19,3 +23,31 @@ pub fn request_exp(id: ClientId,
|
||||
};
|
||||
Box::new(None.into_iter())
|
||||
}
|
||||
|
||||
pub fn player_drop_item<EG>(id: ClientId,
|
||||
player_drop_item: &PlayerDropItem2,
|
||||
entity_gateway: &mut EG,
|
||||
client_location: &ClientLocation,
|
||||
clients: &mut Clients,
|
||||
rooms: &mut Rooms,
|
||||
item_manager: &mut ItemManager)
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError>
|
||||
where
|
||||
EG: EntityGateway
|
||||
{
|
||||
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let room = rooms.get_mut(room_id.0)
|
||||
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
|
||||
.as_mut()
|
||||
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?;
|
||||
let area = MapArea::from_value(&room.mode.episode(), player_drop_item.area as u32)?;
|
||||
let item = item_manager.get_inventory_item_by_id(&client.character, ClientItemId(player_drop_item.item_id))?;
|
||||
item_manager.player_drop_item_on_shared_floor(entity_gateway, &client.character, item, (area, player_drop_item.x, player_drop_item.y, player_drop_item.z))?;
|
||||
let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let pdi = player_drop_item.clone();
|
||||
Ok(Box::new(clients_in_area.into_iter()
|
||||
.map(move |c| {
|
||||
(c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerDropItem2(pdi.clone()))))
|
||||
})))
|
||||
}
|
||||
|
@ -5,11 +5,13 @@ use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients};
|
||||
use crate::ship::location::{ClientLocation, RoomId, RoomLobby, ClientLocationError};
|
||||
use crate::ship::packet::builder;
|
||||
use crate::ship::room;
|
||||
use crate::ship::items::ItemManager;
|
||||
|
||||
pub fn create_room(id: ClientId,
|
||||
create_room: &CreateRoom,
|
||||
client_location: &mut ClientLocation,
|
||||
clients: &mut Clients,
|
||||
item_manager: &mut ItemManager,
|
||||
rooms: &mut Rooms)
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
|
||||
let area = client_location.get_area(id).unwrap();
|
||||
@ -21,6 +23,8 @@ pub fn create_room(id: ClientId,
|
||||
let mut room = room::RoomState::from_create_room(create_room, client.character.section_id).unwrap();
|
||||
room.bursting = true;
|
||||
|
||||
item_manager.add_character_to_room(room_id, &client.character, area_client);
|
||||
|
||||
let join_room = builder::room::join_room(id, clients, client_location, room_id, &room)?;
|
||||
rooms[room_id.0] = Some(room);
|
||||
|
||||
@ -54,6 +58,7 @@ pub fn join_room(id: ClientId,
|
||||
pkt: &MenuSelect,
|
||||
client_location: &mut ClientLocation,
|
||||
clients: &mut Clients,
|
||||
item_manager: &mut ItemManager,
|
||||
level_table: &CharacterLevelTable,
|
||||
rooms: &mut Rooms)
|
||||
-> Result<Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send>, ShipError> {
|
||||
@ -73,11 +78,13 @@ pub fn join_room(id: ClientId,
|
||||
let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let join_room = builder::room::join_room(id, clients, client_location, room_id, &room)?;
|
||||
let add_to = builder::room::add_to_room(id, &client, &area_client, &leader, level_table, room_id)?;
|
||||
let add_to = builder::room::add_to_room(id, &client, &area_client, &leader, item_manager, level_table, room_id)?;
|
||||
|
||||
let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap();
|
||||
room.bursting = true;
|
||||
|
||||
item_manager.add_character_to_room(room_id, &client.character, area_client);
|
||||
|
||||
let mut result: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = Box::new(
|
||||
vec![(id, SendShipPacket::JoinRoom(join_room))]
|
||||
.into_iter()
|
||||
|
@ -1,11 +1,9 @@
|
||||
#![allow(dead_code)]
|
||||
use std::convert::{From, Into, TryFrom, TryInto};
|
||||
|
||||
use rand::Rng;
|
||||
use crate::ship::map::Maps;
|
||||
use crate::ship::drops::DropTable;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::items::FloorItem;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RoomCreationError {
|
||||
@ -147,24 +145,16 @@ pub struct RoomState {
|
||||
pub mode: RoomMode,
|
||||
pub name: String,
|
||||
pub password: [u16; 16],
|
||||
//pub maps: [u32; 0x20],
|
||||
pub maps: Maps,
|
||||
pub drop_table: Box<DropTable<rand_chacha::ChaCha20Rng>>,
|
||||
pub section_id: SectionID,
|
||||
pub random_seed: u32,
|
||||
pub bursting: bool,
|
||||
pub floor_items: Vec<FloorItem>,
|
||||
// items on ground
|
||||
// enemy info
|
||||
}
|
||||
|
||||
impl RoomState {
|
||||
/*fn new(mode: RoomMode) -> Room {
|
||||
Room {
|
||||
mode: mode,
|
||||
}
|
||||
}*/
|
||||
|
||||
pub fn get_flags_for_room_list(&self) -> u8 {
|
||||
let mut flags = 0u8;
|
||||
|
||||
@ -233,11 +223,6 @@ impl RoomState {
|
||||
section_id: section_id,
|
||||
drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)),
|
||||
bursting: false,
|
||||
floor_items: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn map_headers(&self) -> [u32; 0x20] {
|
||||
self.maps.map_headers()
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocation
|
||||
|
||||
use crate::ship::items;
|
||||
use crate::ship::room;
|
||||
use crate::ship::map::MapsError;
|
||||
use crate::ship::map::{MapsError, MapAreaError};
|
||||
use crate::ship::packet::handler;
|
||||
|
||||
pub const SHIP_PORT: u16 = 23423;
|
||||
@ -41,11 +41,14 @@ pub enum ShipError {
|
||||
TooManyClients,
|
||||
ClientLocationError(#[from] ClientLocationError),
|
||||
MapsError(#[from] MapsError),
|
||||
MapAreaError(#[from] MapAreaError),
|
||||
InvalidRoom(u32),
|
||||
MonsterAlreadyDroppedItem(ClientId, u16),
|
||||
SliceError(#[from] std::array::TryFromSliceError),
|
||||
ItemError, // TODO: refine this
|
||||
PickUpInvalidItemId(u32),
|
||||
DropInvalidItemId(u32),
|
||||
ItemManagerError(#[from] items::ItemManagerError)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -158,22 +161,16 @@ pub struct ClientState {
|
||||
pub character: CharacterEntity,
|
||||
session: Session,
|
||||
//guildcard: GuildCard,
|
||||
pub inventory: items::CharacterInventory,
|
||||
//bank: Bank,
|
||||
pub floor_items: Vec<items::FloorItem>,
|
||||
pub block: u32,
|
||||
}
|
||||
|
||||
impl ClientState {
|
||||
pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, inventory: items::CharacterInventory, /*bank: Bank,*/ session: Session) -> ClientState {
|
||||
pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, session: Session) -> ClientState {
|
||||
ClientState {
|
||||
user: user,
|
||||
settings: settings,
|
||||
character: character,
|
||||
session: session,
|
||||
inventory: inventory,
|
||||
//bank: bank,
|
||||
floor_items: Vec::new(),
|
||||
block: 1,
|
||||
}
|
||||
}
|
||||
@ -187,7 +184,7 @@ pub struct ShipServerState<EG: EntityGateway> {
|
||||
level_table: CharacterLevelTable,
|
||||
name: String,
|
||||
rooms: Rooms,
|
||||
item_database: items::ItemManager,
|
||||
item_manager: items::ItemManager,
|
||||
}
|
||||
|
||||
impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
@ -199,7 +196,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
level_table: CharacterLevelTable::new(),
|
||||
name: "Sona-Nyl".into(),
|
||||
rooms: [None; MAX_ROOMS],
|
||||
item_database: items::ItemManager::new(),
|
||||
item_manager: items::ItemManager::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,6 +205,9 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
GameMessage::RequestExp(request_exp) => {
|
||||
handler::message::request_exp(id, request_exp, &self.client_location, &self.rooms)
|
||||
},
|
||||
GameMessage::PlayerDropItem2(player_drop_item) => {
|
||||
handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_manager).unwrap()
|
||||
},
|
||||
_ => {
|
||||
let cmsg = msg.clone();
|
||||
Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter()
|
||||
@ -225,10 +225,10 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
handler::direct_message::guildcard_send(id, guildcard_send, target, &self.client_location, &self.clients)
|
||||
},
|
||||
GameMessage::RequestItem(request_item) => {
|
||||
handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_database).unwrap()
|
||||
handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_manager).unwrap()
|
||||
},
|
||||
GameMessage::PickupItem(pickup_item) => {
|
||||
handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_database).unwrap()
|
||||
handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).unwrap()
|
||||
},
|
||||
_ => {
|
||||
let cmsg = msg.clone();
|
||||
@ -265,12 +265,12 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
|
||||
Ok(match pkt {
|
||||
RecvShipPacket::Login(login) => {
|
||||
Box::new(handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_database, &self.name)?.into_iter().map(move |pkt| (id, pkt)))
|
||||
Box::new(handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager, &self.name)?.into_iter().map(move |pkt| (id, pkt)))
|
||||
},
|
||||
RecvShipPacket::MenuSelect(menuselect) => {
|
||||
match menuselect.menu {
|
||||
BLOCK_MENU_ID => Box::new(handler::lobby::block_selected(id, menuselect, &mut self.clients, &self.level_table)?.into_iter().map(move |pkt| (id, pkt))),
|
||||
ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut self.client_location, &mut self.clients, &self.level_table, &mut self.rooms)?,
|
||||
BLOCK_MENU_ID => Box::new(handler::lobby::block_selected(id, menuselect, &mut self.clients, &self.item_manager, &self.level_table)?.into_iter().map(move |pkt| (id, pkt))),
|
||||
ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut self.client_location, &mut self.clients, &mut self.item_manager, &self.level_table, &mut self.rooms)?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
@ -282,14 +282,14 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
||||
menu: room_password_req.menu,
|
||||
item: room_password_req.item,
|
||||
};
|
||||
handler::room::join_room(id, &menuselect, &mut self.client_location, &mut self.clients, &self.level_table, &mut self.rooms)?
|
||||
handler::room::join_room(id, &menuselect, &mut self.client_location, &mut self.clients, &mut self.item_manager, &self.level_table, &mut self.rooms)?
|
||||
}
|
||||
else {
|
||||
Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))].into_iter())
|
||||
}
|
||||
},
|
||||
RecvShipPacket::CharData(chardata) => {
|
||||
Box::new(handler::lobby::send_player_to_lobby(id, chardata, &mut self.client_location, &self.clients, &self.level_table)?.into_iter())
|
||||
Box::new(handler::lobby::send_player_to_lobby(id, chardata, &mut self.client_location, &self.clients, &self.item_manager, &self.level_table)?.into_iter())
|
||||
},
|
||||
RecvShipPacket::Message(msg) => {
|
||||
self.message(id, msg)
|
||||
@ -301,7 +301,7 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
||||
Box::new(handler::communication::player_chat(id, msg, &self.client_location, &self.clients)?.into_iter())
|
||||
},
|
||||
RecvShipPacket::CreateRoom(create_room) => {
|
||||
handler::room::create_room(id, create_room, &mut self.client_location, &mut self.clients, &mut self.rooms)?
|
||||
handler::room::create_room(id, create_room, &mut self.client_location, &mut self.clients, &mut self.item_manager, &mut self.rooms)?
|
||||
},
|
||||
RecvShipPacket::RoomNameRequest(_req) => {
|
||||
handler::room::room_name_request(id, &self.client_location, &self.rooms)
|
||||
@ -329,14 +329,15 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
||||
handler::room::done_bursting(id, &self.client_location, &mut self.rooms)
|
||||
},
|
||||
RecvShipPacket::LobbySelect(pkt) => {
|
||||
Box::new(handler::lobby::change_lobby(id, pkt.lobby, &mut self.client_location, &self.clients, &self.level_table, &mut self.rooms)?.into_iter())
|
||||
Box::new(handler::lobby::change_lobby(id, pkt.lobby, &mut self.client_location, &self.clients, &mut self.item_manager, &self.level_table, &mut self.rooms)?.into_iter())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn on_disconnect(&mut self, id: ClientId) -> Vec<(ClientId, SendShipPacket)> {
|
||||
// TODO: don't unwrap!
|
||||
let client = self.client_location.get_local_client(id).unwrap();
|
||||
let client = self.clients.get(&id).unwrap();
|
||||
let area_client = self.client_location.get_local_client(id).unwrap();
|
||||
let neighbors = self.client_location.get_client_neighbors(id).unwrap();
|
||||
|
||||
let pkt = match self.client_location.get_area(id).unwrap() {
|
||||
@ -345,15 +346,16 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
||||
self.rooms[room.0] = None;
|
||||
}
|
||||
let leader = self.client_location.get_room_leader(room).unwrap();
|
||||
SendShipPacket::LeaveRoom(LeaveRoom::new(client.local_client.id(), leader.local_client.id()))
|
||||
SendShipPacket::LeaveRoom(LeaveRoom::new(area_client.local_client.id(), leader.local_client.id()))
|
||||
},
|
||||
RoomLobby::Lobby(lobby) => {
|
||||
let leader = self.client_location.get_lobby_leader(lobby).unwrap();
|
||||
SendShipPacket::LeaveLobby(LeaveLobby::new(client.local_client.id(), leader.local_client.id()))
|
||||
SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id()))
|
||||
}
|
||||
};
|
||||
|
||||
self.client_location.remove_client_from_area(id);
|
||||
self.item_manager.remove_character_from_room(&client.character);
|
||||
|
||||
neighbors.into_iter().map(|n| {
|
||||
(n.client, pkt.clone())
|
||||
|
Loading…
x
Reference in New Issue
Block a user