Merge pull request 'cratesplitting' (#141) from cratesplitting into master
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #141
This commit is contained in:
commit
b42056419a
16
.drone.yml
16
.drone.yml
@ -1,12 +1,24 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: test elseware
|
||||
name: test elseware
|
||||
|
||||
concurrency:
|
||||
limit: 1
|
||||
|
||||
environment:
|
||||
CARGO_INCREMENTAL: false
|
||||
|
||||
steps:
|
||||
- name: clean cache
|
||||
image: rustlang/rust:nightly
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /usr/local/cargo
|
||||
- name: target-cache
|
||||
path: /drone/src/target
|
||||
commands:
|
||||
- cargo prune
|
||||
- name: build
|
||||
image: rustlang/rust:nightly
|
||||
volumes:
|
||||
@ -33,7 +45,7 @@ steps:
|
||||
- name: target-cache
|
||||
path: /drone/src/target
|
||||
commands:
|
||||
- cargo test
|
||||
- cargo test --jobs 1
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
|
73
Cargo.toml
73
Cargo.toml
@ -4,8 +4,40 @@ version = "0.1.0"
|
||||
authors = ["Jake Probst <jake.probst@gmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
[workspace]
|
||||
members = [
|
||||
"client",
|
||||
"drops",
|
||||
"entity",
|
||||
"items",
|
||||
"location",
|
||||
"maps",
|
||||
"networking",
|
||||
"pktbuilder",
|
||||
"quests",
|
||||
"room",
|
||||
"shops",
|
||||
"stats",
|
||||
"trade",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
entity = { path = "./entity" }
|
||||
maps = { path = "./maps" }
|
||||
networking = { path = "./networking" }
|
||||
shops = { path = "./shops" }
|
||||
stats = { path = "./stats" }
|
||||
items = { path = "./items" }
|
||||
pktbuilder = { path = "./pktbuilder" }
|
||||
quests = { path = "./quests" }
|
||||
location = { path = "./location" }
|
||||
client = { path = "./client" }
|
||||
drops = { path = "./drops" }
|
||||
trade = { path = "./trade" }
|
||||
room = { path = "./room" }
|
||||
|
||||
libpso = { git = "http://git.sharnoth.com/jake/libpso" }
|
||||
|
||||
async-std = { version = "1.9.0", features = ["unstable", "attributes"] }
|
||||
futures = "0.3.5"
|
||||
rand = "0.7.3"
|
||||
@ -33,3 +65,42 @@ sqlx = { version = "0.6.2", features = ["runtime-async-std-native-tls", "postgre
|
||||
strum = "0.19.5"
|
||||
strum_macros = "0.19"
|
||||
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||
|
||||
[dependencies]
|
||||
entity = { workspace = true }
|
||||
maps = { workspace = true }
|
||||
networking = { workspace = true }
|
||||
shops = { workspace = true }
|
||||
stats = { workspace = true }
|
||||
items = { workspace = true }
|
||||
pktbuilder = { workspace = true }
|
||||
quests = { workspace = true }
|
||||
location = { workspace = true }
|
||||
client = { workspace = true }
|
||||
drops = { workspace = true }
|
||||
trade = { workspace = true }
|
||||
room = { workspace = true }
|
||||
|
||||
libpso = { workspace = true }
|
||||
|
||||
ages-prs = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
async-recursion = { workspace = true }
|
||||
async-std = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
bcrypt = { workspace = true }
|
||||
byteorder = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
crc = { workspace = true }
|
||||
derive_more = { workspace = true }
|
||||
enum-utils = { workspace = true }
|
||||
fern = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
log = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
rand_chacha = { workspace = true }
|
||||
ron = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
thiserror = { workspace = true }
|
20
client/Cargo.toml
Normal file
20
client/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
[dependencies]
|
||||
entity = { workspace = true }
|
||||
maps = { workspace = true }
|
||||
networking = { workspace = true }
|
||||
shops = { workspace = true }
|
||||
items = { workspace = true }
|
||||
|
||||
libpso = { workspace = true }
|
||||
|
||||
async-std = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
chrono = { workspace = true }
|
@ -6,15 +6,20 @@ use futures::future::BoxFuture;
|
||||
use libpso::packet::ship::*;
|
||||
use libpso::packet::login::Session;
|
||||
|
||||
use crate::common::serverstate::ClientId;
|
||||
use crate::entity::account::{UserAccountEntity, UserSettingsEntity};
|
||||
use crate::entity::character::CharacterEntity;
|
||||
use crate::entity::item;
|
||||
use networking::serverstate::ClientId;
|
||||
use entity::account::{UserAccountEntity, UserSettingsEntity};
|
||||
use entity::character::CharacterEntity;
|
||||
use entity::item;
|
||||
|
||||
use crate::ship::ship::ShipError;
|
||||
use crate::ship::items;
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem};
|
||||
use maps::area::MapArea;
|
||||
use shops::{WeaponShopItem, ToolShopItem, ArmorShopItem};
|
||||
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ClientError {
|
||||
#[error("not found {0}")]
|
||||
NotFound(ClientId),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
@ -46,7 +51,7 @@ impl Clients {
|
||||
.await;
|
||||
let client = clients
|
||||
.get(&client_id)
|
||||
.ok_or_else(|| ShipError::ClientNotFound(client_id))?
|
||||
.ok_or(ClientError::NotFound(client_id))?
|
||||
.read()
|
||||
.await;
|
||||
|
||||
@ -69,7 +74,7 @@ impl Clients {
|
||||
for (cindex, client_id) in client_ids.iter().enumerate() {
|
||||
let c = clients
|
||||
.get(client_id)
|
||||
.ok_or_else(|| ShipError::ClientNotFound(*client_id))?
|
||||
.ok_or(ClientError::NotFound(*client_id))?
|
||||
.read()
|
||||
.await;
|
||||
client_states[cindex].write(c);
|
||||
@ -95,7 +100,7 @@ impl Clients {
|
||||
.await;
|
||||
let mut client = clients
|
||||
.get(&client_id)
|
||||
.ok_or_else(|| ShipError::ClientNotFound(client_id))?
|
||||
.ok_or(ClientError::NotFound(client_id))?
|
||||
.write()
|
||||
.await;
|
||||
|
17
drops/Cargo.toml
Normal file
17
drops/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "drops"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
[dependencies]
|
||||
entity = { workspace = true }
|
||||
maps = { workspace = true }
|
||||
stats = { workspace = true }
|
||||
|
||||
rand = { workspace = true }
|
||||
rand_chacha = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
enum-utils = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
chrono = { workspace = true }
|
@ -2,18 +2,17 @@
|
||||
use rand::{Rng};
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||
use crate::ship::map::{MapObject, MapObjectType, FixedBoxDropType};
|
||||
use crate::ship::drops::rare_drop_table::{RareDropTable, RareDropItem};
|
||||
use crate::ship::drops::generic_weapon::GenericWeaponTable;
|
||||
use crate::ship::drops::generic_armor::GenericArmorTable;
|
||||
use crate::ship::drops::generic_shield::GenericShieldTable;
|
||||
use crate::ship::drops::generic_unit::GenericUnitTable;
|
||||
use crate::ship::drops::tool_table::ToolTable;
|
||||
use crate::entity::item::ItemDetail;
|
||||
use entity::character::SectionID;
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use crate::{ItemDropType, load_data_file};
|
||||
use maps::object::{MapObject, MapObjectType, FixedBoxDropType};
|
||||
use crate::rare_drop_table::{RareDropTable, RareDropItem};
|
||||
use crate::generic_weapon::GenericWeaponTable;
|
||||
use crate::generic_armor::GenericArmorTable;
|
||||
use crate::generic_shield::GenericShieldTable;
|
||||
use crate::generic_unit::GenericUnitTable;
|
||||
use crate::tool_table::ToolTable;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct BoxDropRate {
|
||||
@ -176,8 +175,8 @@ impl BoxDropTable {
|
||||
fn random_box_drop<R: Rng>(&self, map_area: &MapArea, rng: &mut R) -> Option<ItemDropType> {
|
||||
self.rare_drop(map_area, rng).or_else(|| {
|
||||
let rate = self.box_rates.rates_by_area(map_area);
|
||||
let type_weights = WeightedIndex::new(&[rate.weapon_rate, rate.armor_rate, rate.shield_rate, rate.unit_rate,
|
||||
rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap();
|
||||
let type_weights = WeightedIndex::new([rate.weapon_rate, rate.armor_rate, rate.shield_rate, rate.unit_rate,
|
||||
rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap();
|
||||
let btype = type_weights.sample(rng);
|
||||
match btype {
|
||||
0 => self.weapon_table.get_drop(map_area, rng),
|
||||
@ -204,7 +203,7 @@ impl BoxDropTable {
|
||||
FixedBoxDropType::Specific(value) => {
|
||||
let mut buf: [u8; 16] = [0; 16];
|
||||
buf[0..4].copy_from_slice(&u32::to_be_bytes(value));
|
||||
ItemDetail::parse_item_from_bytes(buf)
|
||||
ItemDropType::parse_item_from_bytes(buf)
|
||||
},
|
||||
}
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use rand::{Rng};
|
||||
use rand::Rng;
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
|
||||
use crate::entity::item::armor::{ArmorType, Armor};
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||
use crate::ship::item_stats::{armor_stats, ArmorStats};
|
||||
use entity::character::SectionID;
|
||||
use entity::item::armor::{ArmorType, Armor};
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use crate::{ItemDropType, load_data_file};
|
||||
use stats::items::{armor_stats, ArmorStats};
|
||||
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -46,8 +46,8 @@ impl GenericArmorTable {
|
||||
}
|
||||
|
||||
fn armor_type<R: Rng>(&self, area_map: &MapArea, rng: &mut R) -> ArmorType {
|
||||
let rank_weights = WeightedIndex::new(&[self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2,
|
||||
self.rank_rates.rank3, self.rank_rates.rank4]).unwrap();
|
||||
let rank_weights = WeightedIndex::new([self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2,
|
||||
self.rank_rates.rank3, self.rank_rates.rank4]).unwrap();
|
||||
let rank = rank_weights.sample(rng) as i32;
|
||||
let armor_level = std::cmp::max(0i32, self.armor_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32);
|
||||
match armor_level {
|
||||
@ -80,8 +80,8 @@ impl GenericArmorTable {
|
||||
}
|
||||
|
||||
pub fn slots<R: Rng>(&self, _area_map: &MapArea, rng: &mut R) -> usize {
|
||||
let slot_weights = WeightedIndex::new(&[self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2,
|
||||
self.slot_rates.slot3, self.slot_rates.slot4]).unwrap();
|
||||
let slot_weights = WeightedIndex::new([self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2,
|
||||
self.slot_rates.slot3, self.slot_rates.slot4]).unwrap();
|
||||
slot_weights.sample(rng)
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use rand::{Rng};
|
||||
use rand::Rng;
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
|
||||
use crate::entity::item::shield::{ShieldType, Shield};
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||
use crate::ship::item_stats::{shield_stats, ShieldStats};
|
||||
use entity::item::shield::{ShieldType, Shield};
|
||||
use entity::character::SectionID;
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use crate::{ItemDropType, load_data_file};
|
||||
use stats::items::{shield_stats, ShieldStats};
|
||||
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -36,8 +36,8 @@ impl GenericShieldTable {
|
||||
}
|
||||
|
||||
fn shield_type<R: Rng>(&self, area_map: &MapArea, rng: &mut R) -> ShieldType {
|
||||
let rank_weights = WeightedIndex::new(&[self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2,
|
||||
self.rank_rates.rank3, self.rank_rates.rank4]).unwrap();
|
||||
let rank_weights = WeightedIndex::new([self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2,
|
||||
self.rank_rates.rank3, self.rank_rates.rank4]).unwrap();
|
||||
let rank = rank_weights.sample(rng) as i32;
|
||||
let shield_level = std::cmp::max(0i32, self.shield_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32);
|
||||
match shield_level {
|
@ -1,14 +1,14 @@
|
||||
use std::collections::BTreeMap;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use rand::{Rng};
|
||||
use rand::Rng;
|
||||
use rand::seq::IteratorRandom;
|
||||
|
||||
use crate::entity::item::unit::{UnitType, Unit, UnitModifier};
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||
use crate::ship::item_stats::{unit_stats, UnitStats};
|
||||
use entity::character::SectionID;
|
||||
use entity::item::unit::{UnitType, Unit, UnitModifier};
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use crate::{ItemDropType, load_data_file};
|
||||
use stats::items::{unit_stats, UnitStats};
|
||||
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
use std::collections::{HashMap, BTreeMap};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use rand::{Rng};
|
||||
use rand::Rng;
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
use rand::seq::SliceRandom;
|
||||
|
||||
use crate::entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial};
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||
use entity::character::SectionID;
|
||||
use entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial};
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use crate::{ItemDropType, load_data_file};
|
||||
|
||||
|
||||
|
||||
@ -240,7 +240,7 @@ impl AttributeTable {
|
||||
|
||||
|
||||
fn generate_attribute<R: Rng>(&self, pattern: &PercentPatternType, rates: &AttributeRate, rng: &mut R) -> Option<WeaponAttribute> {
|
||||
let attribute_weights = WeightedIndex::new(&[rates.none, rates.native, rates.abeast, rates.machine, rates.dark, rates.hit]).unwrap();
|
||||
let attribute_weights = WeightedIndex::new([rates.none, rates.native, rates.abeast, rates.machine, rates.dark, rates.hit]).unwrap();
|
||||
let attr = match attribute_weights.sample(rng) {
|
||||
0 => return None,
|
||||
1 => Attribute::Native,
|
||||
@ -253,7 +253,7 @@ impl AttributeTable {
|
||||
|
||||
let percents = self.percent_rates.get_by_pattern(pattern);
|
||||
|
||||
let value_weights = WeightedIndex::new(&percents.as_array()).unwrap();
|
||||
let value_weights = WeightedIndex::new(percents.as_array()).unwrap();
|
||||
let value = value_weights.sample(rng);
|
||||
let percent = ((value + 1) * 5) as i8;
|
||||
|
||||
@ -477,7 +477,7 @@ impl GenericWeaponTable {
|
||||
let pattern = std::cmp::min(area % ratio.inc, 3);
|
||||
|
||||
let weights = self.grind_rates.grind_rate[pattern as usize];
|
||||
let grind_choice = WeightedIndex::new(&weights).unwrap();
|
||||
let grind_choice = WeightedIndex::new(weights).unwrap();
|
||||
grind_choice.sample(rng)
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
// to their drops
|
||||
|
||||
|
||||
mod drop_table;
|
||||
pub mod rare_drop_table;
|
||||
mod generic_weapon;
|
||||
mod generic_armor;
|
||||
@ -22,19 +21,19 @@ use std::io::Read;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use rand::{Rng, SeedableRng};
|
||||
|
||||
use crate::ship::monster::MonsterType;
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::drops::generic_weapon::GenericWeaponTable;
|
||||
use crate::ship::drops::generic_armor::GenericArmorTable;
|
||||
use crate::ship::drops::generic_shield::GenericShieldTable;
|
||||
use crate::ship::drops::generic_unit::GenericUnitTable;
|
||||
use crate::ship::drops::tool_table::ToolTable;
|
||||
use crate::ship::drops::rare_drop_table::RareDropTable;
|
||||
use crate::ship::drops::box_drop_table::BoxDropTable;
|
||||
use crate::ship::map::MapObject;
|
||||
use crate::entity::item::{weapon, armor, shield, unit, mag, tool, tech};
|
||||
use maps::monster::MonsterType;
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use entity::character::SectionID;
|
||||
use crate::generic_weapon::GenericWeaponTable;
|
||||
use crate::generic_armor::GenericArmorTable;
|
||||
use crate::generic_shield::GenericShieldTable;
|
||||
use crate::generic_unit::GenericUnitTable;
|
||||
use crate::tool_table::ToolTable;
|
||||
use crate::rare_drop_table::RareDropTable;
|
||||
use crate::box_drop_table::BoxDropTable;
|
||||
use maps::object::MapObject;
|
||||
use entity::item::{ItemType, weapon, armor, shield, unit, mag, tool, tech, esweapon};
|
||||
|
||||
|
||||
fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf {
|
||||
@ -55,18 +54,6 @@ pub fn load_data_file<T: serde::de::DeserializeOwned>(episode: Episode, difficul
|
||||
toml::from_str::<T>(s.as_str()).unwrap()
|
||||
}
|
||||
|
||||
// this is just copypaste
|
||||
pub fn load_rare_monster_file<T: serde::de::DeserializeOwned>(episode: Episode) -> T {
|
||||
// TODO: where does the rare monster toml file actually live
|
||||
let mut path = PathBuf::from("data/battle_param/");
|
||||
path.push(episode.to_string().to_lowercase() + "_rare_monster.toml");
|
||||
|
||||
let mut f = File::open(path).unwrap();
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s);
|
||||
toml::from_str::<T>(s.as_str()).unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
|
||||
pub enum MonsterDropType {
|
||||
#[serde(rename = "weapon")]
|
||||
@ -102,6 +89,28 @@ pub enum ItemDropType {
|
||||
Meseta(u32),
|
||||
}
|
||||
|
||||
impl ItemDropType {
|
||||
pub fn parse_item_from_bytes(data: [u8; 16]) -> Option<ItemDropType> {
|
||||
let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon)
|
||||
.or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor))
|
||||
.or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield))
|
||||
.or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit))
|
||||
.or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag))
|
||||
.or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool))
|
||||
.or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?;
|
||||
|
||||
match item_type {
|
||||
ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)),
|
||||
ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)),
|
||||
ItemType::Shield(_s) => Some(ItemDropType::Shield(shield::Shield::from_bytes(data).ok()?)),
|
||||
ItemType::Unit(_u) => Some(ItemDropType::Unit(unit::Unit::from_bytes(data).ok()?)),
|
||||
ItemType::Mag(_m) => Some(ItemDropType::Mag(mag::Mag::from_bytes(data).ok()?)),
|
||||
ItemType::Tool(_t) => Some(ItemDropType::Tool(tool::Tool::from_bytes(data).ok()?)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ItemDrop {
|
||||
pub map_area: MapArea,
|
||||
@ -112,7 +121,12 @@ pub struct ItemDrop {
|
||||
}
|
||||
|
||||
|
||||
pub struct DropTable {
|
||||
pub trait DropTable {
|
||||
fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType>;
|
||||
fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType>;
|
||||
}
|
||||
|
||||
pub struct StandardDropTable {
|
||||
monster_stats: HashMap<MonsterType, MonsterDropStats>,
|
||||
rare_table: RareDropTable,
|
||||
weapon_table: GenericWeaponTable,
|
||||
@ -124,11 +138,12 @@ pub struct DropTable {
|
||||
rng: rand_chacha::ChaCha20Rng,
|
||||
}
|
||||
|
||||
impl DropTable {
|
||||
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable {
|
||||
impl StandardDropTable {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box<dyn DropTable + Send + Sync> {
|
||||
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
||||
|
||||
DropTable {
|
||||
|
||||
Box::new(StandardDropTable {
|
||||
monster_stats: monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect(),
|
||||
rare_table: RareDropTable::new(episode, difficulty, section_id),
|
||||
weapon_table: GenericWeaponTable::new(episode, difficulty, section_id),
|
||||
@ -138,7 +153,7 @@ impl DropTable {
|
||||
tool_table: ToolTable::new(episode, difficulty, section_id),
|
||||
box_table: BoxDropTable::new(episode, difficulty, section_id),
|
||||
rng: rand_chacha::ChaCha20Rng::from_entropy(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn builder() -> DropTableBuilder {
|
||||
@ -168,8 +183,10 @@ impl DropTable {
|
||||
MonsterDropType::None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType> {
|
||||
impl DropTable for StandardDropTable {
|
||||
fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType> {
|
||||
let monster_stat = *self.monster_stats.get(monster)?;
|
||||
|
||||
let drop_anything = self.rng.gen_range(0, 100);
|
||||
@ -182,7 +199,7 @@ impl DropTable {
|
||||
}
|
||||
|
||||
let drop_type = self.rng.gen_range(0, 3);
|
||||
|
||||
|
||||
match drop_type {
|
||||
0 => {
|
||||
self.generate_meseta(&monster_stat)
|
||||
@ -197,7 +214,7 @@ impl DropTable {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType> {
|
||||
fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType> {
|
||||
self.box_table.get_drop(map_area, object, &mut self.rng)
|
||||
}
|
||||
}
|
||||
@ -244,8 +261,8 @@ impl DropTableBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable {
|
||||
DropTable {
|
||||
pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box<dyn DropTable + Send + Sync> {
|
||||
Box::new(StandardDropTable {
|
||||
monster_stats: self.monster_stats.unwrap_or_else(|| {
|
||||
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
||||
monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect()
|
||||
@ -258,11 +275,10 @@ impl DropTableBuilder {
|
||||
tool_table: self.tool_table.unwrap_or_else(|| ToolTable::new(episode, difficulty, section_id)),
|
||||
box_table: self.box_table.unwrap_or_else(|| BoxDropTable::new(episode, difficulty, section_id)),
|
||||
rng: self.rng.unwrap_or_else(rand_chacha::ChaCha20Rng::from_entropy),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
@ -1,20 +1,20 @@
|
||||
use std::collections::HashMap;
|
||||
use rand::Rng;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::entity::item::weapon::{Weapon, WeaponType};
|
||||
use crate::entity::item::armor::{Armor, ArmorType};
|
||||
use crate::entity::item::shield::{Shield, ShieldType};
|
||||
use crate::entity::item::unit::{Unit, UnitType};
|
||||
use crate::entity::item::tool::{Tool, ToolType};
|
||||
use crate::entity::item::mag::{Mag, MagType};
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::monster::MonsterType;
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||
use crate::ship::drops::generic_weapon::AttributeTable;
|
||||
use crate::ship::drops::generic_armor::GenericArmorTable;
|
||||
use crate::ship::drops::generic_shield::GenericShieldTable;
|
||||
use entity::item::weapon::{Weapon, WeaponType};
|
||||
use entity::item::armor::{Armor, ArmorType};
|
||||
use entity::item::shield::{Shield, ShieldType};
|
||||
use entity::item::unit::{Unit, UnitType};
|
||||
use entity::item::tool::{Tool, ToolType};
|
||||
use entity::item::mag::{Mag, MagType};
|
||||
use entity::character::SectionID;
|
||||
use maps::monster::MonsterType;
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use crate::{ItemDropType, load_data_file};
|
||||
use crate::generic_weapon::AttributeTable;
|
||||
use crate::generic_armor::GenericArmorTable;
|
||||
use crate::generic_shield::GenericShieldTable;
|
||||
|
||||
type ItemParseFn = Box<dyn Fn(&String) -> Option<RareDropItem>>;
|
||||
|
@ -3,11 +3,11 @@ use serde::{Serialize, Deserialize};
|
||||
use rand::{Rng};
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
|
||||
use crate::entity::item::tech::{Technique, TechniqueDisk};
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||
use entity::item::tech::{Technique, TechniqueDisk};
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use entity::character::SectionID;
|
||||
use crate::{ItemDropType, load_data_file};
|
||||
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
use std::collections::{BTreeMap};
|
||||
use std::collections::BTreeMap;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use rand::{Rng};
|
||||
use rand::Rng;
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
|
||||
use crate::entity::item::tool::{Tool, ToolType};
|
||||
use crate::ship::room::{Difficulty, Episode};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||
use crate::ship::drops::tech_table::TechniqueTable;
|
||||
use entity::item::tool::{Tool, ToolType};
|
||||
use maps::room::{Difficulty, Episode};
|
||||
use maps::area::MapArea;
|
||||
use entity::character::SectionID;
|
||||
use crate::{ItemDropType, load_data_file};
|
||||
use crate::tech_table::TechniqueTable;
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, enum_utils::FromStr)]
|
23
entity/Cargo.toml
Normal file
23
entity/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "entity"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libpso = { workspace = true }
|
||||
maps = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
async-std = { workspace = true }
|
||||
sqlx = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
enum-utils = { workspace = true }
|
||||
derive_more = { workspace = true }
|
||||
refinery = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
toml = { workspace = true }
|
@ -4,8 +4,8 @@ use serde::{Serialize, Deserialize};
|
||||
|
||||
use libpso::packet::ship::{UpdateConfig, WriteInfoboard};
|
||||
use libpso::character::settings::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU};
|
||||
use crate::entity::item::tech::Technique;
|
||||
use crate::entity::account::UserAccountId;
|
||||
use crate::item::tech::Technique;
|
||||
use crate::account::UserAccountId;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, enum_utils::FromStr, derive_more::Display, Serialize, Deserialize, Default)]
|
||||
pub enum CharacterClass {
|
@ -1,10 +1,10 @@
|
||||
use thiserror::Error;
|
||||
use futures::future::{Future, BoxFuture};
|
||||
|
||||
use crate::entity::account::*;
|
||||
use crate::entity::character::*;
|
||||
use crate::entity::item::*;
|
||||
use crate::entity::room::*;
|
||||
use crate::account::*;
|
||||
use crate::character::*;
|
||||
use crate::item::*;
|
||||
use crate::room::*;
|
||||
|
||||
|
||||
// TODO: better granularity?
|
@ -2,11 +2,11 @@ use std::collections::BTreeMap;
|
||||
use std::convert::TryInto;
|
||||
use futures::future::{Future, BoxFuture};
|
||||
|
||||
use crate::entity::account::*;
|
||||
use crate::entity::character::*;
|
||||
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
||||
use crate::entity::item::*;
|
||||
use crate::entity::room::*;
|
||||
use crate::account::*;
|
||||
use crate::character::*;
|
||||
use crate::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
||||
use crate::item::*;
|
||||
use crate::room::*;
|
||||
|
||||
use async_std::sync::{Arc, Mutex};
|
||||
|
3
entity/src/gateway/postgres/migrations/mod.rs
Normal file
3
entity/src/gateway/postgres/migrations/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
use refinery::include_migration_mods;
|
||||
|
||||
include_migration_mods!("src/gateway/postgres/migrations");
|
@ -4,13 +4,13 @@ use std::convert::Into;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use libpso::character::settings;
|
||||
use libpso::util::vec_to_array;
|
||||
use crate::entity::account::*;
|
||||
use crate::entity::character::*;
|
||||
use crate::entity::item::*;
|
||||
use crate::entity::room::*;
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::room::{Episode, Difficulty};
|
||||
use crate::ship::monster::MonsterType;
|
||||
use crate::account::*;
|
||||
use crate::character::*;
|
||||
use crate::item::*;
|
||||
use crate::room::*;
|
||||
use maps::area::MapArea;
|
||||
use maps::room::{Episode, Difficulty};
|
||||
use maps::monster::MonsterType;
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
pub struct PgUserAccount {
|
@ -1,16 +1,16 @@
|
||||
// this lint is currently bugged and suggests incorrect code https://github.com/rust-lang/rust-clippy/issues/9123
|
||||
#![allow(clippy::explicit_auto_deref)]
|
||||
|
||||
use std::convert::{From, TryFrom, Into};
|
||||
use std::convert::{From, Into};
|
||||
use futures::future::{Future, BoxFuture};
|
||||
use futures::stream::{StreamExt, FuturesOrdered};
|
||||
use async_std::sync::{Arc, Mutex};
|
||||
use libpso::character::guildcard;
|
||||
use crate::entity::account::*;
|
||||
use crate::entity::character::*;
|
||||
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
||||
use crate::entity::item::*;
|
||||
use crate::entity::room::*;
|
||||
use crate::account::*;
|
||||
use crate::character::*;
|
||||
use crate::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
||||
use crate::item::*;
|
||||
use crate::room::*;
|
||||
use super::models::*;
|
||||
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
@ -19,7 +19,7 @@ use sqlx::Connection;
|
||||
|
||||
mod embedded {
|
||||
use refinery::embed_migrations;
|
||||
embed_migrations!("src/entity/gateway/postgres/migrations");
|
||||
embed_migrations!("src/gateway/postgres/migrations");
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::entity::item::ItemEntityId;
|
||||
use crate::item::ItemEntityId;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum ItemParseError {
|
@ -1,9 +1,9 @@
|
||||
use thiserror::Error;
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::entity::item::tool::ToolType;
|
||||
use crate::entity::character::{CharacterClass, SectionID};
|
||||
use crate::entity::item::ItemEntityId;
|
||||
use crate::item::tool::ToolType;
|
||||
use crate::character::{CharacterClass, SectionID};
|
||||
use crate::item::ItemEntityId;
|
||||
use std::io::Read;
|
||||
|
||||
use std::cmp::Ordering::{Less, Greater, Equal};
|
@ -9,11 +9,11 @@ pub mod mag;
|
||||
pub mod esweapon;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::entity::room::RoomEntityId;
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::monster::MonsterType;
|
||||
use crate::ship::drops::ItemDropType;
|
||||
use crate::character::CharacterEntityId;
|
||||
use crate::room::RoomEntityId;
|
||||
use maps::area::MapArea;
|
||||
use maps::monster::MonsterType;
|
||||
//use crate::ship::drops::ItemDropType;
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct ItemEntityId(pub u32);
|
||||
@ -156,26 +156,6 @@ impl ItemDetail {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_item_from_bytes(data: [u8; 16]) -> Option<ItemDropType> {
|
||||
let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon)
|
||||
.or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor))
|
||||
.or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield))
|
||||
.or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit))
|
||||
.or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag))
|
||||
.or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool))
|
||||
.or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?;
|
||||
|
||||
match item_type {
|
||||
ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)),
|
||||
ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)),
|
||||
ItemType::Shield(_s) => Some(ItemDropType::Shield(shield::Shield::from_bytes(data).ok()?)),
|
||||
ItemType::Unit(_u) => Some(ItemDropType::Unit(unit::Unit::from_bytes(data).ok()?)),
|
||||
ItemType::Mag(_m) => Some(ItemDropType::Mag(mag::Mag::from_bytes(data).ok()?)),
|
||||
ItemType::Tool(_t) => Some(ItemDropType::Tool(tool::Tool::from_bytes(data).ok()?)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_client_bytes(&self) -> [u8; 16] {
|
||||
match self {
|
||||
ItemDetail::Weapon(w) => w.as_bytes(),
|
@ -1,4 +1,4 @@
|
||||
use crate::entity::item::ItemEntityId;
|
||||
use crate::item::ItemEntityId;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
@ -1,8 +1,8 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
|
||||
use crate::entity::character::{CharacterEntityId, SectionID};
|
||||
use crate::ship::room::{Episode, Difficulty};
|
||||
use crate::character::{CharacterEntityId, SectionID};
|
||||
use maps::room::{Episode, Difficulty};
|
||||
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
31
entity/src/team.rs
Normal file
31
entity/src/team.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use super::account::UserAccountId;
|
||||
|
||||
// [2022-10-23 00:11:18][elseware::common::mainloop::client][WARN] error RecvServerPacket::from_bytes: WrongPacketForServerType(490, [40, 0, 234, 1, 0, 0, 0, 0, 9, 0, 74, 0, 97, 0, 115, 0, 100, 0, 102, 0, 0, 0, 0, 0, 192, 52, 67, 3, 60, 159, 129, 0, 32, 64, 233, 10, 196, 156, 152, 0])
|
||||
// [2022-10-23 00:20:14][elseware::common::mainloop::client][WARN] error RecvServerPacket::from_bytes: WrongPacketForServerType(490, [40, 0, 234, 1, 0, 0, 0, 0, 9, 0, 74, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 0, 0, 152, 0])
|
||||
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct TeamEntityId(pub u32);
|
||||
|
||||
pub struct NewTeamEntity {
|
||||
pub created_by: UserAccountId,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TeamEntity {
|
||||
pub id: TeamEntityId,
|
||||
pub owner: UserAccountId,
|
||||
pub name: String,
|
||||
|
||||
pub team_flag: [u8; 2048],
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
25
items/Cargo.toml
Normal file
25
items/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "items"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
entity = { workspace = true }
|
||||
maps = { workspace = true }
|
||||
shops = { workspace = true }
|
||||
location = { workspace = true }
|
||||
drops = { workspace = true }
|
||||
|
||||
libpso = { workspace = true }
|
||||
|
||||
enum-utils = { workspace = true }
|
||||
derive_more = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
rand_chacha = { workspace = true }
|
||||
async-recursion = { workspace = true }
|
||||
async-std = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
thiserror = { workspace = true }
|
@ -1,6 +1,6 @@
|
||||
// TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemNote};
|
||||
use crate::ClientItemId;
|
||||
use entity::item::{Meseta, ItemNote};
|
||||
use async_std::sync::Arc;
|
||||
use std::future::Future;
|
||||
use futures::future::BoxFuture;
|
||||
@ -8,30 +8,33 @@ use std::pin::Pin;
|
||||
use std::iter::IntoIterator;
|
||||
use anyhow::Context;
|
||||
|
||||
use libpso::packet::{ship::Message, messages::GameMessage};
|
||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||
use crate::entity::item::{ItemDetail, NewItemEntity, TradeId, ItemModifier};
|
||||
use crate::entity::item::tool::Tool;
|
||||
use crate::entity::room::RoomEntityId;
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::ship::SendShipPacket;
|
||||
use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail};
|
||||
use crate::ship::items::bank::{BankItem, BankItemDetail};
|
||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||
use crate::ship::items::floor::{FloorItem, FloorItemDetail};
|
||||
use crate::ship::items::apply_item::{apply_item, ApplyItemAction};
|
||||
use crate::ship::shops::ShopItem;
|
||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||
use crate::ship::packet::builder;
|
||||
use crate::ship::location::AreaClient;
|
||||
use crate::ship::monster::MonsterType;
|
||||
use entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||
use entity::item::{ItemDetail, NewItemEntity, TradeId, ItemModifier};
|
||||
use entity::item::tool::Tool;
|
||||
use entity::room::RoomEntityId;
|
||||
use maps::area::MapArea;
|
||||
use crate::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail};
|
||||
use crate::bank::{BankItem, BankItemDetail};
|
||||
use crate::inventory::{InventoryItem, InventoryItemDetail};
|
||||
use crate::floor::{FloorItem, FloorItemDetail};
|
||||
use crate::apply_item::{apply_item, ApplyItemAction};
|
||||
use shops::ShopItem;
|
||||
use drops::{ItemDrop, ItemDropType};
|
||||
use location::AreaClient;
|
||||
use maps::monster::MonsterType;
|
||||
|
||||
pub enum TriggerCreateItem {
|
||||
Yes,
|
||||
No
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CreateItem {
|
||||
Individual(AreaClient, ClientItemId, IndividualItemDetail),
|
||||
Stacked(AreaClient, ClientItemId, Tool, usize),
|
||||
}
|
||||
|
||||
pub(super) fn take_item_from_floor<'a, EG, TR>(
|
||||
character_id: CharacterEntityId,
|
||||
item_id: ClientItemId
|
||||
@ -1144,7 +1147,7 @@ pub(super) fn apply_item_action_packets<'a, EG, TR>(
|
||||
character_id: CharacterEntityId,
|
||||
area_client: AreaClient,
|
||||
) -> impl Fn((ItemStateProxy, TR), ApplyItemAction)
|
||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec<SendShipPacket>), anyhow::Error>>
|
||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec<CreateItem>), anyhow::Error>>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
||||
@ -1161,7 +1164,7 @@ where
|
||||
let (inventory_item_detail, create_item) = if item_detail.is_stackable() {
|
||||
let tool = item_detail.as_tool().ok_or_else(|| ItemStateError::NotATool(ClientItemId(0xFFFFFFFF)))?;
|
||||
|
||||
let create_item = builder::message::create_stacked_item(area_client, item_id, &tool, 1).map_err(|_err| ItemStateError::Dummy)?;
|
||||
let create_item = CreateItem::Stacked(area_client, item_id, tool, 1);
|
||||
let item_detail = StackedItemDetail {
|
||||
entity_ids: vec![new_item.id],
|
||||
tool
|
||||
@ -1173,7 +1176,7 @@ where
|
||||
entity_id: new_item.id,
|
||||
item: item_detail,
|
||||
};
|
||||
let create_item = builder::message::create_individual_item(area_client, item_id, &item_detail).map_err(|_err| ItemStateError::Dummy)?;
|
||||
let create_item = CreateItem::Individual(area_client, item_id, item_detail.clone());
|
||||
(InventoryItemDetail::Individual(item_detail), create_item)
|
||||
};
|
||||
|
||||
@ -1187,7 +1190,8 @@ where
|
||||
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
|
||||
item_state.set_inventory(inventory).await;
|
||||
|
||||
vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))]
|
||||
//vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))]
|
||||
vec![create_item]
|
||||
}
|
||||
else {
|
||||
Vec::new()
|
@ -4,15 +4,15 @@ use thiserror::Error;
|
||||
use anyhow::Context;
|
||||
use rand::SeedableRng;
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
use crate::entity::gateway::{EntityGateway, GatewayError};
|
||||
use crate::entity::character::{CharacterEntity, TechLevel};
|
||||
use crate::entity::item::mag::{MagCell, MagCellError};
|
||||
use crate::entity::item::tool::{Tool, ToolType};
|
||||
use crate::entity::item::tech::TechniqueDisk;
|
||||
use crate::entity::item::{ItemDetail, ItemEntityId};
|
||||
use crate::entity::item::weapon::WeaponModifier;
|
||||
use crate::ship::items::state::ItemStateProxy;
|
||||
use crate::ship::items::inventory::InventoryItemDetail;
|
||||
use entity::gateway::{EntityGateway, GatewayError};
|
||||
use entity::character::{CharacterEntity, TechLevel};
|
||||
use entity::item::mag::{MagCell, MagCellError};
|
||||
use entity::item::tool::{Tool, ToolType};
|
||||
use entity::item::tech::TechniqueDisk;
|
||||
use entity::item::{ItemDetail, ItemEntityId};
|
||||
use entity::item::weapon::WeaponModifier;
|
||||
use crate::state::ItemStateProxy;
|
||||
use crate::inventory::InventoryItemDetail;
|
||||
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@ -226,7 +226,7 @@ pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell:
|
||||
|
||||
fn jack_o_lantern() -> Result<Vec<ApplyItemAction>, anyhow::Error>
|
||||
{
|
||||
let mag_rate = WeightedIndex::new(&[13, 13, 13, 13, 12, 12, 12, 12]).unwrap();
|
||||
let mag_rate = WeightedIndex::new([13, 13, 13, 13, 12, 12, 12, 12]).unwrap();
|
||||
let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) {
|
||||
0 => ToolType::CellOfMag502,
|
||||
1 => ToolType::CellOfMag213,
|
@ -1,15 +1,15 @@
|
||||
use std::cmp::Ordering;
|
||||
use libpso::character::character;
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity};
|
||||
use crate::ClientItemId;
|
||||
use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity};
|
||||
use std::future::Future;
|
||||
use async_std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::entity::item::BankIdentifier;
|
||||
use crate::ship::items::state::ItemStateError;
|
||||
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||
use entity::character::CharacterEntityId;
|
||||
use entity::item::BankIdentifier;
|
||||
use crate::state::ItemStateError;
|
||||
use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||
use crate::inventory::{InventoryItem, InventoryItemDetail};
|
||||
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
@ -325,15 +325,7 @@ impl std::cmp::Eq for BankItemDetail {}
|
||||
|
||||
impl std::cmp::PartialOrd for BankItemDetail {
|
||||
fn partial_cmp(&self, other: &BankItemDetail) -> Option<std::cmp::Ordering> {
|
||||
let mut self_bytes = [0u8; 4];
|
||||
let mut other_bytes = [0u8; 4];
|
||||
self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]);
|
||||
other_bytes.copy_from_slice(&other.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)
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,8 +336,8 @@ impl std::cmp::Ord for BankItemDetail {
|
||||
self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]);
|
||||
other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]);
|
||||
|
||||
let self_value = u32::from_le_bytes(self_bytes);
|
||||
let other_value = u32::from_le_bytes(other_bytes);
|
||||
let self_value = u32::from_be_bytes(self_bytes);
|
||||
let other_value = u32::from_be_bytes(other_bytes);
|
||||
|
||||
self_value.cmp(&other_value)
|
||||
}
|
||||
@ -362,7 +354,7 @@ impl std::cmp::Eq for BankItem {}
|
||||
|
||||
impl std::cmp::PartialOrd for BankItem {
|
||||
fn partial_cmp(&self, other: &BankItem) -> Option<std::cmp::Ordering> {
|
||||
self.item.partial_cmp(&other.item)
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail};
|
||||
use crate::ClientItemId;
|
||||
use entity::item::{Meseta, ItemEntityId, ItemDetail};
|
||||
use std::future::Future;
|
||||
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::entity::item::mag::Mag;
|
||||
use maps::area::MapArea;
|
||||
use entity::character::CharacterEntityId;
|
||||
use entity::item::mag::Mag;
|
||||
|
||||
use crate::ship::items::state::ItemStateError;
|
||||
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail};
|
||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||
use crate::state::ItemStateError;
|
||||
use crate::state::{IndividualItemDetail, StackedItemDetail};
|
||||
use crate::inventory::{InventoryItem, InventoryItemDetail};
|
||||
|
||||
pub enum FloorType {
|
||||
Local,
|
||||
@ -96,13 +96,13 @@ pub struct FloorState {
|
||||
impl FloorState {
|
||||
pub fn take_item(&mut self, item_id: &ClientItemId) -> Option<FloorItem> {
|
||||
let item = self.local.0
|
||||
.drain_filter(|item| {
|
||||
.extract_if(|item| {
|
||||
item.item_id == *item_id
|
||||
})
|
||||
.next();
|
||||
item.or_else(|| {
|
||||
self.shared.0
|
||||
.drain_filter(|item| {
|
||||
.extract_if(|item| {
|
||||
item.item_id == *item_id
|
||||
})
|
||||
.next()
|
@ -1,18 +1,18 @@
|
||||
use std::cmp::Ordering;
|
||||
use libpso::character::character;
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity};
|
||||
use crate::ClientItemId;
|
||||
use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity};
|
||||
use std::future::Future;
|
||||
use async_std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::entity::item::tool::ToolType;
|
||||
use crate::entity::item::mag::Mag;
|
||||
use crate::entity::item::weapon::Weapon;
|
||||
use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem};
|
||||
use crate::ship::items::state::ItemStateError;
|
||||
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||
use crate::ship::items::floor::{FloorItem, FloorItemDetail};
|
||||
use entity::character::CharacterEntityId;
|
||||
use entity::item::tool::ToolType;
|
||||
use entity::item::mag::Mag;
|
||||
use entity::item::weapon::Weapon;
|
||||
use shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem};
|
||||
use crate::state::ItemStateError;
|
||||
use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||
use crate::floor::{FloorItem, FloorItemDetail};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum InventoryItemDetail {
|
@ -1,3 +1,5 @@
|
||||
#![feature(extract_if)]
|
||||
|
||||
pub mod state;
|
||||
pub mod actions;
|
||||
pub mod apply_item;
|
||||
@ -6,6 +8,7 @@ pub mod inventory;
|
||||
pub mod floor;
|
||||
pub mod bank;
|
||||
pub mod tasks;
|
||||
pub mod trade;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)]
|
||||
pub struct ClientItemId(pub u32);
|
@ -1,4 +1,4 @@
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::ClientItemId;
|
||||
use std::collections::HashMap;
|
||||
use std::cmp::Ordering;
|
||||
use std::cell::RefCell;
|
||||
@ -9,18 +9,18 @@ use crate::entity::item::{ItemDetail, ItemNote, BankName};
|
||||
use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, BankItemEntity};
|
||||
use crate::entity::item::tool::{Tool, ToolType};
|
||||
use crate::entity::item::weapon;
|
||||
use crate::ship::map::MapArea;
|
||||
use maps::area::MapArea;
|
||||
use crate::ship::ship::ItemDropLocation;
|
||||
use crate::ship::trade::TradeItem;
|
||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||
use crate::ship::location::{AreaClient, RoomId};
|
||||
use crate::ship::shops::ShopItem;
|
||||
use drops::{ItemDrop, ItemDropType};
|
||||
use location::{AreaClient, RoomId};
|
||||
use shops::ShopItem;
|
||||
use crate::ship::packet::handler::trade::{TradeError, OTHER_MESETA_ITEM_ID};
|
||||
|
||||
use crate::ship::items::bank::*;
|
||||
use crate::ship::items::floor::*;
|
||||
use crate::ship::items::inventory::*;
|
||||
use crate::ship::items::transaction::{ItemTransaction, ItemAction, TransactionError, TransactionCommitError};
|
||||
use crate::bank::*;
|
||||
use crate::floor::*;
|
||||
use crate::inventory::*;
|
||||
use crate::transaction::{ItemTransaction, ItemAction, TransactionError, TransactionCommitError};
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum FloorType {
|
@ -4,18 +4,18 @@ use async_std::sync::{Arc, RwLock, Mutex};
|
||||
use futures::stream::{FuturesOrdered, StreamExt};
|
||||
use anyhow::Context;
|
||||
|
||||
use crate::entity::gateway::{EntityGateway, GatewayError};
|
||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankIdentifier};
|
||||
use crate::entity::item::tool::Tool;
|
||||
use crate::entity::item::weapon::Weapon;
|
||||
use crate::entity::item::mag::Mag;
|
||||
use crate::ship::drops::ItemDrop;
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState};
|
||||
use crate::ship::items::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType};
|
||||
use crate::ship::items::bank::{Bank, BankState, BankItem, BankItemDetail, BankError};
|
||||
use crate::ship::location::{AreaClient, RoomId};
|
||||
use entity::gateway::{EntityGateway, GatewayError};
|
||||
use entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankIdentifier};
|
||||
use entity::item::tool::Tool;
|
||||
use entity::item::weapon::Weapon;
|
||||
use entity::item::mag::Mag;
|
||||
use drops::ItemDrop;
|
||||
use crate::ClientItemId;
|
||||
use crate::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState};
|
||||
use crate::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType};
|
||||
use crate::bank::{Bank, BankState, BankItem, BankItemDetail, BankError};
|
||||
use location::{AreaClient, RoomId};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ItemStateError {
|
||||
@ -50,7 +50,7 @@ pub enum ItemStateError {
|
||||
#[error("stacked item")]
|
||||
StackedItemError(Vec<ItemEntity>),
|
||||
#[error("apply item {0}")]
|
||||
ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError),
|
||||
ApplyItemError(#[from] crate::apply_item::ApplyItemError),
|
||||
#[error("item is not a mag {0}")]
|
||||
NotAMag(ClientItemId),
|
||||
#[error("item is not mag food {0}")]
|
@ -1,24 +1,23 @@
|
||||
use futures::future::BoxFuture;
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::Meseta;
|
||||
use crate::ClientItemId;
|
||||
use entity::item::Meseta;
|
||||
|
||||
use crate::ship::ship::SendShipPacket;
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||
use crate::entity::item::ItemModifier;
|
||||
use crate::entity::room::RoomEntityId;
|
||||
use crate::ship::items::state::{ItemState, ItemStateProxy, IndividualItemDetail};
|
||||
use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction};
|
||||
use crate::ship::items::inventory::InventoryItem;
|
||||
use crate::ship::items::floor::FloorItem;
|
||||
use crate::ship::shops::ShopItem;
|
||||
use crate::ship::trade::TradeItem;
|
||||
use crate::ship::location::AreaClient;
|
||||
use crate::ship::drops::ItemDrop;
|
||||
use crate::ship::monster::MonsterType;
|
||||
use maps::area::MapArea;
|
||||
use entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||
use entity::item::ItemModifier;
|
||||
use entity::room::RoomEntityId;
|
||||
use crate::state::{ItemState, ItemStateProxy, IndividualItemDetail};
|
||||
use crate::itemstateaction::{ItemStateAction, ItemAction};
|
||||
use crate::inventory::InventoryItem;
|
||||
use crate::floor::FloorItem;
|
||||
use shops::ShopItem;
|
||||
use crate::trade::TradeItem;
|
||||
use location::AreaClient;
|
||||
use drops::ItemDrop;
|
||||
use maps::monster::MonsterType;
|
||||
|
||||
use crate::ship::items::actions;
|
||||
use crate::actions;
|
||||
|
||||
pub fn pick_up_item<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
@ -278,7 +277,7 @@ pub fn use_item<'a, EG> (
|
||||
area_client: AreaClient,
|
||||
item_id: &'a ClientItemId,
|
||||
amount: u32,
|
||||
) -> BoxFuture<'a, Result<Vec<SendShipPacket>, anyhow::Error>>
|
||||
) -> BoxFuture<'a, Result<Vec<actions::CreateItem>, anyhow::Error>>
|
||||
where
|
||||
EG: EntityGateway + 'static,
|
||||
{
|
||||
@ -372,6 +371,8 @@ where
|
||||
Ok((transaction, result))
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn trade_items<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &'a mut EG,
|
38
items/src/trade.rs
Normal file
38
items/src/trade.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::ClientItemId;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TradeItem {
|
||||
Individual(ClientItemId),
|
||||
Stacked(ClientItemId, usize),
|
||||
}
|
||||
|
||||
impl TradeItem {
|
||||
pub fn stacked(&self) -> Option<(ClientItemId, usize)> {
|
||||
match self {
|
||||
TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stacked_mut(&mut self) -> Option<(ClientItemId, &mut usize)> {
|
||||
match self {
|
||||
TradeItem::Stacked(item_id, ref mut amount) => Some((*item_id, amount)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn item_id(&self) -> ClientItemId {
|
||||
match self {
|
||||
TradeItem::Individual(item_id) => *item_id,
|
||||
TradeItem::Stacked(item_id, _) => *item_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn amount(&self) -> usize {
|
||||
match self {
|
||||
TradeItem::Individual(_) => 1,
|
||||
TradeItem::Stacked(_, amount) => *amount,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
location/Cargo.toml
Normal file
12
location/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "location"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
networking = { workspace = true }
|
||||
|
||||
async-std = { workspace = true }
|
||||
derive_more = { workspace = true }
|
||||
futures= { workspace = true }
|
||||
thiserror = { workspace = true }
|
@ -2,7 +2,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::time::SystemTime;
|
||||
use thiserror::Error;
|
||||
use crate::common::serverstate::ClientId;
|
||||
use networking::serverstate::ClientId;
|
||||
|
||||
use async_std::sync::{Arc, RwLock};
|
||||
use futures::{stream, StreamExt};
|
14
maps/Cargo.toml
Normal file
14
maps/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "maps"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
byteorder = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
rand_chacha = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
enum-utils = { workspace = true }
|
||||
derive_more = { workspace = true }
|
@ -2,7 +2,7 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
use crate::ship::room::Episode;
|
||||
use crate::room::Episode;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
@ -1,19 +1,18 @@
|
||||
// TOOD: `pub(super) for most of these?`
|
||||
use std::io::{Read};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::ship::ship::ShipEvent;
|
||||
use crate::ship::monster::MonsterType;
|
||||
use crate::ship::room::Episode;
|
||||
|
||||
use crate::ship::map::*;
|
||||
|
||||
use rand::{Rng, SeedableRng};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::ship::drops::{load_rare_monster_file};
|
||||
|
||||
use crate::Holiday;
|
||||
use crate::area::{MapArea, MapAreaError};
|
||||
use crate::room::Episode;
|
||||
use crate::monster::MonsterType;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RawMapEnemy {
|
||||
@ -69,6 +68,17 @@ impl RawMapEnemy {
|
||||
}
|
||||
|
||||
|
||||
pub fn load_rare_monster_file<T: serde::de::DeserializeOwned>(episode: Episode) -> T {
|
||||
// TODO: where does the rare monster toml file actually live
|
||||
let mut path = PathBuf::from("data/battle_param/");
|
||||
path.push(episode.to_string().to_lowercase() + "_rare_monster.toml");
|
||||
|
||||
let mut f = File::open(path).unwrap();
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s).unwrap();
|
||||
toml::from_str::<T>(s.as_str()).unwrap()
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("")]
|
||||
pub enum MapEnemyError {
|
||||
@ -76,6 +86,7 @@ pub enum MapEnemyError {
|
||||
MapAreaError(#[from] MapAreaError),
|
||||
}
|
||||
|
||||
|
||||
// making this `pub type` doesn't allow `impl`s to be defined?
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct RareMonsterAppearTable {
|
||||
@ -103,7 +114,7 @@ impl RareMonsterAppearTable {
|
||||
rand_chacha::ChaChaRng::from_entropy().gen::<f32>() < *self.appear_rate.get(monster).unwrap_or(&0.0f32)
|
||||
}
|
||||
|
||||
pub fn apply(&self, enemy: MapEnemy, event: ShipEvent) -> MapEnemy {
|
||||
pub fn apply(&self, enemy: MapEnemy, event: Holiday) -> MapEnemy {
|
||||
if enemy.can_be_rare() && self.roll_is_rare(&enemy.monster) {
|
||||
enemy.into_rare(event)
|
||||
}
|
||||
@ -345,12 +356,12 @@ impl MapEnemy {
|
||||
guaranteed rare monsters don't count towards the limit
|
||||
*/
|
||||
#[must_use]
|
||||
pub fn into_rare(self, event: ShipEvent) -> MapEnemy {
|
||||
pub fn into_rare(self, event: Holiday) -> MapEnemy {
|
||||
match (self.monster, self.map_area.to_episode(), event) {
|
||||
(MonsterType::RagRappy, Episode::One, _) => {MapEnemy {monster: MonsterType::AlRappy, shiny:true, ..self}},
|
||||
(MonsterType::RagRappy, Episode::Two, ShipEvent::Easter) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}},
|
||||
(MonsterType::RagRappy, Episode::Two, ShipEvent::Halloween) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}},
|
||||
(MonsterType::RagRappy, Episode::Two, ShipEvent::Christmas) => {MapEnemy {monster: MonsterType::StRappy, shiny:true, ..self}},
|
||||
(MonsterType::RagRappy, Episode::Two, Holiday::Easter) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}},
|
||||
(MonsterType::RagRappy, Episode::Two, Holiday::Halloween) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}},
|
||||
(MonsterType::RagRappy, Episode::Two, Holiday::Christmas) => {MapEnemy {monster: MonsterType::StRappy, shiny:true, ..self}},
|
||||
(MonsterType::RagRappy, Episode::Two, _) => {MapEnemy {monster: MonsterType::LoveRappy, shiny:true, ..self}},
|
||||
(MonsterType::Hildebear, _, _) => {MapEnemy {monster: MonsterType::Hildeblue, shiny:true, ..self}},
|
||||
(MonsterType::PoisonLily, _, _) => {MapEnemy {monster: MonsterType::NarLily, shiny:true, ..self}},
|
59
maps/src/lib.rs
Normal file
59
maps/src/lib.rs
Normal file
@ -0,0 +1,59 @@
|
||||
pub mod area;
|
||||
pub mod enemy;
|
||||
pub mod object;
|
||||
pub mod variant;
|
||||
pub mod maps;
|
||||
pub mod monster;
|
||||
pub mod room;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Holiday {
|
||||
None,
|
||||
Christmas,
|
||||
Valentines,
|
||||
Easter,
|
||||
Halloween,
|
||||
Sonic,
|
||||
NewYear,
|
||||
Summer,
|
||||
White,
|
||||
Wedding,
|
||||
Fall,
|
||||
Spring,
|
||||
Summer2,
|
||||
Spring2,
|
||||
}
|
||||
|
||||
|
||||
impl From<Holiday> for u32 {
|
||||
fn from(other: Holiday) -> u32 {
|
||||
u16::from(other) as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Holiday> for u16 {
|
||||
fn from(other: Holiday) -> u16 {
|
||||
u8::from(other) as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Holiday> for u8 {
|
||||
fn from(other: Holiday) -> u8 {
|
||||
match other {
|
||||
Holiday::None => 0,
|
||||
Holiday::Christmas => 1,
|
||||
Holiday::Valentines => 3,
|
||||
Holiday::Easter => 4,
|
||||
Holiday::Halloween => 5,
|
||||
Holiday::Sonic => 6,
|
||||
Holiday::NewYear => 7,
|
||||
Holiday::Summer => 8,
|
||||
Holiday::White => 9,
|
||||
Holiday::Wedding => 10,
|
||||
Holiday::Fall => 11,
|
||||
Holiday::Spring => 12,
|
||||
Holiday::Summer2 => 13,
|
||||
Holiday::Spring2 => 14,
|
||||
}
|
||||
}
|
||||
}
|
@ -6,14 +6,15 @@ use std::fs::File;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::ship::ship::ShipEvent;
|
||||
use crate::ship::monster::MonsterType;
|
||||
use crate::ship::room::{Episode, RoomMode, PlayerMode};
|
||||
|
||||
// TODO: don't use *
|
||||
use crate::ship::map::*;
|
||||
|
||||
|
||||
//use crate::ship::ship::ShipEvent;
|
||||
use crate::area::MapArea;
|
||||
use crate::Holiday;
|
||||
use crate::enemy::{MapEnemy, RawMapEnemy, RareMonsterAppearTable};
|
||||
use crate::monster::MonsterType;
|
||||
use crate::variant::{MapVariant, MapVariantMode};
|
||||
use crate::object::{MapObject, RawMapObject};
|
||||
use crate::room::{Episode, RoomMode, PlayerMode};
|
||||
|
||||
pub fn objects_from_stream(cursor: &mut impl Read, episode: &Episode, map_area: &MapArea) -> Vec<Option<MapObject>> {
|
||||
let mut object_data = Vec::new();
|
||||
@ -325,7 +326,7 @@ impl Maps {
|
||||
enemies: Vec<Option<MapEnemy>>,
|
||||
objects: Vec<Option<MapObject>>,
|
||||
rare_monster_table: &RareMonsterAppearTable,
|
||||
event: ShipEvent)
|
||||
event: Holiday)
|
||||
{
|
||||
self.enemy_data = enemies
|
||||
.into_iter()
|
||||
@ -358,7 +359,7 @@ impl Maps {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_free_roam_maps(room_mode: RoomMode, event: ShipEvent) -> Maps {
|
||||
pub fn generate_free_roam_maps(room_mode: RoomMode, event: Holiday) -> Maps {
|
||||
let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode());
|
||||
let map_variants = default_map_variants(room_mode.episode(), room_mode.player_mode());
|
||||
Maps {
|
||||
@ -375,3 +376,12 @@ pub fn generate_free_roam_maps(room_mode: RoomMode, event: ShipEvent) -> Maps {
|
||||
map_variants,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn null_free_roam_maps(_room_mode: RoomMode, _event: Holiday) -> Maps {
|
||||
Maps {
|
||||
enemy_data: Default::default(),
|
||||
object_data: Default::default(),
|
||||
map_variants: Default::default(),
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::ship::room::{Difficulty, Episode, RoomMode};
|
||||
use crate::room::{Difficulty, Episode, RoomMode};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -149,7 +149,7 @@ pub enum MonsterType {
|
||||
}
|
||||
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct MonsterStats {
|
||||
pub atp: u16,
|
||||
pub mst: u16,
|
@ -1,13 +1,11 @@
|
||||
// TOOD: `pub(super) for most of these?`
|
||||
|
||||
use std::io::{Read};
|
||||
use std::io::Read;
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
|
||||
use crate::ship::room::Episode;
|
||||
|
||||
// TODO: don't use *
|
||||
use crate::ship::map::*;
|
||||
use crate::room::Episode;
|
||||
use crate::area::MapArea;
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
150
maps/src/room.rs
Normal file
150
maps/src/room.rs
Normal file
@ -0,0 +1,150 @@
|
||||
#[derive(Debug, Copy, Clone, derive_more::Display)]
|
||||
pub enum Episode {
|
||||
#[display(fmt="ep1")]
|
||||
One,
|
||||
#[display(fmt="ep2")]
|
||||
Two,
|
||||
#[display(fmt="ep4")]
|
||||
Four,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Episode {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: u8) -> Result<Episode, ()> {
|
||||
match value {
|
||||
1 => Ok(Episode::One),
|
||||
2 => Ok(Episode::Two),
|
||||
3 => Ok(Episode::Four),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Episode> for u8 {
|
||||
fn from(other: Episode) -> u8 {
|
||||
match other {
|
||||
Episode::One => 1,
|
||||
Episode::Two => 2,
|
||||
Episode::Four => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Episode {
|
||||
pub fn from_quest(value: u8) -> Option<Episode> {
|
||||
match value {
|
||||
0 => Some(Episode::One),
|
||||
1 => Some(Episode::Two),
|
||||
2 => Some(Episode::Four),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)]
|
||||
pub enum Difficulty {
|
||||
Normal,
|
||||
Hard,
|
||||
VeryHard,
|
||||
Ultimate,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Difficulty {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: u8) -> Result<Difficulty, ()> {
|
||||
match value {
|
||||
0 => Ok(Difficulty::Normal),
|
||||
1 => Ok(Difficulty::Hard),
|
||||
2 => Ok(Difficulty::VeryHard),
|
||||
3 => Ok(Difficulty::Ultimate),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Difficulty> for u8 {
|
||||
fn from(other: Difficulty) -> u8 {
|
||||
match other {
|
||||
Difficulty::Normal => 0,
|
||||
Difficulty::Hard => 1,
|
||||
Difficulty::VeryHard => 2,
|
||||
Difficulty::Ultimate => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum PlayerMode {
|
||||
Single,
|
||||
Multi,
|
||||
}
|
||||
|
||||
impl PlayerMode {
|
||||
pub fn value(&self) -> u8 {
|
||||
match self {
|
||||
PlayerMode::Single => 1,
|
||||
PlayerMode::Multi => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, derive_more::Display)]
|
||||
pub enum RoomMode {
|
||||
#[display(fmt="single")]
|
||||
Single {
|
||||
episode: Episode,
|
||||
difficulty: Difficulty,
|
||||
},
|
||||
#[display(fmt="multi")]
|
||||
Multi {
|
||||
episode: Episode,
|
||||
difficulty: Difficulty,
|
||||
},
|
||||
#[display(fmt="challenge")]
|
||||
Challenge {
|
||||
episode: Episode,
|
||||
},
|
||||
#[display(fmt="battle")]
|
||||
Battle {
|
||||
episode: Episode,
|
||||
difficulty: Difficulty,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl RoomMode {
|
||||
pub fn difficulty(&self) -> Difficulty {
|
||||
match self {
|
||||
RoomMode::Single {difficulty, ..} => *difficulty,
|
||||
RoomMode::Multi {difficulty, ..} => *difficulty,
|
||||
RoomMode::Battle {difficulty, ..} => *difficulty,
|
||||
RoomMode::Challenge {..} => Difficulty::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn episode(&self) -> Episode {
|
||||
match self {
|
||||
RoomMode::Single {episode, ..} => *episode,
|
||||
RoomMode::Multi {episode, ..} => *episode,
|
||||
RoomMode::Battle {episode, ..} => *episode,
|
||||
RoomMode::Challenge {episode, ..} => *episode,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn battle(&self) -> bool {
|
||||
matches!(self, RoomMode::Battle {..})
|
||||
}
|
||||
|
||||
pub fn challenge(&self) -> bool {
|
||||
matches!(self, RoomMode::Challenge {..})
|
||||
}
|
||||
|
||||
pub fn player_mode(&self) -> PlayerMode {
|
||||
match self {
|
||||
RoomMode::Single {..} => PlayerMode::Single,
|
||||
_ => PlayerMode::Multi,
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,8 @@
|
||||
use rand::Rng;
|
||||
|
||||
// TODO: don't use *
|
||||
use crate::ship::map::*;
|
||||
//use crate::map::*;
|
||||
use crate::area::MapArea;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum MapVariantMode {
|
18
networking/Cargo.toml
Normal file
18
networking/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "networking"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
[dependencies]
|
||||
entity = { workspace = true }
|
||||
|
||||
libpso = { workspace = true }
|
||||
|
||||
async-std = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
derive_more = { workspace = true }
|
@ -2,8 +2,8 @@ use std::net::Ipv4Addr;
|
||||
use async_std::channel;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::de::DeserializeOwned;
|
||||
use crate::entity::account::UserAccountId;
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use entity::account::UserAccountId;
|
||||
use entity::character::CharacterEntityId;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ServerId(pub usize);
|
@ -1,7 +1,6 @@
|
||||
pub mod cipherkeys;
|
||||
pub mod serverstate;
|
||||
pub mod mainloop;
|
||||
pub mod leveltable;
|
||||
pub mod interserver;
|
||||
|
||||
// https://www.reddit.com/r/rust/comments/33xhhu/how_to_create_an_array_of_structs_that_havent/
|
@ -9,8 +9,8 @@ use log::{trace, info, warn, error};
|
||||
|
||||
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
||||
use libpso::PacketParseError;
|
||||
use crate::common::serverstate::ClientId;
|
||||
use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect};
|
||||
use crate::serverstate::ClientId;
|
||||
use crate::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -255,7 +255,7 @@ where
|
||||
let (mut socket, addr) = listener.accept().await.unwrap();
|
||||
id += 1;
|
||||
|
||||
let client_id = crate::common::serverstate::ClientId(id);
|
||||
let client_id = crate::serverstate::ClientId(id);
|
||||
info!("new client {:?} {:?} {:?}", client_id, socket, addr);
|
||||
|
||||
let (client_tx, client_rx) = async_std::channel::unbounded();
|
@ -8,13 +8,11 @@ use std::collections::HashMap;
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use crate::common::interserver::{ServerId, InterserverActor};
|
||||
use crate::interserver::{ServerId, InterserverActor};
|
||||
|
||||
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
||||
use crate::common::serverstate::{ServerState, SendServerPacket, RecvServerPacket};
|
||||
use crate::login::character::CharacterServerState;
|
||||
//use crate::ship::ship::ShipServerState;
|
||||
use crate::entity::gateway::entitygateway::EntityGateway;
|
||||
use crate::serverstate::{ServerState, SendServerPacket, RecvServerPacket};
|
||||
use entity::gateway::entitygateway::EntityGateway;
|
||||
|
||||
use async_std::channel;
|
||||
use std::fmt::Debug;
|
||||
@ -149,7 +147,7 @@ where
|
||||
info!("[interserver listen] new server: {:?} {:?}", socket, addr);
|
||||
|
||||
id += 1;
|
||||
let server_id = crate::common::interserver::ServerId(id);
|
||||
let server_id = crate::interserver::ServerId(id);
|
||||
let (client_tx, client_rx) = async_std::channel::unbounded();
|
||||
state.set_sender(server_id, client_tx.clone()).await;
|
||||
|
||||
@ -196,7 +194,7 @@ where
|
||||
}
|
||||
};
|
||||
id += 1;
|
||||
let server_id = crate::common::interserver::ServerId(id);
|
||||
let server_id = crate::interserver::ServerId(id);
|
||||
info!("[interserver connect] found loginserv: {:?} {:?}", server_id, socket);
|
||||
|
||||
let (client_tx, client_rx) = async_std::channel::unbounded();
|
||||
@ -220,12 +218,8 @@ where
|
||||
let mut buf = [0u8; 1];
|
||||
loop {
|
||||
let peek = socket.peek(&mut buf).await;
|
||||
match peek {
|
||||
Ok(len) if len == 0 => {
|
||||
break
|
||||
},
|
||||
_ => {
|
||||
}
|
||||
if let Ok(0) = peek {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
22
pktbuilder/Cargo.toml
Normal file
22
pktbuilder/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "pktbuilder"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
quests = { workspace = true }
|
||||
stats = { workspace = true }
|
||||
location = { workspace = true }
|
||||
client = { workspace = true }
|
||||
items = { workspace = true }
|
||||
networking = { workspace = true }
|
||||
maps = { workspace = true }
|
||||
room = { workspace = true }
|
||||
shops = { workspace = true }
|
||||
entity = { workspace = true }
|
||||
|
||||
libpso = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
thiserror = { workspace = true }
|
@ -1,10 +1,9 @@
|
||||
use libpso::character::character;
|
||||
use crate::common::leveltable::CharacterStats;
|
||||
use crate::entity::character::CharacterEntity;
|
||||
//use crate::ship::items::{CharacterInventory, CharacterBank};
|
||||
use crate::ship::items::bank::BankState;
|
||||
use crate::ship::items::inventory::InventoryState;
|
||||
use crate::entity::item::Meseta;
|
||||
use stats::leveltable::CharacterStats;
|
||||
use entity::character::CharacterEntity;
|
||||
use items::bank::BankState;
|
||||
use items::inventory::InventoryState;
|
||||
use entity::item::Meseta;
|
||||
|
||||
|
||||
#[derive(Default)]
|
@ -3,14 +3,15 @@ pub mod message;
|
||||
pub mod room;
|
||||
pub mod quest;
|
||||
pub mod ship;
|
||||
pub mod character;
|
||||
|
||||
use libpso::character::character::Inventory;
|
||||
use libpso::packet::ship::{PlayerHeader, PlayerInfo};
|
||||
use crate::common::leveltable::LEVEL_TABLE;
|
||||
use crate::ship::character::CharacterBytesBuilder;
|
||||
use crate::ship::ship::ClientState;
|
||||
use crate::ship::location::AreaClient;
|
||||
use crate::ship::items::inventory::InventoryState;
|
||||
use stats::leveltable::LEVEL_TABLE;
|
||||
use crate::character::CharacterBytesBuilder;
|
||||
use client::ClientState;
|
||||
use location::AreaClient;
|
||||
use items::inventory::InventoryState;
|
||||
|
||||
pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader {
|
||||
PlayerHeader {
|
@ -1,9 +1,10 @@
|
||||
use libpso::packet::ship::*;
|
||||
use crate::common::serverstate::ClientId;
|
||||
use crate::ship::ship::{Clients, ShipEvent};
|
||||
use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError};
|
||||
use crate::ship::packet::builder::{player_info};
|
||||
use crate::ship::items::state::ItemState;
|
||||
use networking::serverstate::ClientId;
|
||||
use maps::Holiday;
|
||||
use client::Clients;
|
||||
use location::{ClientLocation, LobbyId, ClientLocationError};
|
||||
use crate::player_info;
|
||||
use items::state::ItemState;
|
||||
|
||||
use futures::future::join_all;
|
||||
|
||||
@ -12,7 +13,7 @@ pub async fn join_lobby(id: ClientId,
|
||||
client_location: &ClientLocation,
|
||||
clients: &Clients,
|
||||
item_state: &ItemState,
|
||||
event: ShipEvent)
|
||||
event: Holiday)
|
||||
-> Result<JoinLobby, anyhow::Error> {
|
||||
let lobby_clients = client_location.get_clients_in_lobby(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
|
||||
@ -52,7 +53,7 @@ pub async fn add_to_lobby(id: ClientId,
|
||||
client_location: &ClientLocation,
|
||||
clients: &Clients,
|
||||
item_state: &ItemState,
|
||||
event: ShipEvent)
|
||||
event: Holiday)
|
||||
-> Result<AddToLobby, anyhow::Error> {
|
||||
let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?;
|
@ -1,21 +1,21 @@
|
||||
use libpso::packet::messages::*;
|
||||
use libpso::packet::ship::*;
|
||||
use crate::entity::item;
|
||||
use crate::common::leveltable::CharacterStats;
|
||||
use crate::ship::ship::{ShipError};
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::ship::items::inventory::InventoryItem;
|
||||
use crate::ship::items::state::IndividualItemDetail;
|
||||
use crate::ship::items::bank::BankState;
|
||||
use crate::ship::items::floor::FloorItem;
|
||||
use crate::ship::location::AreaClient;
|
||||
use entity::item;
|
||||
use stats::leveltable::CharacterStats;
|
||||
//use crate::ship::ship::{ShipError};
|
||||
use items::ClientItemId;
|
||||
use items::inventory::InventoryItem;
|
||||
use items::state::IndividualItemDetail;
|
||||
use items::bank::BankState;
|
||||
use items::floor::FloorItem;
|
||||
use location::AreaClient;
|
||||
use std::convert::TryInto;
|
||||
use crate::ship::shops::ShopItem;
|
||||
use shops::ShopItem;
|
||||
|
||||
|
||||
pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDrop, ShipError> {
|
||||
pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> ItemDrop {
|
||||
let item_bytes = item_drop.as_client_bytes();
|
||||
Ok(ItemDrop {
|
||||
ItemDrop {
|
||||
client,
|
||||
target,
|
||||
map_area: item_drop.map_area.area_value(),
|
||||
@ -24,37 +24,37 @@ pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDr
|
||||
x: item_drop.x,
|
||||
z: item_drop.z,
|
||||
y: item_drop.y,
|
||||
item_bytes: item_bytes[0..12].try_into()?,
|
||||
item_bytes: item_bytes[0..12].try_into().unwrap(),
|
||||
item_id: item_drop.item_id.0,
|
||||
item_bytes2: item_bytes[12..16].try_into()?,
|
||||
item_bytes2: item_bytes[12..16].try_into().unwrap(),
|
||||
unknown2: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
|
||||
pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &IndividualItemDetail) -> Result<CreateItem, ShipError> {
|
||||
pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &IndividualItemDetail) -> CreateItem {
|
||||
let bytes = item.as_client_bytes();
|
||||
Ok(CreateItem {
|
||||
CreateItem {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
item_data: bytes[0..12].try_into()?,
|
||||
item_data: bytes[0..12].try_into().unwrap(),
|
||||
item_id: item_id.0,
|
||||
item_data2: bytes[12..16].try_into()?,
|
||||
item_data2: bytes[12..16].try_into().unwrap(),
|
||||
unknown: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
|
||||
pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> Result<CreateItem, ShipError> {
|
||||
pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> CreateItem {
|
||||
let bytes = tool.as_stacked_bytes(amount);
|
||||
Ok(CreateItem {
|
||||
CreateItem {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
item_data: bytes[0..12].try_into()?,
|
||||
item_data: bytes[0..12].try_into().unwrap(),
|
||||
item_id: item_id.0,
|
||||
item_data2: bytes[12..16].try_into()?,
|
||||
item_data2: bytes[12..16].try_into().unwrap(),
|
||||
unknown: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem {
|
||||
@ -69,32 +69,32 @@ pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> Result<CreateItem, ShipError> {
|
||||
pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> CreateItem {
|
||||
let bytes = item.item.as_client_bytes();
|
||||
Ok(CreateItem {
|
||||
CreateItem {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
item_data: bytes[0..12].try_into()?,
|
||||
item_data: bytes[0..12].try_into().unwrap(),
|
||||
item_id: item.item_id.0,
|
||||
item_data2: bytes[12..16].try_into()?,
|
||||
item_data2: bytes[12..16].try_into().unwrap(),
|
||||
unknown: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem) -> Result<CreateItem, ShipError> {
|
||||
pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem) -> CreateItem {
|
||||
let bytes = item.item.as_client_bytes();
|
||||
Ok(CreateItem {
|
||||
CreateItem {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
item_data: bytes[0..12].try_into()?,
|
||||
item_data: bytes[0..12].try_into().unwrap(),
|
||||
item_id: item.item_id.0,
|
||||
item_data2: bytes[12..16].try_into()?,
|
||||
item_data2: bytes[12..16].try_into().unwrap(),
|
||||
unknown: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Result<RemoveItemFromFloor, ShipError> {
|
||||
Ok(RemoveItemFromFloor {
|
||||
pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> RemoveItemFromFloor {
|
||||
RemoveItemFromFloor {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
client_id: area_client.local_client.id(),
|
||||
@ -102,12 +102,12 @@ pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Resu
|
||||
map_area: item.map_area.area_value(),
|
||||
unknown2: 0,
|
||||
item_id: item.item_id.0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> Result<DropSplitStack, ShipError> {
|
||||
pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> DropSplitStack {
|
||||
let item_bytes = item.as_client_bytes();
|
||||
Ok(DropSplitStack {
|
||||
DropSplitStack {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
variety: 0,
|
||||
@ -115,16 +115,16 @@ pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> Result<Dro
|
||||
map_area: item.map_area.area_value(),
|
||||
x: item.x,
|
||||
z: item.z,
|
||||
item_bytes: item_bytes[0..12].try_into()?,
|
||||
item_bytes: item_bytes[0..12].try_into().unwrap(),
|
||||
item_id: item.item_id.0,
|
||||
item_bytes2: item_bytes[12..16].try_into()?,
|
||||
item_bytes2: item_bytes[12..16].try_into().unwrap(),
|
||||
unknown2: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> Result<DropSplitStack, ShipError> {
|
||||
pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> DropSplitStack {
|
||||
let item_bytes = item.as_client_bytes();
|
||||
Ok(DropSplitStack {
|
||||
DropSplitStack {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
variety: 0,
|
||||
@ -132,11 +132,11 @@ pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> Res
|
||||
map_area: item.map_area.area_value(),
|
||||
x: item.x,
|
||||
z: item.z,
|
||||
item_bytes: item_bytes[0..12].try_into()?,
|
||||
item_bytes: item_bytes[0..12].try_into().unwrap(),
|
||||
item_id: item.item_id.0,
|
||||
item_bytes2: item_bytes[12..16].try_into()?,
|
||||
item_bytes2: item_bytes[12..16].try_into().unwrap(),
|
||||
unknown2: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn character_gained_exp(area_client: AreaClient, exp: u32) -> GiveCharacterExp {
|
||||
@ -215,13 +215,13 @@ pub fn shop_list<I: ShopItem>(shop_type: u8, items: &[I]) -> ShopList {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tek_preview(id: ClientItemId, weapon: &item::weapon::Weapon) -> Result<TekPreview, ShipError> {
|
||||
pub fn tek_preview(id: ClientItemId, weapon: &item::weapon::Weapon) -> TekPreview {
|
||||
let bytes = weapon.as_bytes();
|
||||
Ok(TekPreview {
|
||||
TekPreview {
|
||||
client: 0x79,
|
||||
target: 0,
|
||||
item_bytes: bytes[0..12].try_into()?,
|
||||
item_bytes: bytes[0..12].try_into().unwrap(),
|
||||
item_id: id.0,
|
||||
item_bytes2: bytes[12..16].try_into()?,
|
||||
})
|
||||
item_bytes2: bytes[12..16].try_into().unwrap(),
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
use crate::ship::quests::{Quest, QuestList};
|
||||
use crate::ship::ship::{QUEST_CATEGORY_MENU_ID, QUEST_SELECT_MENU_ID};
|
||||
use quests::{Quest, QuestList};
|
||||
use libpso::packet::ship::*;
|
||||
use libpso::{utf8_to_array, utf8_to_utf16_array};
|
||||
|
||||
pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2;
|
||||
pub const QUEST_SELECT_MENU_ID: u32 = 0xA3;
|
||||
|
||||
pub fn quest_category_list(quests: &QuestList) -> QuestCategoryList {
|
||||
let categories = quests.iter()
|
@ -1,11 +1,12 @@
|
||||
use libpso::packet::ship::*;
|
||||
use crate::common::serverstate::ClientId;
|
||||
use crate::ship::ship::{ShipError, ClientState, Clients, ShipEvent};
|
||||
use crate::ship::location::{ClientLocation, RoomId, AreaClient, ClientLocationError};
|
||||
use crate::ship::room::RoomState;
|
||||
use crate::ship::items::state::ItemState;
|
||||
use crate::ship::packet::builder::{player_header, player_info};
|
||||
use std::convert::TryInto;
|
||||
use libpso::packet::ship::*;
|
||||
use networking::serverstate::ClientId;
|
||||
use maps::Holiday;
|
||||
use client::{ClientState, Clients};
|
||||
use location::{ClientLocation, RoomId, AreaClient, ClientLocationError};
|
||||
use room::RoomState;
|
||||
use items::state::ItemState;
|
||||
use crate::{player_header, player_info};
|
||||
|
||||
use futures::stream::StreamExt;
|
||||
|
||||
@ -14,13 +15,14 @@ pub async fn join_room(id: ClientId,
|
||||
client_location: &ClientLocation,
|
||||
room_id: RoomId,
|
||||
room: &RoomState,
|
||||
event: ShipEvent)
|
||||
event: Holiday)
|
||||
-> Result<JoinRoom, anyhow::Error> {
|
||||
let all_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
#[allow(clippy::manual_try_fold)] // I don't think its even possible to make this work here
|
||||
let players = futures::stream::iter(all_clients.iter())
|
||||
.enumerate()
|
||||
.fold::<Result<_, anyhow::Error>, _, _>(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| async move {
|
||||
let header_area_client = client_location.get_local_client(id).await.map_err(|err| ShipError::ClientLocationError(err.into()))?;
|
||||
let header_area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError {err.into() })?;
|
||||
clients.with(c.client, |client| Box::pin(async move {
|
||||
acc.map(|mut a| {
|
||||
a[i] = player_header(0x10000, client, &header_area_client);
|
||||
@ -57,7 +59,7 @@ pub async fn add_to_room(_id: ClientId,
|
||||
area_client: &AreaClient,
|
||||
leader: &AreaClient,
|
||||
item_state: &ItemState,
|
||||
event: ShipEvent)
|
||||
event: Holiday)
|
||||
-> Result<AddToRoom, anyhow::Error> {
|
||||
let inventory = item_state.get_character_inventory(&client.character).await?;
|
||||
Ok(AddToRoom {
|
@ -1,8 +1,9 @@
|
||||
use libpso::packet::login::{ShipList, ShipListEntry};
|
||||
use libpso::utf8_to_utf16_array;
|
||||
|
||||
use crate::common::interserver::Ship;
|
||||
use crate::login::character::SHIP_MENU_ID;
|
||||
use networking::interserver::Ship;
|
||||
|
||||
pub const SHIP_MENU_ID: u32 = 1;
|
||||
|
||||
pub fn ship_list(ships: &[Ship]) -> ShipList {
|
||||
let ships = ships.iter()
|
107
pktbuilder/src/team.rs
Normal file
107
pktbuilder/src/team.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use futures::stream::{FuturesOrdered, StreamExt};
|
||||
use libpso::packet::ship::*;
|
||||
use crate::common::serverstate::ClientId;
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use crate::ship::client::{Clients, ClientState};
|
||||
use crate::ship::teams::Teams;
|
||||
use crate::ship::location::ClientLocation;
|
||||
use crate::ship::ship::ShipError;
|
||||
use crate::entity::team::TeamEntity;
|
||||
|
||||
|
||||
pub fn client_team_state_changed(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> ClientTeamStateChanged {
|
||||
ClientTeamStateChanged {
|
||||
unknown: 0,
|
||||
guildcard: client.user.guildcard(),
|
||||
team_id: team.id.0,
|
||||
unknown2: [0;2],
|
||||
privilege: 0x40, // TODO: improve
|
||||
team_name: libpso::utf8_to_utf16_array!(team.name, 14),
|
||||
unknown3: 0x00986C84, // TODO: what if we omit this?
|
||||
}
|
||||
}
|
||||
|
||||
fn player_team_info(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> PlayerTeamInfo {
|
||||
PlayerTeamInfo {
|
||||
guildcard: client.user.guildcard(),
|
||||
team_id: team.id.0,
|
||||
info: 0,
|
||||
info2: 0,
|
||||
privilege: 0x40, // TODO: improve
|
||||
team_name: libpso::utf8_to_utf16_array!(team.name, 14),
|
||||
unknown: 0x00986C84, // TODO: what if we omit this?
|
||||
guildcard_again: client.user.guildcard(),
|
||||
client_id: client_id.0 as u32,
|
||||
character_name: libpso::utf8_to_utf16_array!(client.character.name, 12),
|
||||
unknown2: 0,
|
||||
unknown3: 0,
|
||||
team_flag: team.team_flag,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn team_info_individual(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> TeamInfo {
|
||||
TeamInfo {
|
||||
clients: vec![player_team_info(client_id, client, team)]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn player_team_info_list<EG>(id: ClientId,
|
||||
client_location: &ClientLocation,
|
||||
clients: &Clients,
|
||||
teams: &Teams<EG>,
|
||||
) -> Result<Vec<PlayerTeamInfo>, ShipError>
|
||||
where
|
||||
EG: EntityGateway + Clone + 'static,
|
||||
{
|
||||
Ok(futures::stream::iter(client_location.get_all_clients_by_client(id).await?.into_iter())
|
||||
.filter_map(|area_client| {
|
||||
let clients = clients.clone();
|
||||
async move {
|
||||
clients.with(area_client.client, |client| {
|
||||
let mut teams = teams.clone();
|
||||
Box::pin(async move {
|
||||
let team = teams.get_team(area_client.client).await.ok()??;
|
||||
Some(player_team_info(area_client.client, client, &team))
|
||||
})}).await.ok()?
|
||||
}})
|
||||
.collect::<Vec<_>>()
|
||||
.await)
|
||||
}
|
||||
|
||||
pub async fn team_info<EG>(id: ClientId,
|
||||
client_location: &ClientLocation,
|
||||
clients: &Clients,
|
||||
teams: &Teams<EG>,
|
||||
) -> Result<TeamInfo, ShipError>
|
||||
where
|
||||
EG: EntityGateway + Clone + 'static,
|
||||
{
|
||||
Ok(TeamInfo {
|
||||
clients: player_team_info_list(id, client_location, clients, teams).await?,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn lobby_team_list<EG>(id: ClientId,
|
||||
client_location: &ClientLocation,
|
||||
clients: &Clients,
|
||||
teams: &Teams<EG>,
|
||||
) -> Result<TeamLobbyList, ShipError>
|
||||
where
|
||||
EG: EntityGateway + Clone + 'static,
|
||||
{
|
||||
Ok(TeamLobbyList {
|
||||
clients: player_team_info_list(id, client_location, clients, teams).await?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn team_invitation_info(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> TeamInvitationInfo {
|
||||
TeamInvitationInfo {
|
||||
guildcard: client.user.guildcard(),
|
||||
team_id: team.id.0,
|
||||
unknown: [0; 2],
|
||||
team_name: libpso::utf8_to_utf16_array!(team.name, 14),
|
||||
unknown2: 0x00986C84, // TODO: what if we omit this?
|
||||
team_flag: team.team_flag,
|
||||
}
|
||||
}
|
18
quests/Cargo.toml
Normal file
18
quests/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "quests"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
maps = { workspace = true }
|
||||
|
||||
libpso = { workspace = true }
|
||||
|
||||
async-std = { workspace = true }
|
||||
ages-prs = { workspace = true }
|
||||
log = { workspace = true }
|
||||
byteorder = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
serde = { workspace = true }
|
@ -10,9 +10,12 @@ use serde::{Serialize, Deserialize};
|
||||
use ages_prs::{LegacyPrsDecoder, LegacyPrsEncoder};
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use libpso::util::array_to_utf16;
|
||||
use crate::ship::map::{MapArea, MapAreaError, MapObject, MapEnemy, enemy_data_from_stream, objects_from_stream};
|
||||
use crate::ship::room::{Episode, RoomMode};
|
||||
use crate::ship::map::area::{MapAreaLookup, MapAreaLookupBuilder};
|
||||
use maps::area::{MapArea, MapAreaError};
|
||||
use maps::object::MapObject;
|
||||
use maps::enemy::MapEnemy;
|
||||
use maps::maps::{objects_from_stream, enemy_data_from_stream};
|
||||
use maps::room::{Episode, RoomMode};
|
||||
use maps::area::{MapAreaLookup, MapAreaLookupBuilder};
|
||||
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
@ -101,7 +104,7 @@ fn quest_episode(bin: &[u8]) -> Option<Episode> {
|
||||
for bytes in bin.windows(3) {
|
||||
// set_episode
|
||||
if bytes[0] == 0xF8 && bytes[1] == 0xBC {
|
||||
return Episode::from_quest(bytes[2]).ok()
|
||||
return Episode::from_quest(bytes[2])
|
||||
}
|
||||
}
|
||||
None
|
17
room/Cargo.toml
Normal file
17
room/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "room"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
maps = { workspace = true }
|
||||
entity = { workspace = true }
|
||||
quests = { workspace = true }
|
||||
location = { workspace = true }
|
||||
drops = { workspace = true }
|
||||
|
||||
rand = { workspace = true }
|
||||
async-std = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
thiserror = { workspace = true }
|
@ -1,5 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::convert::{From, Into, TryFrom};
|
||||
use std::convert::{From, Into};
|
||||
use async_std::sync::{Arc, RwLock, RwLockReadGuard};
|
||||
use futures::future::BoxFuture;
|
||||
use futures::stream::{FuturesOrdered, Stream};
|
||||
@ -7,19 +7,29 @@ use futures::stream::{FuturesOrdered, Stream};
|
||||
use thiserror::Error;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::ship::map::Maps;
|
||||
use crate::ship::drops::DropTable;
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::entity::room::{RoomEntityId, RoomEntityMode};
|
||||
use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats};
|
||||
use crate::ship::map::area::MapAreaLookup;
|
||||
use crate::ship::quests;
|
||||
use crate::ship::ship::{ShipError, ShipEvent};
|
||||
use crate::ship::location::{MAX_ROOMS, RoomId};
|
||||
use quests::{QuestList, QuestLoadError};
|
||||
use maps::maps::Maps;
|
||||
use drops::DropTable;
|
||||
use entity::character::SectionID;
|
||||
use entity::room::{RoomEntityId, RoomEntityMode};
|
||||
use maps::monster::{load_monster_stats_table, MonsterType, MonsterStats};
|
||||
use maps::area::MapAreaLookup;
|
||||
use maps::Holiday;
|
||||
use location::{MAX_ROOMS, RoomId};
|
||||
|
||||
use maps::room::{Episode, Difficulty, RoomMode};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum RoomError {
|
||||
#[error("invalid room id {0}")]
|
||||
Invalid(u32),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Rooms([Arc<RwLock<Option<RoomState>>>; MAX_ROOMS]);
|
||||
|
||||
|
||||
impl Default for Rooms {
|
||||
fn default() -> Rooms {
|
||||
Rooms(core::array::from_fn(|_| Arc::new(RwLock::new(None))))
|
||||
@ -30,7 +40,7 @@ impl Rooms {
|
||||
pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), anyhow::Error> {
|
||||
*self.0
|
||||
.get(room_id.0)
|
||||
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
|
||||
.ok_or(RoomError::Invalid(room_id.0 as u32))?
|
||||
.write()
|
||||
.await = Some(room);
|
||||
Ok(())
|
||||
@ -63,14 +73,14 @@ impl Rooms {
|
||||
{
|
||||
let room = self.0
|
||||
.get(room_id.0)
|
||||
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
|
||||
.ok_or(RoomError::Invalid(room_id.0 as u32))?
|
||||
.read()
|
||||
.await;
|
||||
if let Some(room) = room.as_ref() {
|
||||
Ok(func(room).await)
|
||||
}
|
||||
else {
|
||||
Err(ShipError::InvalidRoom(room_id.0 as u32).into())
|
||||
Err(RoomError::Invalid(room_id.0 as u32).into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +91,7 @@ impl Rooms {
|
||||
{
|
||||
let mut room = self.0
|
||||
.get(room_id.0)
|
||||
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
|
||||
.ok_or(RoomError::Invalid(room_id.0 as u32))?
|
||||
.write()
|
||||
.await;
|
||||
|
||||
@ -89,7 +99,7 @@ impl Rooms {
|
||||
Ok(func(room).await)
|
||||
}
|
||||
else {
|
||||
Err(ShipError::InvalidRoom(room_id.0 as u32).into())
|
||||
Err(RoomError::Invalid(room_id.0 as u32).into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,156 +133,7 @@ pub enum RoomCreationError {
|
||||
CouldNotLoadQuests,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, derive_more::Display)]
|
||||
pub enum Episode {
|
||||
#[display(fmt="ep1")]
|
||||
One,
|
||||
#[display(fmt="ep2")]
|
||||
Two,
|
||||
#[display(fmt="ep4")]
|
||||
Four,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum PlayerMode{
|
||||
Single,
|
||||
Multi,
|
||||
}
|
||||
|
||||
impl PlayerMode {
|
||||
pub fn value(&self) -> u8 {
|
||||
match self {
|
||||
PlayerMode::Single => 1,
|
||||
PlayerMode::Multi => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Episode {
|
||||
type Error = RoomCreationError;
|
||||
|
||||
fn try_from(value: u8) -> Result<Episode, RoomCreationError> {
|
||||
match value {
|
||||
1 => Ok(Episode::One),
|
||||
2 => Ok(Episode::Two),
|
||||
3 => Ok(Episode::Four),
|
||||
_ => Err(RoomCreationError::InvalidEpisode(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Episode> for u8 {
|
||||
fn from(other: Episode) -> u8 {
|
||||
match other {
|
||||
Episode::One => 1,
|
||||
Episode::Two => 2,
|
||||
Episode::Four => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Episode {
|
||||
pub fn from_quest(value: u8) -> Result<Episode, RoomCreationError> {
|
||||
match value {
|
||||
0 => Ok(Episode::One),
|
||||
1 => Ok(Episode::Two),
|
||||
2 => Ok(Episode::Four),
|
||||
_ => Err(RoomCreationError::InvalidEpisode(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)]
|
||||
pub enum Difficulty {
|
||||
Normal,
|
||||
Hard,
|
||||
VeryHard,
|
||||
Ultimate,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Difficulty {
|
||||
type Error = RoomCreationError;
|
||||
|
||||
fn try_from(value: u8) -> Result<Difficulty, RoomCreationError> {
|
||||
match value {
|
||||
0 => Ok(Difficulty::Normal),
|
||||
1 => Ok(Difficulty::Hard),
|
||||
2 => Ok(Difficulty::VeryHard),
|
||||
3 => Ok(Difficulty::Ultimate),
|
||||
_ => Err(RoomCreationError::InvalidDifficulty(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Difficulty> for u8 {
|
||||
fn from(other: Difficulty) -> u8 {
|
||||
match other {
|
||||
Difficulty::Normal => 0,
|
||||
Difficulty::Hard => 1,
|
||||
Difficulty::VeryHard => 2,
|
||||
Difficulty::Ultimate => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, derive_more::Display)]
|
||||
pub enum RoomMode {
|
||||
#[display(fmt="single")]
|
||||
Single {
|
||||
episode: Episode,
|
||||
difficulty: Difficulty,
|
||||
},
|
||||
#[display(fmt="multi")]
|
||||
Multi {
|
||||
episode: Episode,
|
||||
difficulty: Difficulty,
|
||||
},
|
||||
#[display(fmt="challenge")]
|
||||
Challenge {
|
||||
episode: Episode,
|
||||
},
|
||||
#[display(fmt="battle")]
|
||||
Battle {
|
||||
episode: Episode,
|
||||
difficulty: Difficulty,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl RoomMode {
|
||||
pub fn difficulty(&self) -> Difficulty {
|
||||
match self {
|
||||
RoomMode::Single {difficulty, ..} => *difficulty,
|
||||
RoomMode::Multi {difficulty, ..} => *difficulty,
|
||||
RoomMode::Battle {difficulty, ..} => *difficulty,
|
||||
RoomMode::Challenge {..} => Difficulty::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn episode(&self) -> Episode {
|
||||
match self {
|
||||
RoomMode::Single {episode, ..} => *episode,
|
||||
RoomMode::Multi {episode, ..} => *episode,
|
||||
RoomMode::Battle {episode, ..} => *episode,
|
||||
RoomMode::Challenge {episode, ..} => *episode,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn battle(&self) -> bool {
|
||||
matches!(self, RoomMode::Battle {..})
|
||||
}
|
||||
|
||||
pub fn challenge(&self) -> bool {
|
||||
matches!(self, RoomMode::Challenge {..})
|
||||
}
|
||||
|
||||
pub fn player_mode(&self) -> PlayerMode {
|
||||
match self {
|
||||
RoomMode::Single {..} => PlayerMode::Single,
|
||||
_ => PlayerMode::Multi,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub enum QuestCategoryType {
|
||||
Standard,
|
||||
Government,
|
||||
@ -310,15 +171,15 @@ pub struct RoomState {
|
||||
pub name: String,
|
||||
pub password: [u16; 16],
|
||||
pub maps: Maps,
|
||||
pub drop_table: Box<DropTable>,
|
||||
pub drop_table: Box<dyn DropTable + Send + Sync>,
|
||||
pub section_id: SectionID,
|
||||
pub random_seed: u32,
|
||||
pub bursting: bool,
|
||||
pub monster_stats: Box<HashMap<MonsterType, MonsterStats>>,
|
||||
pub map_areas: MapAreaLookup,
|
||||
pub quest_group: QuestCategoryType,
|
||||
pub standard_quests: quests::QuestList,
|
||||
pub government_quests: quests::QuestList,
|
||||
pub standard_quests: QuestList,
|
||||
pub government_quests: QuestList,
|
||||
// enemy info
|
||||
}
|
||||
|
||||
@ -353,14 +214,14 @@ impl RoomState {
|
||||
difficulty + 0x22
|
||||
}
|
||||
|
||||
pub fn quests(&self) -> &quests::QuestList {
|
||||
pub fn quests(&self) -> &QuestList {
|
||||
match self.quest_group {
|
||||
QuestCategoryType::Standard => &self.standard_quests,
|
||||
QuestCategoryType::Government => &self.government_quests,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
|
||||
pub fn new (room_id: RoomEntityId,
|
||||
mode: RoomEntityMode,
|
||||
episode: Episode,
|
||||
@ -368,9 +229,11 @@ impl RoomState {
|
||||
section_id: SectionID,
|
||||
name: String,
|
||||
password: [u16; 16],
|
||||
event: ShipEvent,
|
||||
map_builder: Arc<Box<dyn Fn(RoomMode, ShipEvent) -> Maps + Send + Sync>>,
|
||||
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
|
||||
event: Holiday,
|
||||
map_builder: Arc<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>,
|
||||
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> Box<dyn DropTable + Send + Sync> + Send + Sync>>,
|
||||
standard_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
|
||||
government_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
|
||||
) -> Result<RoomState, anyhow::Error> {
|
||||
let mode = match mode {
|
||||
RoomEntityMode::Single => RoomMode::Single {
|
||||
@ -399,12 +262,12 @@ impl RoomState {
|
||||
password,
|
||||
maps: map_builder(mode, event),
|
||||
section_id,
|
||||
drop_table: Box::new(drop_table_builder(episode, difficulty, section_id)),
|
||||
drop_table: drop_table_builder(episode, difficulty, section_id),
|
||||
bursting: false,
|
||||
map_areas: MapAreaLookup::new(&episode),
|
||||
quest_group: QuestCategoryType::Standard,
|
||||
standard_quests: quests::load_standard_quests(mode)?,
|
||||
government_quests: quests::load_government_quests(mode)?,
|
||||
standard_quests: standard_quest_builder(mode)?,
|
||||
government_quests: government_quest_builder(mode)?,
|
||||
})
|
||||
|
||||
}
|
17
shops/Cargo.toml
Normal file
17
shops/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "shops"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
maps = { workspace = true }
|
||||
stats = { workspace = true }
|
||||
entity = { workspace = true }
|
||||
|
||||
async-std = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
rand_chacha = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
serde = { workspace = true }
|
@ -5,12 +5,12 @@ use std::convert::TryInto;
|
||||
use serde::Deserialize;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
use crate::entity::item::ItemDetail;
|
||||
use crate::entity::item::armor::{Armor, ArmorType};
|
||||
use crate::entity::item::shield::{Shield, ShieldType};
|
||||
use crate::entity::item::unit::{Unit, UnitType};
|
||||
use crate::ship::shops::ShopItem;
|
||||
use crate::ship::item_stats::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS};
|
||||
use entity::item::ItemDetail;
|
||||
use entity::item::armor::{Armor, ArmorType};
|
||||
use entity::item::shield::{Shield, ShieldType};
|
||||
use entity::item::unit::{Unit, UnitType};
|
||||
use crate::ShopItem;
|
||||
use stats::items::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS};
|
||||
|
||||
// #[derive(Debug)]
|
||||
// pub enum ArmorShopItem {
|
||||
@ -342,8 +342,8 @@ impl<R: Rng + SeedableRng> ArmorShop<R> {
|
||||
|
||||
pub fn generate_armor_list(&mut self, character_level: usize) -> Vec<ArmorShopItem> {
|
||||
self.generate_frame_list(character_level).into_iter()
|
||||
.chain(self.generate_barrier_list(character_level).into_iter())
|
||||
.chain(self.generate_unit_list(character_level).into_iter())
|
||||
.chain(self.generate_barrier_list(character_level))
|
||||
.chain(self.generate_unit_list(character_level))
|
||||
.collect()
|
||||
}
|
||||
}
|
95
shops/src/lib.rs
Normal file
95
shops/src/lib.rs
Normal file
@ -0,0 +1,95 @@
|
||||
mod weapon;
|
||||
mod tool;
|
||||
mod armor;
|
||||
|
||||
use async_std::sync::{Arc, Mutex};
|
||||
use futures::future::OptionFuture;
|
||||
use std::collections::HashMap;
|
||||
use entity::item::ItemDetail;
|
||||
use maps::room::Difficulty;
|
||||
use entity::character::SectionID;
|
||||
|
||||
pub use weapon::{WeaponShop, WeaponShopItem};
|
||||
pub use tool::{ToolShop, ToolShopItem};
|
||||
pub use armor::{ArmorShop, ArmorShopItem};
|
||||
|
||||
pub trait ShopItem {
|
||||
fn price(&self) -> usize;
|
||||
fn as_bytes(&self) -> [u8; 12];
|
||||
fn as_item(&self) -> ItemDetail;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait ItemShops {
|
||||
async fn generate_weapon_list(&self, difficulty: Difficulty, section_id: SectionID, char_level: usize) -> Option<Vec<WeaponShopItem>>;
|
||||
async fn generate_tool_list(&self, char_level: usize) -> Vec<ToolShopItem>;
|
||||
async fn generate_armor_list(&self, char_level: usize) -> Vec<ArmorShopItem>;
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StandardItemShops {
|
||||
weapon_shop: HashMap<(Difficulty, SectionID), Arc<Mutex<WeaponShop<rand_chacha::ChaCha20Rng>>>>,
|
||||
tool_shop: Arc<Mutex<ToolShop<rand_chacha::ChaCha20Rng>>>,
|
||||
armor_shop: Arc<Mutex<ArmorShop<rand_chacha::ChaCha20Rng>>>,
|
||||
}
|
||||
|
||||
impl Default for StandardItemShops {
|
||||
fn default() -> StandardItemShops {
|
||||
let difficulty = [Difficulty::Normal, Difficulty::Hard, Difficulty::VeryHard, Difficulty::Ultimate];
|
||||
let section_id = [SectionID::Viridia, SectionID::Greenill, SectionID::Skyly, SectionID::Bluefull, SectionID::Purplenum,
|
||||
SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill];
|
||||
|
||||
let mut weapon_shop = HashMap::new();
|
||||
for d in difficulty.iter() {
|
||||
for id in section_id.iter() {
|
||||
weapon_shop.insert((*d, *id), Arc::new(Mutex::new(WeaponShop::new(*d, *id))));
|
||||
}
|
||||
}
|
||||
|
||||
StandardItemShops {
|
||||
weapon_shop,
|
||||
tool_shop: Arc::new(Mutex::new(ToolShop::default())),
|
||||
armor_shop: Arc::new(Mutex::new(ArmorShop::default())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ItemShops for StandardItemShops {
|
||||
async fn generate_weapon_list(&self, difficulty: Difficulty, section_id: SectionID, char_level: usize) -> Option<Vec<WeaponShopItem>> {
|
||||
OptionFuture::from(
|
||||
self.weapon_shop
|
||||
.get(&(difficulty, section_id))
|
||||
.map(|shop| async {
|
||||
shop
|
||||
.lock()
|
||||
.await
|
||||
.generate_weapon_list(char_level)
|
||||
})).await
|
||||
}
|
||||
|
||||
async fn generate_tool_list(&self, char_level: usize) -> Vec<ToolShopItem> {
|
||||
self.tool_shop
|
||||
.lock()
|
||||
.await
|
||||
.generate_tool_list(char_level)
|
||||
}
|
||||
|
||||
async fn generate_armor_list(&self, char_level: usize) -> Vec<ArmorShopItem> {
|
||||
self.armor_shop
|
||||
.lock()
|
||||
.await
|
||||
.generate_armor_list(char_level)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pub enum ShopType {
|
||||
Weapon,
|
||||
Tool,
|
||||
Armor
|
||||
}
|
||||
|
@ -6,11 +6,11 @@ use std::convert::TryInto;
|
||||
use serde::Deserialize;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
use crate::entity::item::ItemDetail;
|
||||
use crate::entity::item::tool::{Tool, ToolType};
|
||||
use crate::entity::item::tech::{Technique, TechniqueDisk};
|
||||
use crate::ship::shops::ShopItem;
|
||||
use crate::ship::item_stats::{TOOL_STATS, TECH_STATS};
|
||||
use entity::item::ItemDetail;
|
||||
use entity::item::tool::{Tool, ToolType};
|
||||
use entity::item::tech::{Technique, TechniqueDisk};
|
||||
use crate::ShopItem;
|
||||
use stats::items::{TOOL_STATS, TECH_STATS};
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@ -36,16 +36,7 @@ impl Ord for ToolShopItem {
|
||||
|
||||
impl PartialOrd for ToolShopItem {
|
||||
fn partial_cmp(&self, other: &ToolShopItem) -> Option<std::cmp::Ordering> {
|
||||
let a = match self {
|
||||
ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(),
|
||||
ToolShopItem::Tech(t) => t.as_bytes(),
|
||||
};
|
||||
let b = match other {
|
||||
ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(),
|
||||
ToolShopItem::Tech(t) => t.as_bytes(),
|
||||
};
|
||||
|
||||
a.partial_cmp(&b)
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +276,7 @@ impl<R: Rng + SeedableRng> ToolShop<R> {
|
||||
pub fn generate_tool_list(&mut self, character_level: usize) -> Vec<ToolShopItem> {
|
||||
let mut tools = Vec::new().into_iter()
|
||||
.chain(self.tools.0.clone().into_iter().map(ToolShopItem::Tool))
|
||||
.chain(self.generate_techs(character_level).into_iter())
|
||||
.chain(self.generate_techs(character_level))
|
||||
.collect::<Vec<_>>();
|
||||
tools.sort();
|
||||
tools
|
@ -8,12 +8,12 @@ use serde::Deserialize;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand::distributions::{WeightedIndex, Distribution};
|
||||
use rand::seq::{SliceRandom, IteratorRandom};
|
||||
use crate::entity::character::SectionID;
|
||||
use crate::ship::room::Difficulty;
|
||||
use crate::entity::item::ItemDetail;
|
||||
use crate::entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute};
|
||||
use crate::ship::shops::ShopItem;
|
||||
use crate::ship::item_stats::WEAPON_STATS;
|
||||
use entity::character::SectionID;
|
||||
use maps::room::Difficulty;
|
||||
use entity::item::ItemDetail;
|
||||
use entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute};
|
||||
use crate::ShopItem;
|
||||
use stats::items::WEAPON_STATS;
|
||||
|
||||
|
||||
const TIER1_SPECIAL: [WeaponSpecial; 8] = [WeaponSpecial::Draw, WeaponSpecial::Heart, WeaponSpecial::Ice, WeaponSpecial::Bind,
|
||||
@ -412,7 +412,7 @@ impl<R: Rng + SeedableRng> WeaponShop<R> {
|
||||
.last()
|
||||
.unwrap();
|
||||
|
||||
let attr_choice = WeightedIndex::new(&[tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap();
|
||||
let attr_choice = WeightedIndex::new([tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap();
|
||||
let attr = match attr_choice.sample(&mut self.rng) {
|
||||
0 => return None,
|
||||
1 => Attribute::Native,
|
||||
@ -439,7 +439,7 @@ impl<R: Rng + SeedableRng> WeaponShop<R> {
|
||||
.last()
|
||||
.unwrap();
|
||||
|
||||
let attr_choice = WeightedIndex::new(&[tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap();
|
||||
let attr_choice = WeightedIndex::new([tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap();
|
||||
let attr = match attr_choice.sample(&mut self.rng) {
|
||||
0 => return None,
|
||||
1 => Attribute::Native,
|
@ -1,8 +1,8 @@
|
||||
use log::{info};
|
||||
use elseware::entity::gateway::postgres::PostgresGateway;
|
||||
use entity::gateway::postgres::PostgresGateway;
|
||||
use elseware::login::login::LoginServerState;
|
||||
use elseware::login::character::CharacterServerState;
|
||||
use elseware::common::interserver::AuthToken;
|
||||
use networking::interserver::AuthToken;
|
||||
|
||||
fn main() {
|
||||
let colors = fern::colors::ColoredLevelConfig::new()
|
||||
@ -38,17 +38,17 @@ fn main() {
|
||||
|
||||
let login_state = LoginServerState::new(entity_gateway.clone(), charserv_ip);
|
||||
let login_loop = async_std::task::spawn(async move {
|
||||
elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await;
|
||||
networking::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await;
|
||||
});
|
||||
|
||||
let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token));
|
||||
let sub_char_state = char_state.clone();
|
||||
let character_loop = async_std::task::spawn(async move {
|
||||
elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await;
|
||||
networking::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await;
|
||||
});
|
||||
|
||||
let inter_character_loop = async_std::task::spawn(async move {
|
||||
elseware::common::mainloop::run_interserver_listen(char_state, elseware::login::login::COMMUNICATION_PORT).await;
|
||||
networking::mainloop::run_interserver_listen(char_state, elseware::login::login::COMMUNICATION_PORT).await;
|
||||
});
|
||||
|
||||
info!("[auth/character] starting server");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user