diff --git a/assets/common/entity/village/dummy.ron b/assets/common/entity/village/dummy.ron index 96e7b9d467..c62a515143 100644 --- a/assets/common/entity/village/dummy.ron +++ b/assets/common/entity/village/dummy.ron @@ -3,7 +3,7 @@ EntityConfig ( body: Exact(Object(TrainingDummy)), alignment: Alignment(Passive), - loot: Uninit, + loot: None, hands: Uninit, diff --git a/common/src/comp/inventory/item/mod.rs b/common/src/comp/inventory/item/mod.rs index a432977fcd..b262a64420 100644 --- a/common/src/comp/inventory/item/mod.rs +++ b/common/src/comp/inventory/item/mod.rs @@ -13,6 +13,7 @@ use crate::{ CharacterAbility, }, effect::Effect, + lottery::LootSpec, recipe::RecipeInput, terrain::Block, }; @@ -862,10 +863,17 @@ impl Component for Item { type Storage = DerefFlaggedStorage>; } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct ItemDrop(pub Item); +// #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +// pub struct ItemDrop>(pub LootSpec); -impl Component for ItemDrop { +// impl> Component for ItemDrop { +// type Storage = IdvStorage; +// } + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ItemDrop>(pub LootSpec); + +impl Component for ItemDrop { type Storage = IdvStorage; } diff --git a/common/src/event.rs b/common/src/event.rs index d3a22423d8..e271d4000d 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -4,9 +4,9 @@ use crate::{ self, agent::Sound, invite::{InviteKind, InviteResponse}, - item::Item, DisconnectReason, Ori, Pos, }, + lottery::LootSpec, outcome::Outcome, rtsim::RtSimEntity, terrain::SpriteKind, @@ -134,7 +134,7 @@ pub enum ServerEvent { alignment: comp::Alignment, scale: comp::Scale, anchor: Option, - drop_item: Option, + drop_item: Option>, rtsim_entity: Option, projectile: Option, }, diff --git a/common/src/generation.rs b/common/src/generation.rs index 837b8a2d83..b4686a510f 100644 --- a/common/src/generation.rs +++ b/common/src/generation.rs @@ -5,7 +5,7 @@ use crate::{ inventory::loadout_builder::{ItemSpec, LoadoutBuilder}, Alignment, Body, Item, }, - lottery::{LootSpec, Lottery}, + lottery::LootSpec, npc::{self, NPC_NAMES}, trade, trade::SiteInformation, @@ -37,17 +37,6 @@ impl Default for AlignmentMark { fn default() -> Self { Self::Alignment(Alignment::Wild) } } -#[derive(Debug, Deserialize, Clone)] -enum LootKind { - Item(String), - LootTable(String), - Uninit, -} - -impl Default for LootKind { - fn default() -> Self { Self::Uninit } -} - #[derive(Debug, Deserialize, Clone)] enum Hands { TwoHanded(ItemSpec), @@ -115,10 +104,8 @@ pub struct EntityConfig { alignment: AlignmentMark, /// Loot - /// Can be Item (with asset_specifier for item) - /// or LootTable (with asset_specifier for loot table) - /// or Uninit (means it should be specified something in the code) - loot: LootKind, + /// See LootSpec in lottery + loot: LootSpec, /// Hands: /// - TwoHanded(ItemSpec) for one 2h or 1h weapon, @@ -173,7 +160,7 @@ pub struct EntityInfo { pub scale: f32, // TODO: Properly give NPCs skills pub health_scaling: Option, - pub loot_drop: Option, + pub loot_drop: Option>, pub loadout_asset: Option, pub make_loadout: Option) -> LoadoutBuilder>, pub skillset_asset: Option, @@ -253,21 +240,7 @@ impl EntityInfo { self = self.with_alignment(alignment); } - match loot { - LootKind::Item(asset) => { - if let Ok(item) = Item::new_from_asset(&asset) { - self = self.with_loot_drop(item); - } - }, - LootKind::LootTable(asset) => { - if let Ok(table) = Lottery::>::load(&asset) { - if let Some(drop) = table.read().choose().to_item() { - self = self.with_loot_drop(drop); - } - } - }, - LootKind::Uninit => {}, - } + self = self.with_loot_drop(loot); let rng = &mut rand::thread_rng(); match hands { @@ -363,7 +336,7 @@ impl EntityInfo { self } - pub fn with_loot_drop(mut self, loot_drop: Item) -> Self { + pub fn with_loot_drop(mut self, loot_drop: LootSpec) -> Self { self.loot_drop = Some(loot_drop); self } @@ -469,6 +442,7 @@ mod tests { } } + #[cfg(test)] fn validate_hands(hands: Hands, _config_asset: &str) { match hands { Hands::TwoHanded(main_tool) => { @@ -486,6 +460,7 @@ mod tests { } } + #[cfg(test)] fn validate_body_and_name(body: BodyBuilder, name: NameKind, config_asset: &str) { match body { BodyBuilder::RandomWith(string) => { @@ -511,30 +486,13 @@ mod tests { } } - fn validate_loot(loot: LootKind, config_asset: &str) { - match loot { - LootKind::Item(asset) => { - if let Err(e) = Item::new_from_asset(&asset) { - panic!( - "Unable to parse loot item ({}) in {}. Err: {:?}", - asset, config_asset, e - ); - } - }, - LootKind::LootTable(asset) => { - // we need to just load it check if it exists, - // because all loot tables are tested in Lottery module - if let Err(e) = Lottery::>::load(&asset) { - panic!( - "Unable to parse loot table ({}) in {}. Err: {:?}", - asset, config_asset, e - ); - } - }, - LootKind::Uninit => {}, - } + #[cfg(test)] + fn validate_loot(loot: LootSpec, _config_asset: &str) { + use crate::lottery; + lottery::tests::validate_loot_spec(&loot); } + #[cfg(test)] fn validate_meta(meta: Vec, config_asset: &str) { let mut meta_counter = HashMap::new(); for field in meta { diff --git a/common/src/lottery.rs b/common/src/lottery.rs index 6e5d103641..383d1c3b30 100644 --- a/common/src/lottery.rs +++ b/common/src/lottery.rs @@ -114,44 +114,52 @@ impl> LootSpec { } } +impl Default for LootSpec { + fn default() -> Self { Self::None } +} + #[cfg(test)] -mod tests { +pub mod tests { use super::*; use crate::{assets, comp::Item}; + #[cfg(test)] + pub fn validate_loot_spec(item: &LootSpec) { + match item { + LootSpec::Item(item) => { + Item::new_from_asset_expect(item); + }, + LootSpec::ItemQuantity(item, lower, upper) => { + assert!( + *lower > 0, + "Lower quantity must be more than 0. It is {}.", + lower + ); + assert!( + upper >= lower, + "Upper quantity must be at least the value of lower quantity. Upper value: \ + {}, low value: {}.", + upper, + lower + ); + Item::new_from_asset_expect(item); + }, + LootSpec::LootTable(loot_table) => { + let loot_table = Lottery::>::load_expect_cloned(loot_table); + validate_table_contents(loot_table); + }, + LootSpec::None => {}, + } + } + + fn validate_table_contents(table: Lottery>) { + for (_, item) in table.iter() { + validate_loot_spec(item); + } + } + #[test] fn test_loot_tables() { - fn validate_table_contents(table: Lottery>) { - for (_, item) in table.iter() { - match item { - LootSpec::Item(item) => { - Item::new_from_asset_expect(item); - }, - LootSpec::ItemQuantity(item, lower, upper) => { - assert!( - *lower > 0, - "Lower quantity must be more than 0. It is {}.", - lower - ); - assert!( - upper >= lower, - "Upper quantity must be at least the value of lower quantity. Upper \ - value: {}, low value: {}.", - upper, - lower - ); - Item::new_from_asset_expect(item); - }, - LootSpec::LootTable(loot_table) => { - let loot_table = - Lottery::>::load_expect_cloned(loot_table); - validate_table_contents(loot_table); - }, - LootSpec::None => {}, - } - } - } - let loot_tables = assets::read_expect_dir::>>("common.loot_tables", true); for loot_table in loot_tables { diff --git a/common/state/src/state.rs b/common/state/src/state.rs index 599d6013d4..141fc82d1b 100644 --- a/common/state/src/state.rs +++ b/common/state/src/state.rs @@ -189,7 +189,7 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); + ecs.register::>(); ecs.register::(); ecs.register::(); ecs.register::(); diff --git a/server/src/events/entity_creation.rs b/server/src/events/entity_creation.rs index 43294d0dff..16243b71c8 100644 --- a/server/src/events/entity_creation.rs +++ b/server/src/events/entity_creation.rs @@ -8,10 +8,11 @@ use common::{ beam, buff::{BuffCategory, BuffData, BuffKind, BuffSource}, inventory::loadout::Loadout, - shockwave, Agent, Alignment, Anchor, Body, Health, Inventory, Item, ItemDrop, LightEmitter, + shockwave, Agent, Alignment, Anchor, Body, Health, Inventory, ItemDrop, LightEmitter, Object, Ori, PidController, Poise, Pos, Projectile, Scale, SkillSet, Stats, Vel, WaypointArea, }, + lottery::LootSpec, outcome::Outcome, rtsim::RtSimEntity, uid::Uid, @@ -62,7 +63,7 @@ pub fn handle_create_npc( agent: impl Into>, alignment: Alignment, scale: Scale, - drop_item: Option, + drop_item: Option>, home_chunk: Option, rtsim_entity: Option, projectile: Option, diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index c332c5558c..39f248b463 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -354,7 +354,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt // Decide for a loot drop before turning into a lootbag let old_body = state.ecs().write_storage::().remove(entity); - let lottery = || { + let _ = || { Lottery::>::load_expect(match old_body { Some(common::comp::Body::Humanoid(_)) => "common.loot_tables.creature.humanoid", Some(common::comp::Body::QuadrupedSmall(quadruped_small)) => { @@ -503,13 +503,15 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt }) }; - if let Some(item) = { - let mut item_drops = state.ecs().write_storage::(); - item_drops.remove(entity).map_or_else( - || lottery().read().choose().to_item(), - |item_drop| Some(item_drop.0), + let loot_spec = { + let mut item_drop = state.ecs().write_storage::>(); + item_drop.remove(entity).map_or_else( + || LootSpec::LootTable("common.loot_tables.fallback".to_string()), + |item| item.0, ) - } { + }; + + if let Some(item) = loot_spec.to_item() { let pos = state.ecs().read_storage::().get(entity).cloned(); let vel = state.ecs().read_storage::().get(entity).cloned(); if let Some(pos) = pos { diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index 850a48001a..90a2534eeb 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -13,6 +13,7 @@ use common::{ comp::{self, agent, bird_medium, BehaviorCapability, ForceUpdate, Pos, Waypoint}, event::{EventBus, ServerEvent}, generation::EntityInfo, + lottery::LootSpec, resources::Time, terrain::TerrainGrid, LoadoutBuilder, SkillSetBuilder, @@ -357,7 +358,7 @@ pub enum NpcData { body: comp::Body, alignment: comp::Alignment, scale: comp::Scale, - drop_item: Option, + drop_item: Option>, }, Waypoint(Vec3), }