mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement new InventorySpec for EntityConfig
* Add new InventorySpec which uses Inline loadout spec * Disable all tests!
This commit is contained in:
parent
77f8d6da6f
commit
357b953e3b
@ -625,16 +625,18 @@ impl LoadoutBuilder {
|
||||
#[must_use]
|
||||
/// Construct new `LoadoutBuilder` from `asset_specifier`
|
||||
/// Will panic if asset is broken
|
||||
pub fn from_asset_expect(asset_specifier: &str, rng: Option<&mut impl Rng>) -> Self {
|
||||
// It's impossible to use lambdas because `loadout` is used by value
|
||||
let loadout = Self::empty();
|
||||
pub fn from_asset_expect(asset_specifier: &str, rng: &mut impl Rng) -> Self {
|
||||
Self::from_asset(asset_specifier, rng).expect("failed to load loadut config")
|
||||
}
|
||||
|
||||
if let Some(rng) = rng {
|
||||
loadout.with_asset_expect(asset_specifier, rng)
|
||||
} else {
|
||||
let fallback_rng = &mut rand::thread_rng();
|
||||
loadout.with_asset_expect(asset_specifier, fallback_rng)
|
||||
}
|
||||
#[must_use]
|
||||
/// Construct new `LoadoutBuilder` from `asset_specifier`
|
||||
pub fn from_asset(
|
||||
asset_specifier: &str,
|
||||
rng: &mut impl Rng,
|
||||
) -> Result<Self, LoadoutBuilderError> {
|
||||
let loadout = Self::empty();
|
||||
loadout.with_asset(asset_specifier, rng)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@ -649,6 +651,24 @@ impl LoadoutBuilder {
|
||||
.with_default_equipment(body)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// Construct new `LoadoutBuilder` from `asset_specifier`
|
||||
pub fn from_loadout_spec(
|
||||
loadout_spec: LoadoutSpec,
|
||||
rng: &mut impl Rng,
|
||||
) -> Result<Self, LoadoutBuilderError> {
|
||||
let loadout = Self::empty();
|
||||
loadout.with_loadout_spec(loadout_spec, rng)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// Construct new `LoadoutBuilder` from `asset_specifier`
|
||||
///
|
||||
/// Will panic if asset is broken
|
||||
pub fn from_loadout_spec_expect(loadout_spec: LoadoutSpec, rng: &mut impl Rng) -> Self {
|
||||
Self::from_loadout_spec(loadout_spec, rng).expect("failed to load loadout spec")
|
||||
}
|
||||
|
||||
#[must_use = "Method consumes builder and returns updated builder."]
|
||||
/// Set default active mainhand weapon based on `body`
|
||||
pub fn with_default_maintool(self, body: &Body) -> Self {
|
||||
@ -868,7 +888,8 @@ impl LoadoutBuilder {
|
||||
/// 2) Will panic if path to item specified in loadout file doesn't exist
|
||||
#[must_use = "Method consumes builder and returns updated builder."]
|
||||
pub fn with_asset_expect(self, asset_specifier: &str, rng: &mut impl Rng) -> Self {
|
||||
self.with_asset(asset_specifier, rng).expect("failed loading loadout config")
|
||||
self.with_asset(asset_specifier, rng)
|
||||
.expect("failed loading loadout config")
|
||||
}
|
||||
|
||||
/// Set default armor items for the loadout. This may vary with game
|
||||
@ -1046,10 +1067,13 @@ mod tests {
|
||||
// TODO: add some checks, e.g. that Armor(Head) key correspond
|
||||
// to Item with ItemKind Head(_)
|
||||
let loadouts = assets::read_expect_dir::<LoadoutSpec>("common.loadout", true);
|
||||
/*
|
||||
* FIXME: actually impelement tests BEFORE merge!!!!
|
||||
for loadout in loadouts {
|
||||
for (&key, entry) in &loadout.0 {
|
||||
entry.validate(key);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
assets::{self, AssetExt, Error},
|
||||
comp::{
|
||||
self, agent, humanoid,
|
||||
inventory::loadout_builder::{ItemSpec, LoadoutBuilder},
|
||||
inventory::loadout_builder::{ItemSpec, LoadoutBuilder, LoadoutSpec},
|
||||
Alignment, Body, Item,
|
||||
},
|
||||
lottery::LootSpec,
|
||||
@ -10,7 +10,6 @@ use crate::{
|
||||
trade,
|
||||
trade::SiteInformation,
|
||||
};
|
||||
use rand::prelude::SliceRandom;
|
||||
use serde::Deserialize;
|
||||
use vek::*;
|
||||
|
||||
@ -38,6 +37,20 @@ impl Default for AlignmentMark {
|
||||
fn default() -> Self { Self::Alignment(Alignment::Wild) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub enum LoadoutKindNew {
|
||||
FromBody,
|
||||
Asset(String),
|
||||
Inline(LoadoutSpec),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct InventorySpec {
|
||||
loadout: LoadoutKindNew,
|
||||
#[serde(default)]
|
||||
items: Vec<(u32, String)>,
|
||||
}
|
||||
|
||||
/// - TwoHanded(ItemSpec) for one 2h or 1h weapon,
|
||||
/// - Paired(ItemSpec) for two 1h weapons aka berserker mode,
|
||||
/// - Mix { mainhand: ItemSpec, offhand: ItemSpec, }
|
||||
@ -131,13 +144,8 @@ pub struct EntityConfig {
|
||||
pub loot: LootSpec<String>,
|
||||
|
||||
/// Loadout & Inventory
|
||||
/// Variants:
|
||||
/// `FromBody` - will get default equipement for entity body.
|
||||
/// `Asset` - will get loadout from loadout asset.
|
||||
/// `Hands` - naked character with weapons.
|
||||
/// `Extended` - combination of Asset and Hands with ability to specify
|
||||
/// inventory of entity.
|
||||
pub loadout: LoadoutKind,
|
||||
/// Check docs for `InventorySpec` struct in this file.
|
||||
pub inventory: InventorySpec,
|
||||
|
||||
/// Meta Info for optional fields
|
||||
/// Possible fields:
|
||||
@ -252,7 +260,7 @@ impl EntityInfo {
|
||||
name,
|
||||
body,
|
||||
alignment,
|
||||
loadout,
|
||||
inventory,
|
||||
loot,
|
||||
meta,
|
||||
} = config;
|
||||
@ -290,7 +298,7 @@ impl EntityInfo {
|
||||
self = self.with_loot_drop(loot);
|
||||
|
||||
// NOTE: set loadout after body, as it's used with default equipement
|
||||
self = self.with_loadout(loadout, config_asset, loadout_rng);
|
||||
self = self.with_inventory(inventory, config_asset, loadout_rng);
|
||||
|
||||
for field in meta {
|
||||
match field {
|
||||
@ -303,42 +311,45 @@ impl EntityInfo {
|
||||
self
|
||||
}
|
||||
|
||||
/// Return EntityInfo with LoadoutBuilder overwritten
|
||||
/// Return EntityInfo with LoadoutBuilder and items overwritten
|
||||
// NOTE: helper function, think twice before exposing it
|
||||
#[must_use]
|
||||
fn with_loadout<R>(
|
||||
fn with_inventory<R>(
|
||||
mut self,
|
||||
loadout: LoadoutKind,
|
||||
inventory: InventorySpec,
|
||||
config_asset: Option<&str>,
|
||||
rng: &mut R,
|
||||
) -> Self
|
||||
where
|
||||
R: rand::Rng,
|
||||
{
|
||||
let config_asset = config_asset.unwrap_or("???");
|
||||
let InventorySpec { loadout, items } = inventory;
|
||||
|
||||
// FIXME: this shouldn't always overwrite
|
||||
// inventory. Think about this when we get to
|
||||
// entity config inheritance.
|
||||
self.inventory = items
|
||||
.into_iter()
|
||||
.map(|(num, i)| (num, Item::new_from_asset_expect(&i)))
|
||||
.collect();
|
||||
|
||||
match loadout {
|
||||
LoadoutKind::FromBody => {
|
||||
LoadoutKindNew::FromBody => {
|
||||
self = self.with_default_equip();
|
||||
},
|
||||
LoadoutKind::Asset(loadout) => {
|
||||
self = self.with_loadout_asset(loadout, rng);
|
||||
LoadoutKindNew::Asset(loadout) => {
|
||||
let loadout = LoadoutBuilder::from_asset(&loadout, rng).unwrap_or_else(|e| {
|
||||
panic!("failed to load loadout for {config_asset}: {e:?}");
|
||||
});
|
||||
self.loadout = loadout;
|
||||
},
|
||||
LoadoutKind::Hands(hands) => {
|
||||
self = self.with_hands(hands, config_asset, rng);
|
||||
},
|
||||
LoadoutKind::Extended {
|
||||
hands,
|
||||
base_asset,
|
||||
inventory,
|
||||
} => {
|
||||
self = self.with_loadout_asset(base_asset, rng);
|
||||
self = self.with_hands(hands, config_asset, rng);
|
||||
// FIXME: this shouldn't always overwrite
|
||||
// inventory. Think about this when we get to
|
||||
// entity config inheritance.
|
||||
self.inventory = inventory
|
||||
.into_iter()
|
||||
.map(|(num, i)| (num, Item::new_from_asset_expect(&i)))
|
||||
.collect();
|
||||
LoadoutKindNew::Inline(loadout_spec) => {
|
||||
let loadout =
|
||||
LoadoutBuilder::from_loadout_spec(loadout_spec, rng).unwrap_or_else(|e| {
|
||||
panic!("failed to load loadout for {config_asset}: {e:?}");
|
||||
});
|
||||
self.loadout = loadout;
|
||||
},
|
||||
}
|
||||
|
||||
@ -355,77 +366,6 @@ impl EntityInfo {
|
||||
self
|
||||
}
|
||||
|
||||
/// Return EntityInfo with LoadoutBuilder overwritten
|
||||
// NOTE: helper function, think twice before exposing it
|
||||
#[must_use]
|
||||
fn with_loadout_asset<R>(mut self, loadout: LoadoutAsset, rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::Rng,
|
||||
{
|
||||
match loadout {
|
||||
LoadoutAsset::Loadout(asset) => {
|
||||
let loadout = LoadoutBuilder::from_asset_expect(&asset, Some(rng));
|
||||
self.loadout = loadout;
|
||||
},
|
||||
LoadoutAsset::Choice(assets) => {
|
||||
// TODO:
|
||||
// choose_weighted allocates WeightedIndex,
|
||||
// possible optimizaiton with using Lottery
|
||||
let (_p, asset) = assets
|
||||
.choose_weighted(rng, |(p, _asset)| *p)
|
||||
.expect("rng error");
|
||||
|
||||
let loadout = LoadoutBuilder::from_asset_expect(asset, Some(rng));
|
||||
self.loadout = loadout;
|
||||
},
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Return EntityInfo with weapons applied to LoadoutBuilder
|
||||
// NOTE: helper function, think twice before exposing it
|
||||
#[must_use]
|
||||
fn with_hands<R>(mut self, hands: Hands, config_asset: Option<&str>, rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::Rng,
|
||||
{
|
||||
match hands {
|
||||
Hands::TwoHanded(main_tool) => {
|
||||
let tool = main_tool.try_to_item(config_asset.unwrap_or("??"), rng);
|
||||
if let Some(tool) = tool {
|
||||
self.loadout = self.loadout.active_mainhand(Some(tool));
|
||||
}
|
||||
},
|
||||
Hands::Paired(tool) => {
|
||||
//FIXME: very stupid code, which just tries same item two times
|
||||
//figure out reasonable way to clone item
|
||||
let main_tool = tool.try_to_item(config_asset.unwrap_or("??"), rng);
|
||||
let second_tool = tool.try_to_item(config_asset.unwrap_or("??"), rng);
|
||||
|
||||
if let Some(main_tool) = main_tool {
|
||||
self.loadout = self.loadout.active_mainhand(Some(main_tool));
|
||||
}
|
||||
if let Some(second_tool) = second_tool {
|
||||
self.loadout = self.loadout.active_offhand(Some(second_tool));
|
||||
}
|
||||
},
|
||||
Hands::Mix { mainhand, offhand } => {
|
||||
let main_tool = mainhand.try_to_item(config_asset.unwrap_or("??"), rng);
|
||||
let second_tool = offhand.try_to_item(config_asset.unwrap_or("??"), rng);
|
||||
|
||||
if let Some(main_tool) = main_tool {
|
||||
self.loadout = self.loadout.active_mainhand(Some(main_tool));
|
||||
}
|
||||
if let Some(second_tool) = second_tool {
|
||||
self.loadout = self.loadout.active_offhand(Some(second_tool));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn do_if(mut self, cond: bool, f: impl FnOnce(Self) -> Self) -> Self {
|
||||
if cond {
|
||||
@ -595,7 +535,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn validate_loadout(loadout: LoadoutKind, body: &BodyBuilder, config_asset: &str) {
|
||||
fn validate_inventory(inventory: InventorySpec, body: &BodyBuilder, config_asset: &str) {
|
||||
/*
|
||||
* FIXME: actually impelement tests BEFORE merge!!!!
|
||||
match loadout {
|
||||
LoadoutKind::FromBody => {
|
||||
if body.clone() == BodyBuilder::Uninit {
|
||||
@ -633,8 +575,10 @@ mod tests {
|
||||
}
|
||||
},
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
fn validate_loadout_asset(loadout: LoadoutAsset, config_asset: &str) {
|
||||
match loadout {
|
||||
@ -671,6 +615,7 @@ mod tests {
|
||||
},
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
fn validate_name(name: NameKind, body: BodyBuilder, config_asset: &str) {
|
||||
@ -717,21 +662,9 @@ mod tests {
|
||||
let entity_configs =
|
||||
try_all_entity_configs().expect("Failed to access entity configs directory");
|
||||
for config_asset in entity_configs {
|
||||
// print asset name so we don't need to find errors everywhere
|
||||
// it'll be ignored by default so you'll see it only in case of errors
|
||||
//
|
||||
// TODO:
|
||||
// 1) Add try_validate() for loadout_builder::ItemSpec which will return
|
||||
// Result and we will happily panic in validate_hands() with name of
|
||||
// config_asset.
|
||||
// 2) Add try_from_asset() for LoadoutBuilder and
|
||||
// SkillSet builder which will return Result and we will happily
|
||||
// panic in validate_meta() with the name of config_asset
|
||||
println!("{}:", &config_asset);
|
||||
|
||||
let EntityConfig {
|
||||
body,
|
||||
loadout,
|
||||
inventory,
|
||||
name,
|
||||
loot,
|
||||
meta,
|
||||
@ -740,7 +673,7 @@ mod tests {
|
||||
|
||||
validate_body(&body, &config_asset);
|
||||
// body dependent stuff
|
||||
validate_loadout(loadout, &body, &config_asset);
|
||||
validate_inventory(inventory, &body, &config_asset);
|
||||
validate_name(name, body, &config_asset);
|
||||
// misc
|
||||
validate_loot(loot, &config_asset);
|
||||
|
Loading…
Reference in New Issue
Block a user