Merge branch 'unvariant/render_item_drops' into 'master'

Render item drops instead of placeholder textures

See merge request veloren/veloren!3175
This commit is contained in:
Imbris 2022-02-14 02:09:45 +00:00
commit 46c35f3376
30 changed files with 3585 additions and 126 deletions

View File

@ -82,6 +82,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Friendly creatures will now defend each other
- Creatures will now defend their pets
- [WorldGen] Change path colors
- Render item drops instead of placeholder textures
### Removed

View File

@ -1013,6 +1013,13 @@
),
species: ()
),
item_drop: (
body: (
keyword: "item_drop",
names_0: []
),
species: ()
),
ship: (
body: (
keyword: "ship",

File diff suppressed because it is too large Load Diff

View File

@ -263,6 +263,7 @@ impl<'a> From<&'a Body> for Psyche {
Body::FishMedium(_) => 0.75,
Body::BipedLarge(_) => 0.0,
Body::Object(_) => 0.0,
Body::ItemDrop(_) => 0.0,
Body::Golem(_) => 0.0,
Body::Theropod(_) => 0.0,
Body::Ship(_) => 0.0,

View File

@ -8,6 +8,7 @@ pub mod fish_medium;
pub mod fish_small;
pub mod golem;
pub mod humanoid;
pub mod item_drop;
pub mod object;
pub mod quadruped_low;
pub mod quadruped_medium;
@ -50,6 +51,7 @@ make_case_elim!(
QuadrupedLow(body: quadruped_low::Body) = 13,
Ship(body: ship::Body) = 14,
Arthropod(body: arthropod::Body) = 15,
ItemDrop(body: item_drop::Body) = 16,
}
);
@ -83,6 +85,7 @@ pub struct AllBodies<BodyMeta, SpeciesMeta> {
pub biped_large: BodyData<BodyMeta, biped_large::AllSpecies<SpeciesMeta>>,
pub biped_small: BodyData<BodyMeta, biped_small::AllSpecies<SpeciesMeta>>,
pub object: BodyData<BodyMeta, ()>,
pub item_drop: BodyData<BodyMeta, ()>,
pub golem: BodyData<BodyMeta, golem::AllSpecies<SpeciesMeta>>,
pub theropod: BodyData<BodyMeta, theropod::AllSpecies<SpeciesMeta>>,
pub quadruped_low: BodyData<BodyMeta, quadruped_low::AllSpecies<SpeciesMeta>>,
@ -133,6 +136,7 @@ impl<'a, BodyMeta, SpeciesMeta> core::ops::Index<&'a Body> for AllBodies<BodyMet
Body::BipedLarge(_) => &self.biped_large.body,
Body::BipedSmall(_) => &self.biped_small.body,
Body::Object(_) => &self.object.body,
Body::ItemDrop(_) => &self.item_drop.body,
Body::Golem(_) => &self.golem.body,
Body::Theropod(_) => &self.theropod.body,
Body::QuadrupedLow(_) => &self.quadruped_low.body,
@ -196,6 +200,7 @@ impl Body {
_ => false,
},
Body::Object(_) => false,
Body::ItemDrop(_) => false,
Body::Golem(b1) => match other {
Body::Golem(b2) => b1.species == b2.species,
_ => false,
@ -235,6 +240,7 @@ impl Body {
Body::Humanoid(_) => HUMAN_DENSITY,
Body::Ship(ship) => ship.density().0,
Body::Object(object) => object.density().0,
Body::ItemDrop(item_drop) => item_drop.density().0,
_ => HUMAN_DENSITY,
};
Density(d)
@ -287,6 +293,7 @@ impl Body {
65.0 * humanoid.height() / 1.75f32
},
Body::Object(obj) => obj.mass().0,
Body::ItemDrop(item_drop) => item_drop.mass().0,
Body::QuadrupedLow(body) => match body.species {
quadruped_low::Species::Alligator => 360.0, // ~✅
quadruped_low::Species::Asp => 300.0,
@ -411,6 +418,7 @@ impl Body {
Vec3::new(height / 1.3, 1.75 / 2.0, height)
},
Body::Object(object) => object.dimensions(),
Body::ItemDrop(item_drop) => item_drop.dimensions(),
Body::QuadrupedMedium(body) => match body.species {
quadruped_medium::Species::Barghest => Vec3::new(2.0, 4.4, 2.7),
quadruped_medium::Species::Bear => Vec3::new(2.0, 3.8, 3.0),
@ -696,6 +704,7 @@ impl Body {
object::Body::SeaLantern => 100,
_ => 1000,
},
Body::ItemDrop(_) => 1000,
Body::Golem(golem) => match golem.species {
golem::Species::ClayGolem => 450,
_ => 1000,

View File

@ -0,0 +1,150 @@
use crate::{
comp::{
item::{
armor::ArmorKind,
tool::{Tool, ToolKind},
Item, ItemKind, Utility,
},
Density, Mass, Ori,
},
consts::WATER_DENSITY,
make_case_elim,
util::Dir,
};
use rand::prelude::*;
use serde::{Deserialize, Serialize};
use std::f32::consts::PI;
use vek::Vec3;
make_case_elim!(
armor,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum ItemDropArmorKind {
Shoulder = 0,
Chest = 1,
Belt = 2,
Hand = 3,
Pants = 4,
Foot = 5,
Back = 6,
Ring = 7,
Neck = 8,
Head = 9,
Tabard = 10,
Bag = 11,
}
);
make_case_elim!(
body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Body {
Tool(tool: ToolKind) = 0,
ModularComponent = 1,
Lantern = 2,
Glider = 3,
Armor(armor: ItemDropArmorKind) = 4,
Utility = 5,
Consumable = 6,
Throwable = 7,
Ingredient = 8,
Coins = 9,
CoinPouch = 10,
Empty = 11,
}
);
impl From<Body> for super::Body {
fn from(body: Body) -> Self { super::Body::ItemDrop(body) }
}
impl From<&Item> for Body {
fn from(item: &Item) -> Self {
match item.kind() {
ItemKind::Tool(Tool { kind, .. }) => Body::Tool(*kind),
ItemKind::ModularComponent(_) => Body::ModularComponent,
ItemKind::Lantern(_) => Body::Lantern,
ItemKind::Glider(_) => Body::Glider,
ItemKind::Armor(armor) => match armor.kind {
ArmorKind::Shoulder(_) => Body::Armor(ItemDropArmorKind::Shoulder),
ArmorKind::Chest(_) => Body::Armor(ItemDropArmorKind::Chest),
ArmorKind::Belt(_) => Body::Armor(ItemDropArmorKind::Belt),
ArmorKind::Hand(_) => Body::Armor(ItemDropArmorKind::Hand),
ArmorKind::Pants(_) => Body::Armor(ItemDropArmorKind::Pants),
ArmorKind::Foot(_) => Body::Armor(ItemDropArmorKind::Foot),
ArmorKind::Back(_) => Body::Armor(ItemDropArmorKind::Back),
ArmorKind::Ring(_) => Body::Armor(ItemDropArmorKind::Ring),
ArmorKind::Neck(_) => Body::Armor(ItemDropArmorKind::Neck),
ArmorKind::Head(_) => Body::Armor(ItemDropArmorKind::Head),
ArmorKind::Tabard(_) => Body::Armor(ItemDropArmorKind::Tabard),
ArmorKind::Bag(_) => Body::Armor(ItemDropArmorKind::Bag),
},
ItemKind::Utility { kind, .. } => match kind {
Utility::Coins => {
if item.amount() > 100 {
Body::CoinPouch
} else {
Body::Coins
}
},
_ => Body::Utility,
},
ItemKind::Consumable { .. } => Body::Consumable,
ItemKind::Throwable { .. } => Body::Throwable,
ItemKind::Ingredient { .. } => Body::Ingredient,
_ => Body::Empty,
}
}
}
impl Body {
pub fn to_string(self) -> &'static str {
match self {
Body::Tool(_) => "tool",
Body::ModularComponent => "modular_component",
Body::Lantern => "lantern",
Body::Glider => "glider",
Body::Armor(_) => "armor",
Body::Utility => "utility",
Body::Consumable => "consumable",
Body::Throwable => "throwable",
Body::Ingredient => "ingredient",
Body::Coins => "coins",
Body::CoinPouch => "coin_pouch",
Body::Empty => "empty",
}
}
pub fn density(&self) -> Density { Density(1.1 * WATER_DENSITY) }
pub fn mass(&self) -> Mass { Mass(2.0) }
pub fn dimensions(&self) -> Vec3<f32> { Vec3::new(0.0, 0.1, 0.0) }
pub fn orientation(&self, rng: &mut impl Rng) -> Ori {
let random = rng.gen_range(-1.0..1.0f32);
let default = Ori::default();
match self {
Body::Tool(_) => default
.pitched_down(PI / 2.0)
.yawed_left(PI / 2.0)
.pitched_towards(
Dir::from_unnormalized(Vec3::new(
random,
rng.gen_range(-1.0..1.0f32),
rng.gen_range(-1.0..1.0f32),
))
.unwrap_or_default(),
),
Body::Armor(kind) => match kind {
ItemDropArmorKind::Neck | ItemDropArmorKind::Back | ItemDropArmorKind::Tabard => {
default.pitched_down(PI / -2.0)
},
_ => default.yawed_left(random),
},
_ => default.yawed_left(random),
}
}
}

View File

@ -306,6 +306,12 @@ impl Body {
},
},
Body::ItemDrop(_) => {
let dim = self.dimensions();
const CD: f32 = 2.0;
CD * (PI / 6.0 * dim.x * dim.y * dim.z).powf(2.0 / 3.0)
},
Body::Ship(_) => {
// Airships tend to use the square of the cube root of its volume for
// reference area

View File

@ -0,0 +1,51 @@
use crate::{
assets::AssetExt,
comp::inventory::item::{
armor::{Armor, ArmorKind},
Glider, ItemDef, ItemDesc, ItemKind, Lantern, Throwable, Utility,
},
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Clone, Debug, Serialize, Deserialize, Hash, Eq, PartialEq)]
pub enum ItemKey {
Tool(String),
ModularComponent(String),
Lantern(String),
Glider(String),
Armor(ArmorKind),
Utility(Utility),
Consumable(String),
Throwable(Throwable),
Ingredient(String),
TagExamples(Vec<ItemKey>),
Empty,
}
impl<T: ItemDesc> From<&T> for ItemKey {
fn from(item_desc: &T) -> Self {
let item_kind = item_desc.kind();
let item_definition_id = item_desc.item_definition_id();
match item_kind {
ItemKind::Tool(_) => ItemKey::Tool(item_definition_id.to_owned()),
ItemKind::ModularComponent(_) => {
ItemKey::ModularComponent(item_definition_id.to_owned())
},
ItemKind::Lantern(Lantern { kind, .. }) => ItemKey::Lantern(kind.clone()),
ItemKind::Glider(Glider { kind, .. }) => ItemKey::Glider(kind.clone()),
ItemKind::Armor(Armor { kind, .. }) => ItemKey::Armor(kind.clone()),
ItemKind::Utility { kind, .. } => ItemKey::Utility(*kind),
ItemKind::Consumable { .. } => ItemKey::Consumable(item_definition_id.to_owned()),
ItemKind::Throwable { kind, .. } => ItemKey::Throwable(*kind),
ItemKind::Ingredient { kind, .. } => ItemKey::Ingredient(kind.clone()),
ItemKind::TagExamples { item_ids } => ItemKey::TagExamples(
item_ids
.iter()
.map(|id| ItemKey::from(&*Arc::<ItemDef>::load_expect_cloned(id)))
.collect(),
),
}
}
}

View File

@ -1,4 +1,5 @@
pub mod armor;
pub mod item_key;
pub mod modular;
pub mod tool;

View File

@ -60,8 +60,8 @@ pub use self::{
beam::{Beam, BeamSegment},
body::{
arthropod, biped_large, biped_small, bird_large, bird_medium, dragon, fish_medium,
fish_small, golem, humanoid, object, quadruped_low, quadruped_medium, quadruped_small,
ship, theropod, AllBodies, Body, BodyData,
fish_small, golem, humanoid, item_drop, object, quadruped_low, quadruped_medium,
quadruped_small, ship, theropod, AllBodies, Body, BodyData,
},
buff::{
Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs,
@ -83,6 +83,7 @@ pub use self::{
inventory::{
item::{
self,
item_key::ItemKey,
tool::{self, AbilityItem},
Item, ItemConfig, ItemDrop,
},

View File

@ -109,6 +109,7 @@ impl Body {
_ => 80.0,
},
Body::Object(_) => 0.0,
Body::ItemDrop(_) => 0.0,
Body::Golem(_) => 60.0,
Body::Theropod(_) => 135.0,
Body::QuadrupedLow(quadruped_low) => match quadruped_low.species {
@ -183,6 +184,7 @@ impl Body {
Body::BipedLarge(_) => 2.7,
Body::BipedSmall(_) => 3.5,
Body::Object(_) => 2.0,
Body::ItemDrop(_) => 2.0,
Body::Golem(_) => 2.0,
Body::Theropod(theropod) => match theropod.species {
theropod::Species::Archaeos => 2.3,
@ -208,6 +210,7 @@ impl Body {
pub fn swim_thrust(&self) -> Option<f32> {
match self {
Body::Object(_) => None,
Body::ItemDrop(_) => None,
Body::BipedLarge(_) | Body::Golem(_) => Some(200.0 * self.mass().0),
Body::BipedSmall(_) => Some(100.0 * self.mass().0),
Body::BirdMedium(_) => Some(50.0 * self.mass().0),
@ -247,7 +250,7 @@ impl Body {
/// Returns jump impulse if the body type can jump, otherwise None
pub fn jump_impulse(&self) -> Option<f32> {
match self {
Body::Object(_) | Body::Ship(_) => None,
Body::Object(_) | Body::Ship(_) | Body::ItemDrop(_) => None,
Body::BipedLarge(_) | Body::Dragon(_) | Body::Golem(_) | Body::QuadrupedLow(_) => {
Some(0.1 * self.mass().0)
},

View File

@ -476,7 +476,7 @@ fn handle_drop_all(
server
.state
.create_object(Default::default(), comp::object::Body::Pouch)
.create_item_drop(Default::default(), &item)
.with(comp::Pos(Vec3::new(
pos.0.x + rng.gen_range(5.0..10.0),
pos.0.y + rng.gen_range(5.0..10.0),

View File

@ -17,8 +17,8 @@ use common::{
self, aura, buff,
chat::{KillSource, KillType},
inventory::item::MaterialStatManifest,
object, Alignment, Auras, Body, CharacterState, Energy, Group, Health, HealthChange,
Inventory, Player, Poise, Pos, SkillSet, Stats,
Alignment, Auras, Body, CharacterState, Energy, Group, Health, HealthChange, Inventory,
Player, Poise, Pos, SkillSet, Stats,
},
event::{EventBus, ServerEvent},
outcome::Outcome,
@ -427,7 +427,6 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
// and if it is not owned by another entity (not a pet)
// Decide for a loot drop before turning into a lootbag
let old_body = state.ecs().write_storage::<Body>().remove(entity);
let item = {
let mut item_drop = state.ecs().write_storage::<comp::ItemDrop>();
@ -442,23 +441,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
// render the items on the ground, rather than changing the texture depending on
// the body type
let _ = state
.create_object(comp::Pos(pos.0 + Vec3::unit_z() * 0.25), match old_body {
Some(common::comp::Body::Humanoid(_)) => object::Body::Pouch,
Some(common::comp::Body::BipedSmall(_))
| Some(common::comp::Body::BipedLarge(_)) => object::Body::Pouch,
Some(common::comp::Body::Golem(_)) => object::Body::Chest,
Some(common::comp::Body::QuadrupedSmall(_)) => object::Body::SmallMeat,
Some(common::comp::Body::FishMedium(_))
| Some(common::comp::Body::FishSmall(_)) => object::Body::FishMeat,
Some(common::comp::Body::QuadrupedMedium(_)) => object::Body::BeastMeat,
Some(common::comp::Body::QuadrupedLow(_)) => object::Body::ToughMeat,
Some(common::comp::Body::BirdLarge(_))
| Some(common::comp::Body::BirdMedium(_)) => object::Body::BirdMeat,
Some(common::comp::Body::Theropod(_)) => object::Body::BeastMeat,
Some(common::comp::Body::Dragon(_)) => object::Body::BeastMeat,
Some(common::comp::Body::Object(_)) => object::Body::Chest,
_ => object::Body::Pouch,
})
.create_item_drop(comp::Pos(pos.0 + Vec3::unit_z() * 0.25), &item)
.maybe_with(vel)
.with(item)
.build();

View File

@ -379,7 +379,7 @@ pub fn handle_mine_block(
}
}
state
.create_object(Default::default(), comp::object::Body::Pouch)
.create_item_drop(Default::default(), &item)
.with(comp::Pos(pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)))
.with(item)
.build();

View File

@ -247,14 +247,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
}
drop(inventories);
if let Some(item) = drop_item {
// TODO: Choose a body appropriate for the item
let body = match item.item_definition_id() {
"common.items.utility.coins" => comp::object::Body::Coins,
_ => comp::object::Body::Pouch,
};
state
.create_object(Default::default(), body)
.create_item_drop(Default::default(), &item)
.with(comp::Pos(
Vec3::new(pos.x as f32, pos.y as f32, pos.z as f32) + Vec3::unit_z(),
))
@ -712,12 +706,6 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.into_iter()
.filter(|(_, _, i)| !matches!(i.quality(), item::Quality::Debug))
{
// hack: special case coins for now
let body = match item.item_definition_id() {
"common.items.utility.coins" => comp::object::Body::Coins,
_ => comp::object::Body::Pouch,
};
// If item is a container check inside of it for Debug items and remove them
item.slots_mut().iter_mut().for_each(|x| {
if let Some(contained_item) = &x {
@ -728,7 +716,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
});
state
.create_object(Default::default(), body)
.create_item_drop(Default::default(), &item)
.with(comp::Pos(pos.0 + *ori.look_dir() + Vec3::unit_z()))
.with(item)
.with(comp::Vel(Vec3::zero()))

View File

@ -15,7 +15,7 @@ use common::{
comp::{
self,
skills::{GeneralSkill, Skill},
Group, Inventory, Poise,
Group, Inventory, Item, Poise,
},
effect::Effect,
link::{Link, LinkHandle},
@ -54,6 +54,7 @@ pub trait StateExt {
) -> EcsEntityBuilder;
/// Build a static object entity
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder;
fn create_item_drop(&mut self, pos: comp::Pos, item: &Item) -> EcsEntityBuilder;
fn create_ship<F: FnOnce(comp::ship::Body) -> comp::Collider>(
&mut self,
pos: comp::Pos,
@ -269,6 +270,20 @@ impl StateExt for State {
.with(body)
}
fn create_item_drop(&mut self, pos: comp::Pos, item: &Item) -> EcsEntityBuilder {
let item_drop = comp::item_drop::Body::from(item);
let body = comp::Body::ItemDrop(item_drop);
self.ecs_mut()
.create_entity_synced()
.with(pos)
.with(comp::Vel(Vec3::zero()))
.with(item_drop.orientation(&mut thread_rng()))
.with(item_drop.mass())
.with(item_drop.density())
.with(capsule(&body))
.with(body)
}
fn create_ship<F: FnOnce(comp::ship::Body) -> comp::Collider>(
&mut self,
pos: comp::Pos,

View File

@ -0,0 +1,29 @@
use super::{
super::{vek::*, Animation},
ItemDropSkeleton, SkeletonAttr,
};
pub struct IdleAnimation;
impl Animation for IdleAnimation {
type Dependency<'a> = f32;
type Skeleton = ItemDropSkeleton;
#[cfg(feature = "use-dyn-lib")]
const UPDATE_FN: &'static [u8] = b"item_drop_idle\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "item_drop_idle")]
fn update_skeleton_inner<'a>(
skeleton: &Self::Skeleton,
_: Self::Dependency<'a>,
_anim_time: f32,
_rate: &mut f32,
s_a: &SkeletonAttr,
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
next.bone0.position = Vec3::new(s_a.bone0.0, s_a.bone0.1, s_a.bone0.2);
next
}
}

View File

@ -0,0 +1,95 @@
pub mod idle;
// Reexports
pub use self::idle::IdleAnimation;
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton};
use common::comp::{self, item_drop::ItemDropArmorKind};
use core::convert::TryFrom;
pub type Body = comp::item_drop::Body;
skeleton_impls!(struct ItemDropSkeleton {
+ bone0,
});
impl Skeleton for ItemDropSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 1;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"item_drop_compute_mats\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "item_drop_compute_mats")]
fn compute_matrices_inner(
&self,
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
let scale_mat = Mat4::scaling_3d(1.0 / 11.0 * Self::scale(&body));
let bone0_mat = base_mat * scale_mat * Mat4::<f32>::from(self.bone0);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) =
[make_bone(bone0_mat)];
Offsets {
lantern: None,
mount_bone: Transform {
position: common::comp::Body::ItemDrop(body)
.mount_offset()
.into_tuple()
.into(),
..Default::default()
},
}
}
}
impl ItemDropSkeleton {
pub fn scale(body: &Body) -> f32 {
match body {
Body::Tool(_) => 0.8,
Body::Glider => 0.45,
Body::Coins => 0.5,
Body::Armor(kind) => match kind {
ItemDropArmorKind::Neck | ItemDropArmorKind::Ring => 0.5,
ItemDropArmorKind::Back => 0.7,
_ => 0.8,
},
_ => 1.0,
}
}
}
pub struct SkeletonAttr {
bone0: (f32, f32, f32),
}
impl<'a> std::convert::TryFrom<&'a comp::Body> for SkeletonAttr {
type Error = ();
fn try_from(body: &'a comp::Body) -> Result<Self, Self::Error> {
match body {
comp::Body::ItemDrop(body) => Ok(SkeletonAttr::from(body)),
_ => Err(()),
}
}
}
impl Default for SkeletonAttr {
fn default() -> Self {
Self {
bone0: (0.0, 0.0, 0.0),
}
}
}
impl<'a> From<&'a Body> for SkeletonAttr {
fn from(_body: &'a Body) -> Self {
Self {
bone0: (0.0, 0.0, 0.0),
}
}
}

View File

@ -58,6 +58,7 @@ pub mod fish_medium;
pub mod fish_small;
pub mod fixture;
pub mod golem;
pub mod item_drop;
pub mod object;
pub mod quadruped_low;
pub mod quadruped_medium;

View File

@ -728,6 +728,7 @@ fn body_species(body: &Body) -> String {
Body::BipedLarge(body) => format!("{:?}", body.species),
Body::BipedSmall(body) => format!("{:?}", body.species),
Body::Object(body) => format!("{:?}", body),
Body::ItemDrop(body) => format!("{:?}", body),
Body::Golem(body) => format!("{:?}", body.species),
Body::Theropod(body) => format!("{:?}", body.species),
Body::QuadrupedLow(body) => format!("{:?}", body.species),

View File

@ -1,7 +1,7 @@
use super::{
get_quality_col,
img_ids::{Imgs, ImgsRot},
item_imgs::{animate_by_pulse, ItemImgs, ItemKey::Tool},
item_imgs::{animate_by_pulse, ItemImgs},
Show, TEXT_COLOR, TEXT_DULL_RED_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
};
use crate::ui::{
@ -13,7 +13,8 @@ use common::{
assets::AssetExt,
comp::{
item::{
ItemDef, ItemDesc, ItemKind, ItemTag, MaterialStatManifest, Quality, TagExampleInfo,
item_key::ItemKey, ItemDef, ItemDesc, ItemKind, ItemTag, MaterialStatManifest, Quality,
TagExampleInfo,
},
Inventory,
},
@ -634,7 +635,7 @@ impl<'a> Widget for Crafting<'a> {
Button::image(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool(station_img_str.to_string())),
.img_ids_or_not_found_img(ItemKey::Tool(station_img_str.to_string())),
self.pulse,
))
.image_color(color::LIGHT_RED)
@ -815,7 +816,7 @@ impl<'a> Widget for Crafting<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool(station_img.to_string())),
.img_ids_or_not_found_img(ItemKey::Tool(station_img.to_string())),
self.pulse,
))
.w_h(25.0, 25.0)
@ -1056,7 +1057,7 @@ impl<'a> Widget for Crafting<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("DismantlingBench".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("DismantlingBench".to_string())),
self.pulse,
))
.wh([size; 2])

View File

@ -1,6 +1,6 @@
use super::{
img_ids::{Imgs, ImgsRot},
item_imgs::{animate_by_pulse, ItemImgs, ItemKey::Tool},
item_imgs::{animate_by_pulse, ItemImgs},
Position, PositionSpecifier, Show, BLACK, CRITICAL_HP_COLOR, HP_COLOR, TEXT_COLOR,
UI_HIGHLIGHT_0, UI_MAIN, XP_COLOR,
};
@ -34,6 +34,7 @@ use common::{
ability::{Ability, ActiveAbilities, AuxiliaryAbility, MAX_ABILITIES},
inventory::{
item::{
item_key::ItemKey,
tool::{MaterialStatManifest, ToolKind},
ItemKind,
},
@ -1358,7 +1359,7 @@ impl<'a> Diary<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_general_combat_left".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("example_general_combat_left".to_string())),
self.pulse,
))
.wh(ART_SIZE)
@ -1367,9 +1368,9 @@ impl<'a> Diary<'a> {
.set(state.ids.general_combat_render_0, ui);
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_general_combat_right".to_string())),
&self.item_imgs.img_ids_or_not_found_img(ItemKey::Tool(
"example_general_combat_right".to_string(),
)),
self.pulse,
))
.wh(ART_SIZE)
@ -1536,7 +1537,7 @@ impl<'a> Diary<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_sword".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("example_sword".to_string())),
self.pulse,
))
.wh(ART_SIZE)
@ -1707,7 +1708,7 @@ impl<'a> Diary<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_hammer".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("example_hammer".to_string())),
self.pulse,
))
.wh(ART_SIZE)
@ -1865,7 +1866,7 @@ impl<'a> Diary<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_axe".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("example_axe".to_string())),
self.pulse,
))
.wh(ART_SIZE)
@ -2023,7 +2024,7 @@ impl<'a> Diary<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_sceptre".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("example_sceptre".to_string())),
self.pulse,
))
.wh(ART_SIZE)
@ -2175,7 +2176,7 @@ impl<'a> Diary<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_bow".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("example_bow".to_string())),
self.pulse,
))
.wh(ART_SIZE)
@ -2333,7 +2334,7 @@ impl<'a> Diary<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_staff_fire".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("example_staff_fire".to_string())),
self.pulse,
))
.wh(ART_SIZE)
@ -2480,7 +2481,7 @@ impl<'a> Diary<'a> {
Image::new(animate_by_pulse(
&self
.item_imgs
.img_ids_or_not_found_img(Tool("example_pick".to_string())),
.img_ids_or_not_found_img(ItemKey::Tool("example_pick".to_string())),
self.pulse,
))
.wh(ART_SIZE)

View File

@ -1,5 +1,7 @@
use crate::hud::item_imgs::ItemKey;
use common::comp::{self, inventory::item::Item};
use common::comp::{
self,
inventory::item::{item_key::ItemKey, Item},
};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq)]

View File

@ -1,10 +1,7 @@
use crate::ui::{Graphic, SampleStrat, Transform, Ui};
use common::{
assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher},
comp::item::{
armor::{Armor, ArmorKind},
Glider, ItemDef, ItemDesc, ItemKind, Lantern, Throwable, Utility,
},
comp::item::item_key::ItemKey,
figure::Segment,
};
use conrod_core::image::Id;
@ -20,48 +17,6 @@ pub fn animate_by_pulse(ids: &[Id], pulse: f32) -> Id {
ids[animation_frame % ids.len()]
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ItemKey {
Tool(String),
ModularComponent(String),
Lantern(String),
Glider(String),
Armor(ArmorKind),
Utility(Utility),
Consumable(String),
Throwable(Throwable),
Ingredient(String),
TagExamples(Vec<ItemKey>),
Empty,
}
impl<T: ItemDesc> From<&T> for ItemKey {
fn from(item_desc: &T) -> Self {
let item_kind = item_desc.kind();
let item_definition_id = item_desc.item_definition_id();
match item_kind {
ItemKind::Tool(_) => ItemKey::Tool(item_definition_id.to_owned()),
ItemKind::ModularComponent(_) => {
ItemKey::ModularComponent(item_definition_id.to_owned())
},
ItemKind::Lantern(Lantern { kind, .. }) => ItemKey::Lantern(kind.clone()),
ItemKind::Glider(Glider { kind, .. }) => ItemKey::Glider(kind.clone()),
ItemKind::Armor(Armor { kind, .. }) => ItemKey::Armor(kind.clone()),
ItemKind::Utility { kind, .. } => ItemKey::Utility(*kind),
ItemKind::Consumable { .. } => ItemKey::Consumable(item_definition_id.to_owned()),
ItemKind::Throwable { kind, .. } => ItemKey::Throwable(*kind),
ItemKind::Ingredient { kind, .. } => ItemKey::Ingredient(kind.clone()),
ItemKind::TagExamples { item_ids } => ItemKey::TagExamples(
item_ids
.iter()
.map(|id| ItemKey::from(&*Arc::<ItemDef>::load_expect_cloned(id)))
.collect(),
),
}
}
}
#[derive(Serialize, Deserialize)]
enum ImageSpec {
Png(String),
@ -97,6 +52,7 @@ impl ImageSpec {
}
}
}
#[derive(Serialize, Deserialize)]
struct ItemImagesSpec(HashMap<ItemKey, ImageSpec>);
impl assets::Asset for ItemImagesSpec {

View File

@ -1,14 +1,14 @@
use super::{
hotbar::{self, Slot as HotbarSlot},
img_ids,
item_imgs::{ItemImgs, ItemKey},
item_imgs::ItemImgs,
util,
};
use crate::ui::slot::{self, SlotKey, SumSlot};
use common::comp::{
ability::{Ability, AbilityInput, AuxiliaryAbility},
slot::InvSlotId,
ActiveAbilities, Body, Energy, Inventory, SkillSet,
ActiveAbilities, Body, Energy, Inventory, ItemKey, SkillSet,
};
use conrod_core::{image, Color};
use specs::Entity as EcsEntity;

View File

@ -14,6 +14,7 @@ use common::{
},
item::{
armor::{Armor, ArmorKind},
item_key::ItemKey,
Item, ItemKind,
},
CharacterState,
@ -60,9 +61,12 @@ const LOD_COUNT: usize = 3;
type FigureModelEntryLod<'b> = Option<&'b FigureModelEntry<LOD_COUNT>>;
#[derive(Clone, Eq, Hash, PartialEq)]
/// TODO: merge item_key and extra field into an enum
pub struct FigureKey<Body> {
/// Body pointed to by this key.
pub(super) body: Body,
/// Only used by Body::ItemDrop
pub item_key: Option<Arc<ItemKey>>,
/// Extra state.
pub(super) extra: Option<Arc<CharacterCacheKey>>,
}
@ -323,10 +327,12 @@ where
_tick: u64,
camera_mode: CameraMode,
character_state: Option<&CharacterState>,
item_key: Option<ItemKey>,
) -> FigureModelEntryLod<'b> {
// TODO: Use raw entries to avoid lots of allocation (among other things).
let key = FigureKey {
body,
item_key: item_key.map(Arc::new),
extra: inventory.map(|inventory| {
Arc::new(CharacterCacheKey::from(
character_state,
@ -343,6 +349,7 @@ where
}
}
#[allow(clippy::too_many_arguments)]
pub fn get_or_create_model<'c>(
&'c mut self,
renderer: &mut Renderer,
@ -354,6 +361,7 @@ where
camera_mode: CameraMode,
character_state: Option<&CharacterState>,
slow_jobs: &SlowJobPool,
item_key: Option<ItemKey>,
) -> (FigureModelEntryLod<'c>, &'c Skel::Attr)
where
for<'a> &'a Skel::Body: Into<Skel::Attr>,
@ -363,6 +371,7 @@ where
let skeleton_attr = (&body).into();
let key = FigureKey {
body,
item_key: item_key.map(Arc::new),
extra: inventory.map(|inventory| {
Arc::new(CharacterCacheKey::from(
character_state,
@ -417,7 +426,8 @@ where
slow_jobs.spawn("FIGURE_MESHING", move || {
// First, load all the base vertex data.
let meshes = <Skel::Body as BodySpec>::bone_meshes(&key, &manifests, extra);
let meshes =
<Skel::Body as BodySpec>::bone_meshes(&key, &manifests, extra);
// Then, set up meshing context.
let mut greedy = FigureModel::make_greedy();
@ -447,9 +457,7 @@ where
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i as u8, bm)))
.for_each(|(i, (segment, offset))| {
// Generate this mesh.
let (_opaque_mesh, bounds) =
generate_mesh(&mut greedy, &mut opaque, segment, *offset, i);
let (_opaque_mesh, bounds) = generate_mesh(&mut greedy, &mut opaque, segment, *offset, i);
// Update the figure bounds to the largest granularity seen so far
// (NOTE: this is more than a little imperfect).
//

View File

@ -12,8 +12,8 @@ use common::{
fish_small::{self, BodyType as FSBodyType, Species as FSSpecies},
golem::{self, BodyType as GBodyType, Species as GSpecies},
humanoid::{self, Body, BodyType, EyeColor, Skin, Species},
item::{ItemDef, ModularComponentKind},
object,
item::{item_key::ItemKey, ItemDef, ModularComponentKind},
item_drop, object,
quadruped_low::{self, BodyType as QLBodyType, Species as QLSpecies},
quadruped_medium::{self, BodyType as QMBodyType, Species as QMSpecies},
quadruped_small::{self, BodyType as QSBodyType, Species as QSSpecies},
@ -23,7 +23,7 @@ use common::{
},
theropod::{self, BodyType as TBodyType, Species as TSpecies},
},
figure::{Cell, DynaUnionizer, MatSegment, Material, Segment},
figure::{Cell, DynaUnionizer, MatCell, MatSegment, Material, Segment},
vol::Vox,
};
use hashbrown::HashMap;
@ -137,7 +137,6 @@ macro_rules! make_vox_spec {
type Manifests = AssetHandle<Self::Spec>;
type Extra = ();
#[allow(unused_variables)]
fn load_spec() -> Result<Self::Manifests, assets::Error> {
Self::Spec::load("")
}
@ -398,7 +397,7 @@ make_vox_spec!(
// TODO: Add these.
/* tabard: HumArmorTabardSpec = "voxygen.voxel.humanoid_armor_tabard_manifest", */
},
|FigureKey { body, extra }, spec| {
|FigureKey { body, item_key: _, extra }, spec| {
const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey {
third_person: None,
tool: None,
@ -2888,7 +2887,7 @@ make_vox_spec!(
armor_tail: BipedSmallArmorTailSpec = "voxygen.voxel.biped_small_armor_tail_manifest",
},
|FigureKey { body: _, extra }, spec| {
|FigureKey { body: _, item_key: _, extra }, spec| {
const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey {
third_person: None,
tool: None,
@ -3917,7 +3916,7 @@ make_vox_spec!(
main: BipedLargeMainSpec = "voxygen.voxel.biped_weapon_manifest",
second: BipedLargeSecondSpec = "voxygen.voxel.biped_weapon_manifest",
},
|FigureKey { body, extra }, spec| {
|FigureKey { body, item_key: _, extra }, spec| {
const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey {
third_person: None,
tool: None,
@ -4902,6 +4901,75 @@ impl ObjectCentralSpec {
}
}
#[derive(Deserialize)]
struct ItemDropCentralSpec(HashMap<ItemKey, (String, [f32; 3], [f32; 3], f32)>);
make_vox_spec!(
item_drop::Body,
struct ItemDropSpec {
central: ItemDropCentralSpec = "voxygen.voxel.item_drop_manifest",
},
| FigureKey { body, item_key, .. }, spec| {
[
Some(spec.central.read().0.mesh_bone0(body, item_key.as_deref().unwrap_or(&ItemKey::Empty))),
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
]
},
);
impl ItemDropCentralSpec {
fn mesh_bone0(&self, item_drop: &item_drop::Body, item_key: &ItemKey) -> BoneMeshes {
let coin_pouch = (
"voxel.object.pouch".to_string(),
[-5.0, -5.0, 0.0],
[-10.0, 15.0, 0.0],
0.8,
);
if let Some(spec) = match item_drop {
item_drop::Body::CoinPouch => Some(&coin_pouch),
_ => self.0.get(item_key),
} {
let full_spec: String = ["voxygen.", spec.0.as_str()].concat();
(
match item_drop {
item_drop::Body::Armor(_) => {
MatSegment::from(&graceful_load_vox_fullspec(&full_spec).read().0)
.map(|mat_cell| match mat_cell {
MatCell::None => None,
MatCell::Mat(_) => Some(MatCell::None),
MatCell::Normal(data) => data.is_hollow().then(|| MatCell::None),
})
.to_segment(|_| Default::default())
},
_ => graceful_load_segment_fullspec(&full_spec),
},
Vec3::from(spec.1),
)
} else {
error!(
"No specification exists for {:?}, {:?}",
item_drop, item_key
);
load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5))
}
}
}
fn mesh_ship_bone<K: fmt::Debug + Eq + Hash, V, F: Fn(&V) -> &ShipCentralSubSpec>(
map: &HashMap<K, V>,
obj: &K,
@ -4925,7 +4993,6 @@ impl BodySpec for ship::Body {
type Manifests = AssetHandle<Self::Spec>;
type Spec = ShipSpec;
#[allow(unused_variables)]
fn load_spec() -> Result<Self::Manifests, assets::Error> { Self::Spec::load("") }
fn reload_watcher(manifests: &Self::Manifests) -> ReloadWatcher { manifests.reload_watcher() }

View File

@ -24,16 +24,17 @@ use anim::{
arthropod::ArthropodSkeleton, biped_large::BipedLargeSkeleton, biped_small::BipedSmallSkeleton,
bird_large::BirdLargeSkeleton, bird_medium::BirdMediumSkeleton, character::CharacterSkeleton,
dragon::DragonSkeleton, fish_medium::FishMediumSkeleton, fish_small::FishSmallSkeleton,
golem::GolemSkeleton, object::ObjectSkeleton, quadruped_low::QuadrupedLowSkeleton,
quadruped_medium::QuadrupedMediumSkeleton, quadruped_small::QuadrupedSmallSkeleton,
ship::ShipSkeleton, theropod::TheropodSkeleton, Animation, Skeleton,
golem::GolemSkeleton, item_drop::ItemDropSkeleton, object::ObjectSkeleton,
quadruped_low::QuadrupedLowSkeleton, quadruped_medium::QuadrupedMediumSkeleton,
quadruped_small::QuadrupedSmallSkeleton, ship::ShipSkeleton, theropod::TheropodSkeleton,
Animation, Skeleton,
};
use common::{
comp::{
inventory::slot::EquipSlot,
item::{Hands, ItemKind, ToolKind},
Body, CharacterState, Collider, Controller, Health, Inventory, Item, Last, LightAnimation,
LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Vel,
Body, CharacterState, Collider, Controller, Health, Inventory, Item, ItemKey, Last,
LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Vel,
},
link::Is,
mounting::Rider,
@ -117,6 +118,7 @@ struct FigureMgrStates {
biped_small_states: HashMap<EcsEntity, FigureState<BipedSmallSkeleton>>,
golem_states: HashMap<EcsEntity, FigureState<GolemSkeleton>>,
object_states: HashMap<EcsEntity, FigureState<ObjectSkeleton>>,
item_drop_states: HashMap<EcsEntity, FigureState<ItemDropSkeleton>>,
ship_states: HashMap<EcsEntity, FigureState<ShipSkeleton>>,
volume_states: HashMap<EcsEntity, FigureState<VolumeKey>>,
arthropod_states: HashMap<EcsEntity, FigureState<ArthropodSkeleton>>,
@ -139,6 +141,7 @@ impl FigureMgrStates {
biped_small_states: HashMap::new(),
golem_states: HashMap::new(),
object_states: HashMap::new(),
item_drop_states: HashMap::new(),
ship_states: HashMap::new(),
volume_states: HashMap::new(),
arthropod_states: HashMap::new(),
@ -202,6 +205,10 @@ impl FigureMgrStates {
.map(DerefMut::deref_mut),
Body::Golem(_) => self.golem_states.get_mut(entity).map(DerefMut::deref_mut),
Body::Object(_) => self.object_states.get_mut(entity).map(DerefMut::deref_mut),
Body::ItemDrop(_) => self
.item_drop_states
.get_mut(entity)
.map(DerefMut::deref_mut),
Body::Ship(ship) => {
if ship.manifest_entry().is_some() {
self.ship_states.get_mut(entity).map(DerefMut::deref_mut)
@ -236,6 +243,7 @@ impl FigureMgrStates {
Body::BipedSmall(_) => self.biped_small_states.remove(entity).map(|e| e.meta),
Body::Golem(_) => self.golem_states.remove(entity).map(|e| e.meta),
Body::Object(_) => self.object_states.remove(entity).map(|e| e.meta),
Body::ItemDrop(_) => self.item_drop_states.remove(entity).map(|e| e.meta),
Body::Ship(ship) => {
if ship.manifest_entry().is_some() {
self.ship_states.remove(entity).map(|e| e.meta)
@ -263,6 +271,7 @@ impl FigureMgrStates {
self.biped_small_states.retain(|k, v| f(k, &mut *v));
self.golem_states.retain(|k, v| f(k, &mut *v));
self.object_states.retain(|k, v| f(k, &mut *v));
self.item_drop_states.retain(|k, v| f(k, &mut *v));
self.ship_states.retain(|k, v| f(k, &mut *v));
self.volume_states.retain(|k, v| f(k, &mut *v));
self.arthropod_states.retain(|k, v| f(k, &mut *v));
@ -284,6 +293,7 @@ impl FigureMgrStates {
+ self.biped_small_states.len()
+ self.golem_states.len()
+ self.object_states.len()
+ self.item_drop_states.len()
+ self.ship_states.len()
+ self.volume_states.len()
+ self.arthropod_states.len()
@ -359,6 +369,11 @@ impl FigureMgrStates {
.iter()
.filter(|(_, c)| c.visible())
.count()
+ self
.item_drop_states
.iter()
.filter(|(_, c)| c.visible())
.count()
+ self
.arthropod_states
.iter()
@ -388,6 +403,7 @@ pub struct FigureMgr {
biped_large_model_cache: FigureModelCache<BipedLargeSkeleton>,
biped_small_model_cache: FigureModelCache<BipedSmallSkeleton>,
object_model_cache: FigureModelCache<ObjectSkeleton>,
item_drop_model_cache: FigureModelCache<ItemDropSkeleton>,
ship_model_cache: FigureModelCache<ShipSkeleton>,
golem_model_cache: FigureModelCache<GolemSkeleton>,
volume_model_cache: FigureModelCache<VolumeKey>,
@ -412,6 +428,7 @@ impl FigureMgr {
biped_large_model_cache: FigureModelCache::new(),
biped_small_model_cache: FigureModelCache::new(),
object_model_cache: FigureModelCache::new(),
item_drop_model_cache: FigureModelCache::new(),
ship_model_cache: FigureModelCache::new(),
golem_model_cache: FigureModelCache::new(),
volume_model_cache: FigureModelCache::new(),
@ -446,6 +463,7 @@ impl FigureMgr {
self.biped_small_model_cache
.clean(&mut self.col_lights, tick);
self.object_model_cache.clean(&mut self.col_lights, tick);
self.item_drop_model_cache.clean(&mut self.col_lights, tick);
self.ship_model_cache.clean(&mut self.col_lights, tick);
self.golem_model_cache.clean(&mut self.col_lights, tick);
self.volume_model_cache.clean(&mut self.col_lights, tick);
@ -864,6 +882,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let holding_lantern = inventory
@ -1759,6 +1778,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -1957,6 +1977,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -2272,6 +2293,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -2627,6 +2649,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -2729,6 +2752,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -2810,6 +2834,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -3207,6 +3232,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self.states.dragon_states.entry(entity).or_insert_with(|| {
@ -3292,6 +3318,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -3469,6 +3496,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -3759,6 +3787,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -4080,6 +4109,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -4161,6 +4191,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -4781,6 +4812,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self.states.golem_states.entry(entity).or_insert_with(|| {
@ -5020,6 +5052,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self.states.object_states.entry(entity).or_insert_with(|| {
@ -5135,6 +5168,68 @@ impl FigureMgr {
body,
);
},
Body::ItemDrop(body) => {
let item_key = item.map(ItemKey::from);
let (model, skeleton_attr) = self.item_drop_model_cache.get_or_create_model(
renderer,
&mut self.col_lights,
body,
inventory,
(),
tick,
player_camera_mode,
player_character_state,
&slow_jobs,
item_key,
);
let state = self
.states
.item_drop_states
.entry(entity)
.or_insert_with(|| {
FigureState::new(renderer, ItemDropSkeleton::default(), body)
});
// Average velocity relative to the current ground
let _rel_avg_vel = state.avg_vel - physics.ground_vel;
let (character, last_character) = match (character, last_character) {
(Some(c), Some(l)) => (c, l),
_ => (
&CharacterState::Idle(common::states::idle::Data {
is_sneaking: false,
}),
&Last {
0: CharacterState::Idle(common::states::idle::Data {
is_sneaking: false,
}),
},
),
};
if !character.same_variant(&last_character.0) {
state.state_time = 0.0;
}
let target_bones = anim::item_drop::IdleAnimation::update_skeleton(
&ItemDropSkeleton::default(),
time,
state.state_time,
&mut state_animation_rate,
skeleton_attr,
);
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
&mut update_buf,
&common_params,
state_animation_rate,
model,
body,
);
},
Body::Ship(body) => {
let (model, skeleton_attr) = if let Some(Collider::Volume(vol)) = collider {
let vk = VolumeKey {
@ -5151,6 +5246,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
);
let state = self
@ -5180,6 +5276,7 @@ impl FigureMgr {
player_camera_mode,
player_character_state,
&slow_jobs,
None,
)
} else {
// No way to determine model (this is okay, we might just not have received
@ -5282,6 +5379,7 @@ impl FigureMgr {
) {
span!(_guard, "render_shadows", "FigureManager::render_shadows");
let ecs = state.ecs();
let items = ecs.read_storage::<Item>();
(
&ecs.entities(),
@ -5312,6 +5410,7 @@ impl FigureMgr {
_ => 0,
},
|state| state.can_shadow_sun(),
if matches!(body, Body::ItemDrop(_)) { items.get(entity).map(ItemKey::from) } else { None },
) {
drawer.draw(model, bound);
}
@ -5331,7 +5430,7 @@ impl FigureMgr {
let character_state_storage = state.read_storage::<common::comp::CharacterState>();
let character_state = character_state_storage.get(player_entity);
let items = ecs.read_storage::<Item>();
for (entity, pos, body, _, inventory, scale, collider) in (
&ecs.entities(),
&ecs.read_storage::<Pos>(),
@ -5362,6 +5461,11 @@ impl FigureMgr {
_ => 0,
},
|state| state.visible(),
if matches!(body, Body::ItemDrop(_)) {
items.get(entity).map(ItemKey::from)
} else {
None
},
) {
drawer.draw(model, bound, col_lights);
}
@ -5381,6 +5485,7 @@ impl FigureMgr {
let character_state_storage = state.read_storage::<common::comp::CharacterState>();
let character_state = character_state_storage.get(player_entity);
let items = ecs.read_storage::<Item>();
if let (Some(pos), Some(body)) = (
ecs.read_storage::<Pos>().get(player_entity),
@ -5407,6 +5512,11 @@ impl FigureMgr {
figure_lod_render_distance,
0,
|state| state.visible(),
if matches!(body, Body::ItemDrop(_)) {
items.get(player_entity).map(ItemKey::from)
} else {
None
},
) {
drawer.draw(model, bound, col_lights);
/*renderer.render_player_shadow(
@ -5435,6 +5545,7 @@ impl FigureMgr {
figure_lod_render_distance: f32,
mut_count: usize,
filter_state: impl Fn(&FigureStateMeta) -> bool,
item_key: Option<ItemKey>,
) -> Option<FigureModelRef> {
let body = *body;
@ -5462,6 +5573,7 @@ impl FigureMgr {
biped_large_model_cache,
biped_small_model_cache,
object_model_cache,
item_drop_model_cache,
ship_model_cache,
golem_model_cache,
volume_model_cache,
@ -5482,6 +5594,7 @@ impl FigureMgr {
biped_small_states,
golem_states,
object_states,
item_drop_states,
ship_states,
volume_states,
arthropod_states,
@ -5502,6 +5615,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5518,6 +5632,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5534,6 +5649,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5550,6 +5666,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5566,6 +5683,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5582,6 +5700,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5598,6 +5717,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5614,6 +5734,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5630,6 +5751,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5646,6 +5768,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5662,6 +5785,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5678,6 +5802,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5694,6 +5819,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5710,6 +5836,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
@ -5726,6 +5853,24 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
}),
Body::ItemDrop(body) => item_drop_states
.get(&entity)
.filter(|state| filter_state(*state))
.map(move |state| {
(
state.bound(),
item_drop_model_cache.get_model(
col_lights,
body,
inventory,
tick,
player_camera_mode,
character_state,
item_key,
),
)
}),
@ -5744,6 +5889,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
})
@ -5761,6 +5907,7 @@ impl FigureMgr {
tick,
player_camera_mode,
character_state,
None,
),
)
})

View File

@ -325,6 +325,7 @@ impl Scene {
CameraMode::default(),
None,
scene_data.slow_job_pool,
None,
)
.0;
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
@ -369,6 +370,7 @@ impl Scene {
tick,
CameraMode::default(),
None,
None,
);
if let Some((model, figure_state)) = model.zip(self.figure_state.as_ref()) {

View File

@ -2,7 +2,7 @@ use super::image_frame::ImageFrame;
use crate::hud::{
get_quality_col,
img_ids::Imgs,
item_imgs::{animate_by_pulse, ItemImgs, ItemKey},
item_imgs::{animate_by_pulse, ItemImgs},
util,
};
use client::Client;
@ -11,6 +11,7 @@ use common::{
comp::{
item::{
armor::{ArmorKind, Protection},
item_key::ItemKey,
Item, ItemDesc, ItemKind, ItemTag, MaterialStatManifest, Quality,
},
Energy,