Cache figures more intelligently.

Cache figures for longer, and don't cache character states for the
player except where they actually affect the rendered model.
This commit is contained in:
Joshua Yanovski 2020-08-12 20:15:46 +02:00
parent 0ed801d540
commit c6251a956a
3 changed files with 398 additions and 376 deletions

View File

@ -8,80 +8,159 @@ use anim::Skeleton;
use common::{ use common::{
assets::watch::ReloadIndicator, assets::watch::ReloadIndicator,
comp::{ comp::{
item::{armor::ArmorKind, tool::ToolKind, ItemKind}, item::{
armor::{Armor, ArmorKind},
tool::ToolKind,
ItemKind,
},
Body, CharacterState, Loadout, Body, CharacterState, Loadout,
}, },
figure::Segment, figure::Segment,
vol::BaseVol, vol::BaseVol,
}; };
use core::convert::TryInto;
use hashbrown::{hash_map::Entry, HashMap}; use hashbrown::{hash_map::Entry, HashMap};
use std::{
convert::TryInto,
mem::{discriminant, Discriminant},
};
use vek::*; use vek::*;
pub type FigureModelEntry = [FigureModel; 3]; pub type FigureModelEntry = [FigureModel; 3];
#[allow(clippy::large_enum_variant)] // TODO: Pending review in #587 #[derive(Eq, Hash, PartialEq)]
#[derive(PartialEq, Eq, Hash, Clone)] struct FigureKey {
enum FigureKey { /// Body pointed to by this key.
Simple(Body), body: Body,
Complex(Body, CameraMode, CharacterCacheKey), /// Extra state.
extra: Option<Box<CharacterCacheKey>>,
} }
#[derive(PartialEq, Eq, Hash, Clone)] /// Character data that should be visible when tools are visible (i.e. in third
/// person or when the character is in a tool-using state).
#[derive(Eq, Hash, PartialEq)]
pub struct CharacterToolKey {
active: Option<ToolKind>,
second: Option<ToolKind>,
}
/// Character data that exists in third person only.
#[derive(Eq, Hash, PartialEq)]
struct CharacterThirdPersonKey {
shoulder: Option<String>,
chest: Option<String>,
belt: Option<String>,
back: Option<String>,
pants: Option<String>,
}
#[derive(Eq, Hash, PartialEq)]
/// NOTE: To avoid spamming the character cache with player models, we try to
/// store only the minimum information required to correctly update the model.
///
/// TODO: Memoize, etc.
struct CharacterCacheKey { struct CharacterCacheKey {
state: Option<Discriminant<CharacterState>>, // TODO: Can this be simplified? /// Character state that is only visible in third person.
active_tool: Option<ToolKind>, third_person: Option<CharacterThirdPersonKey>,
second_tool: Option<ToolKind>, /// Tool state should be present when a character is either in third person,
shoulder: Option<ArmorKind>, /// or is in first person and the character state is tool-using.
chest: Option<ArmorKind>, ///
belt: Option<ArmorKind>, /// NOTE: This representation could be tightened in various ways to
back: Option<ArmorKind>, /// eliminate incorrect states, e.g. setting active_tool to None when no
/// tools are equipped, but currently we are more focused on the big
/// performance impact of recreating the whole model whenever the character
/// state changes, so for now we don't bother with this.
tool: Option<CharacterToolKey>,
lantern: Option<String>, lantern: Option<String>,
hand: Option<ArmorKind>, hand: Option<String>,
pants: Option<ArmorKind>, foot: Option<String>,
foot: Option<ArmorKind>,
} }
impl CharacterCacheKey { impl CharacterCacheKey {
fn from(cs: Option<&CharacterState>, loadout: &Loadout) -> Self { fn from(cs: Option<&CharacterState>, camera_mode: CameraMode, loadout: &Loadout) -> Self {
let is_first_person = match camera_mode {
CameraMode::FirstPerson => true,
CameraMode::ThirdPerson | CameraMode::Freefly => false,
};
// Third person tools are only modeled when the camera is either not first
// person, or the camera is first person and we are in a tool-using
// state.
let are_tools_visible = !is_first_person
|| cs
.map(|cs| cs.is_attack() || cs.is_block() || cs.is_wield())
// If there's no provided character state but we're still somehow in first person,
// We currently assume there's no need to visually model tools.
//
// TODO: Figure out what to do here, and/or refactor how this works.
.unwrap_or(false);
Self { Self {
state: cs.map(|cs| discriminant(cs)), // Third person armor is only modeled when the camera mode is not first person.
active_tool: if let Some(ItemKind::Tool(tool)) = third_person: if is_first_person {
None
} else {
Some(CharacterThirdPersonKey {
shoulder: if let Some(ItemKind::Armor(Armor {
kind: ArmorKind::Shoulder(armor),
..
})) = loadout.shoulder.as_ref().map(|i| &i.kind)
{
Some(armor.clone())
} else {
None
},
chest: if let Some(ItemKind::Armor(Armor {
kind: ArmorKind::Chest(armor),
..
})) = loadout.chest.as_ref().map(|i| &i.kind)
{
Some(armor.clone())
} else {
None
},
belt: if let Some(ItemKind::Armor(Armor {
kind: ArmorKind::Belt(armor),
..
})) = loadout.belt.as_ref().map(|i| &i.kind)
{
Some(armor.clone())
} else {
None
},
back: if let Some(ItemKind::Armor(Armor {
kind: ArmorKind::Back(armor),
..
})) = loadout.back.as_ref().map(|i| &i.kind)
{
Some(armor.clone())
} else {
None
},
pants: if let Some(ItemKind::Armor(Armor {
kind: ArmorKind::Pants(armor),
..
})) = loadout.pants.as_ref().map(|i| &i.kind)
{
Some(armor.clone())
} else {
None
},
})
},
tool: if are_tools_visible {
Some(CharacterToolKey {
active: if let Some(ItemKind::Tool(tool)) =
loadout.active_item.as_ref().map(|i| &i.item.kind) loadout.active_item.as_ref().map(|i| &i.item.kind)
{ {
Some(tool.kind.clone()) Some(tool.kind.clone())
} else { } else {
None None
}, },
second_tool: if let Some(ItemKind::Tool(tool)) = second: if let Some(ItemKind::Tool(tool)) =
loadout.second_item.as_ref().map(|i| &i.item.kind) loadout.second_item.as_ref().map(|i| &i.item.kind)
{ {
Some(tool.kind.clone()) Some(tool.kind.clone())
} else { } else {
None None
}, },
shoulder: if let Some(ItemKind::Armor(armor)) = })
loadout.shoulder.as_ref().map(|i| &i.kind)
{
Some(armor.kind.clone())
} else {
None
},
chest: if let Some(ItemKind::Armor(armor)) = loadout.chest.as_ref().map(|i| &i.kind) {
Some(armor.kind.clone())
} else {
None
},
belt: if let Some(ItemKind::Armor(armor)) = loadout.belt.as_ref().map(|i| &i.kind) {
Some(armor.kind.clone())
} else {
None
},
back: if let Some(ItemKind::Armor(armor)) = loadout.back.as_ref().map(|i| &i.kind) {
Some(armor.kind.clone())
} else { } else {
None None
}, },
@ -92,18 +171,21 @@ impl CharacterCacheKey {
} else { } else {
None None
}, },
hand: if let Some(ItemKind::Armor(armor)) = loadout.hand.as_ref().map(|i| &i.kind) { hand: if let Some(ItemKind::Armor(Armor {
Some(armor.kind.clone()) kind: ArmorKind::Hand(armor),
..
})) = loadout.hand.as_ref().map(|i| &i.kind)
{
Some(armor.clone())
} else { } else {
None None
}, },
pants: if let Some(ItemKind::Armor(armor)) = loadout.pants.as_ref().map(|i| &i.kind) { foot: if let Some(ItemKind::Armor(Armor {
Some(armor.kind.clone()) kind: ArmorKind::Foot(armor),
} else { ..
None })) = loadout.foot.as_ref().map(|i| &i.kind)
}, {
foot: if let Some(ItemKind::Armor(armor)) = loadout.foot.as_ref().map(|i| &i.kind) { Some(armor.clone())
Some(armor.kind.clone())
} else { } else {
None None
}, },
@ -129,11 +211,12 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
} }
} }
/// NOTE: We deliberately call this function with only the key into the
/// cache, to enforce that the cached state only depends on the key. We
/// may end up using different from this cache eventually, in which case
/// this strategy might change.
fn bone_meshes( fn bone_meshes(
body: Body, FigureKey { body, extra }: &FigureKey,
loadout: Option<&Loadout>,
character_state: Option<&CharacterState>,
camera_mode: CameraMode,
manifest_indicator: &mut ReloadIndicator, manifest_indicator: &mut ReloadIndicator,
mut generate_mesh: impl FnMut(Segment, Vec3<f32>) -> BoneMeshes, mut generate_mesh: impl FnMut(Segment, Vec3<f32>) -> BoneMeshes,
) -> [Option<BoneMeshes>; 16] { ) -> [Option<BoneMeshes>; 16] {
@ -152,130 +235,109 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
let humanoid_armor_foot_spec = HumArmorFootSpec::load_watched(manifest_indicator); let humanoid_armor_foot_spec = HumArmorFootSpec::load_watched(manifest_indicator);
let humanoid_main_weapon_spec = HumMainWeaponSpec::load_watched(manifest_indicator); let humanoid_main_weapon_spec = HumMainWeaponSpec::load_watched(manifest_indicator);
const DEFAULT_LOADOUT: CharacterCacheKey = CharacterCacheKey {
third_person: None,
tool: None,
lantern: None,
hand: None,
foot: None,
};
// TODO: This is bad code, maybe this method should return Option<_> // TODO: This is bad code, maybe this method should return Option<_>
let default_loadout = Loadout::default(); let loadout = extra.as_deref().unwrap_or(&DEFAULT_LOADOUT);
let loadout = loadout.unwrap_or(&default_loadout); let third_person = loadout.third_person.as_ref();
let tool = loadout.tool.as_ref();
let lantern = loadout.lantern.as_deref();
let hand = loadout.hand.as_deref();
let foot = loadout.foot.as_deref();
[ [
match camera_mode { third_person.map(|_| {
CameraMode::ThirdPerson | CameraMode::Freefly => Some(
humanoid_head_spec humanoid_head_spec
.mesh_head(&body, |segment, offset| generate_mesh(segment, offset)), .mesh_head(body, |segment, offset| generate_mesh(segment, offset))
}),
third_person.map(|loadout| {
humanoid_armor_chest_spec.mesh_chest(
body,
loadout.chest.as_deref(),
|segment, offset| generate_mesh(segment, offset),
)
}),
third_person.map(|loadout| {
humanoid_armor_belt_spec.mesh_belt(
body,
loadout.belt.as_deref(),
|segment, offset| generate_mesh(segment, offset),
)
}),
third_person.map(|loadout| {
humanoid_armor_back_spec.mesh_back(
body,
loadout.back.as_deref(),
|segment, offset| generate_mesh(segment, offset),
)
}),
third_person.map(|loadout| {
humanoid_armor_pants_spec.mesh_pants(
body,
loadout.pants.as_deref(),
|segment, offset| generate_mesh(segment, offset),
)
}),
Some(
humanoid_armor_hand_spec.mesh_left_hand(body, hand, |segment, offset| {
generate_mesh(segment, offset)
}),
), ),
CameraMode::FirstPerson => None,
},
match camera_mode {
CameraMode::ThirdPerson | CameraMode::Freefly => {
Some(humanoid_armor_chest_spec.mesh_chest(
&body,
loadout,
|segment, offset| generate_mesh(segment, offset),
))
},
CameraMode::FirstPerson => None,
},
match camera_mode {
CameraMode::ThirdPerson | CameraMode::Freefly => {
Some(humanoid_armor_belt_spec.mesh_belt(
&body,
loadout,
|segment, offset| generate_mesh(segment, offset),
))
},
CameraMode::FirstPerson => None,
},
match camera_mode {
CameraMode::ThirdPerson | CameraMode::Freefly => {
Some(humanoid_armor_back_spec.mesh_back(
&body,
loadout,
|segment, offset| generate_mesh(segment, offset),
))
},
CameraMode::FirstPerson => None,
},
match camera_mode {
CameraMode::ThirdPerson | CameraMode::Freefly => {
Some(humanoid_armor_pants_spec.mesh_pants(
&body,
loadout,
|segment, offset| generate_mesh(segment, offset),
))
},
CameraMode::FirstPerson => None,
},
Some(humanoid_armor_hand_spec.mesh_left_hand(
&body,
loadout,
|segment, offset| generate_mesh(segment, offset),
)),
Some(humanoid_armor_hand_spec.mesh_right_hand( Some(humanoid_armor_hand_spec.mesh_right_hand(
&body, body,
loadout, hand,
|segment, offset| generate_mesh(segment, offset),
)),
Some(humanoid_armor_foot_spec.mesh_left_foot(
&body,
loadout,
|segment, offset| generate_mesh(segment, offset), |segment, offset| generate_mesh(segment, offset),
)), )),
Some(
humanoid_armor_foot_spec.mesh_left_foot(body, foot, |segment, offset| {
generate_mesh(segment, offset)
}),
),
Some(humanoid_armor_foot_spec.mesh_right_foot( Some(humanoid_armor_foot_spec.mesh_right_foot(
&body, body,
loadout, foot,
|segment, offset| generate_mesh(segment, offset), |segment, offset| generate_mesh(segment, offset),
)), )),
match camera_mode { third_person.map(|loadout| {
CameraMode::ThirdPerson | CameraMode::Freefly => { humanoid_armor_shoulder_spec.mesh_left_shoulder(
Some(humanoid_armor_shoulder_spec.mesh_left_shoulder( body,
&body, loadout.shoulder.as_deref(),
loadout,
|segment, offset| generate_mesh(segment, offset), |segment, offset| generate_mesh(segment, offset),
)) )
}, }),
CameraMode::FirstPerson => None, third_person.map(|loadout| {
}, humanoid_armor_shoulder_spec.mesh_right_shoulder(
match camera_mode { body,
CameraMode::ThirdPerson | CameraMode::Freefly => { loadout.shoulder.as_deref(),
Some(humanoid_armor_shoulder_spec.mesh_right_shoulder(
&body,
loadout,
|segment, offset| generate_mesh(segment, offset), |segment, offset| generate_mesh(segment, offset),
)) )
}, }),
CameraMode::FirstPerson => None,
},
Some(mesh_glider(|segment, offset| { Some(mesh_glider(|segment, offset| {
generate_mesh(segment, offset) generate_mesh(segment, offset)
})), })),
if camera_mode != CameraMode::FirstPerson tool.map(|tool| {
|| character_state humanoid_main_weapon_spec.mesh_main_weapon(
.map(|cs| cs.is_attack() || cs.is_block() || cs.is_wield()) tool.active.as_ref(),
.unwrap_or_default()
{
Some(humanoid_main_weapon_spec.mesh_main_weapon(
loadout.active_item.as_ref().map(|i| &i.item.kind),
false, false,
|segment, offset| generate_mesh(segment, offset), |segment, offset| generate_mesh(segment, offset),
)) )
} else { }),
None tool.map(|tool| {
}, humanoid_main_weapon_spec.mesh_main_weapon(
if camera_mode != CameraMode::FirstPerson tool.second.as_ref(),
|| character_state
.map(|cs| cs.is_attack() || cs.is_block() || cs.is_wield())
.unwrap_or_default()
{
Some(humanoid_main_weapon_spec.mesh_main_weapon(
loadout.second_item.as_ref().map(|i| &i.item.kind),
true, true,
|segment, offset| generate_mesh(segment, offset), |segment, offset| generate_mesh(segment, offset),
)) )
} else { }),
None
},
Some(humanoid_armor_lantern_spec.mesh_lantern( Some(humanoid_armor_lantern_spec.mesh_lantern(
&body, body,
loadout, lantern,
|segment, offset| generate_mesh(segment, offset), |segment, offset| generate_mesh(segment, offset),
)), )),
Some(mesh_hold(|segment, offset| generate_mesh(segment, offset))), Some(mesh_hold(|segment, offset| generate_mesh(segment, offset))),
@ -923,14 +985,15 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
for<'a> &'a common::comp::Body: std::convert::TryInto<Skel::Attr>, for<'a> &'a common::comp::Body: std::convert::TryInto<Skel::Attr>,
Skel::Attr: Default, Skel::Attr: Default,
{ {
let key = if let Some(loadout) = loadout { let key = FigureKey {
FigureKey::Complex(
body, body,
extra: loadout.map(|loadout| {
Box::new(CharacterCacheKey::from(
character_state,
camera_mode, camera_mode,
CharacterCacheKey::from(character_state, loadout), loadout,
) ))
} else { }),
FigureKey::Simple(body)
}; };
match self.models.entry(key) { match self.models.entry(key) {
@ -940,8 +1003,8 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
model model
}, },
Entry::Vacant(v) => { Entry::Vacant(v) => {
&v.insert(( let key = v.key();
{ let model = {
let skeleton_attr = (&body) let skeleton_attr = (&body)
.try_into() .try_into()
.ok() .ok()
@ -956,25 +1019,17 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
min: Vec3::zero(), min: Vec3::zero(),
max: Vec3::zero(), max: Vec3::zero(),
}; };
Self::bone_meshes( Self::bone_meshes(key, manifest_indicator, |segment, offset| {
body, generate_mesh(&mut greedy, segment, offset)
loadout, })
character_state,
camera_mode,
manifest_indicator,
|segment, offset| generate_mesh(&mut greedy, segment, offset),
)
.iter() .iter()
.enumerate() .enumerate()
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
.for_each( .for_each(|(i, (opaque_mesh, bounds))| {
|(i, (opaque_mesh, bounds))| { opaque
opaque.push_mesh_map(opaque_mesh, |vert| { .push_mesh_map(opaque_mesh, |vert| vert.with_bone_idx(i as u8));
vert.with_bone_idx(i as u8)
});
figure_bounds.expand_to_contain(*bounds); figure_bounds.expand_to_contain(*bounds);
}, });
);
col_lights col_lights
.create_figure(renderer, greedy, (opaque, figure_bounds)) .create_figure(renderer, greedy, (opaque, figure_bounds))
.unwrap() .unwrap()
@ -1030,10 +1085,8 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
], ],
skeleton_attr, skeleton_attr,
) )
}, };
tick, &v.insert((model, tick)).0
))
.0
}, },
} }
} }
@ -1048,7 +1101,9 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
// TODO: Don't hard-code this. // TODO: Don't hard-code this.
if tick % 60 == 0 { if tick % 60 == 0 {
self.models.retain(|_, ((models, _), last_used)| { self.models.retain(|_, ((models, _), last_used)| {
let alive = *last_used + 60 > tick; // Wait about a minute at 60 fps before invalidating old models.
let delta = 60 * 60;
let alive = *last_used + delta > tick;
if !alive { if !alive {
models.iter().for_each(|model| { models.iter().for_each(|model| {
col_lights.atlas.deallocate(model.allocation.id); col_lights.atlas.deallocate(model.allocation.id);

View File

@ -10,16 +10,11 @@ use common::{
fish_medium, fish_small, fish_medium, fish_small,
golem::{BodyType as GBodyType, Species as GSpecies}, golem::{BodyType as GBodyType, Species as GSpecies},
humanoid::{Body, BodyType, EyeColor, Skin, Species}, humanoid::{Body, BodyType, EyeColor, Skin, Species},
item::{ item::tool::ToolKind,
armor::{Armor, ArmorKind},
tool::{Tool, ToolKind},
ItemKind, Lantern,
},
object, object,
quadruped_low::{BodyType as QLBodyType, Species as QLSpecies}, quadruped_low::{BodyType as QLBodyType, Species as QLSpecies},
quadruped_medium::{BodyType as QMBodyType, Species as QMSpecies}, quadruped_medium::{BodyType as QMBodyType, Species as QMSpecies},
quadruped_small::{BodyType as QSBodyType, Species as QSSpecies}, quadruped_small::{BodyType as QSBodyType, Species as QSSpecies},
Loadout,
}, },
figure::{DynaUnionizer, MatSegment, Material, Segment}, figure::{DynaUnionizer, MatSegment, Material, Segment},
}; };
@ -361,15 +356,11 @@ impl HumArmorShoulderSpec {
fn mesh_shoulder( fn mesh_shoulder(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, shoulder: Option<&str>,
flipped: bool, flipped: bool,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(shoulder) = shoulder {
kind: ArmorKind::Shoulder(shoulder),
..
})) = loadout.shoulder.as_ref().map(|i| &i.kind)
{
match self.0.map.get(shoulder) { match self.0.map.get(shoulder) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -419,19 +410,19 @@ impl HumArmorShoulderSpec {
pub fn mesh_left_shoulder( pub fn mesh_left_shoulder(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, shoulder: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
self.mesh_shoulder(body, loadout, true, generate_mesh) self.mesh_shoulder(body, shoulder, true, generate_mesh)
} }
pub fn mesh_right_shoulder( pub fn mesh_right_shoulder(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, shoulder: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
self.mesh_shoulder(body, loadout, false, generate_mesh) self.mesh_shoulder(body, shoulder, false, generate_mesh)
} }
} }
// Chest // Chest
@ -444,18 +435,14 @@ impl HumArmorChestSpec {
pub fn mesh_chest( pub fn mesh_chest(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, chest: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(chest) = chest {
kind: ArmorKind::Chest(chest),
..
})) = loadout.chest.as_ref().map(|i| &i.kind)
{
match self.0.map.get(chest) { match self.0.map.get(chest) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
error!(?loadout.chest, "No chest specification exists"); error!(?chest, "No chest specification exists");
return load_mesh("not_found", Vec3::new(-7.0, -3.5, 2.0), generate_mesh); return load_mesh("not_found", Vec3::new(-7.0, -3.5, 2.0), generate_mesh);
}, },
} }
@ -500,15 +487,11 @@ impl HumArmorHandSpec {
fn mesh_hand( fn mesh_hand(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, hand: Option<&str>,
flipped: bool, flipped: bool,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(hand) = hand {
kind: ArmorKind::Hand(hand),
..
})) = loadout.hand.as_ref().map(|i| &i.kind)
{
match self.0.map.get(hand) { match self.0.map.get(hand) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -552,19 +535,19 @@ impl HumArmorHandSpec {
pub fn mesh_left_hand( pub fn mesh_left_hand(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, hand: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
self.mesh_hand(body, loadout, true, generate_mesh) self.mesh_hand(body, hand, true, generate_mesh)
} }
pub fn mesh_right_hand( pub fn mesh_right_hand(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, hand: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
self.mesh_hand(body, loadout, false, generate_mesh) self.mesh_hand(body, hand, false, generate_mesh)
} }
} }
// Belt // Belt
@ -577,14 +560,10 @@ impl HumArmorBeltSpec {
pub fn mesh_belt( pub fn mesh_belt(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, belt: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(belt) = belt {
kind: ArmorKind::Belt(belt),
..
})) = loadout.belt.as_ref().map(|i| &i.kind)
{
match self.0.map.get(belt) { match self.0.map.get(belt) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -621,14 +600,10 @@ impl HumArmorBackSpec {
pub fn mesh_back( pub fn mesh_back(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, back: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(back) = back {
kind: ArmorKind::Back(back),
..
})) = loadout.back.as_ref().map(|i| &i.kind)
{
match self.0.map.get(back) { match self.0.map.get(back) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -664,14 +639,10 @@ impl HumArmorPantsSpec {
pub fn mesh_pants( pub fn mesh_pants(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, pants: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(pants) = pants {
kind: ArmorKind::Pants(pants),
..
})) = loadout.pants.as_ref().map(|i| &i.kind)
{
match self.0.map.get(pants) { match self.0.map.get(pants) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -720,15 +691,11 @@ impl HumArmorFootSpec {
fn mesh_foot( fn mesh_foot(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, foot: Option<&str>,
flipped: bool, flipped: bool,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(foot) = foot {
kind: ArmorKind::Foot(foot),
..
})) = loadout.foot.as_ref().map(|i| &i.kind)
{
match self.0.map.get(foot) { match self.0.map.get(foot) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -762,19 +729,19 @@ impl HumArmorFootSpec {
pub fn mesh_left_foot( pub fn mesh_left_foot(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, foot: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
self.mesh_foot(body, loadout, true, generate_mesh) self.mesh_foot(body, foot, true, generate_mesh)
} }
pub fn mesh_right_foot( pub fn mesh_right_foot(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, foot: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
self.mesh_foot(body, loadout, false, generate_mesh) self.mesh_foot(body, foot, false, generate_mesh)
} }
} }
@ -786,11 +753,11 @@ impl HumMainWeaponSpec {
pub fn mesh_main_weapon( pub fn mesh_main_weapon(
&self, &self,
item_kind: Option<&ItemKind>, tool_kind: Option<&ToolKind>,
flipped: bool, flipped: bool,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let tool_kind = if let Some(ItemKind::Tool(Tool { kind, .. })) = item_kind { let tool_kind = if let Some(kind) = tool_kind {
kind kind
} else { } else {
return (Mesh::new(), Aabb::default()); return (Mesh::new(), Aabb::default());
@ -835,12 +802,10 @@ impl HumArmorLanternSpec {
pub fn mesh_lantern( pub fn mesh_lantern(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, lantern: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Lantern(Lantern { kind, .. })) = let spec = if let Some(kind) = lantern {
loadout.lantern.as_ref().map(|i| &i.kind)
{
match self.0.map.get(kind) { match self.0.map.get(kind) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -876,14 +841,10 @@ impl HumArmorHeadSpec {
pub fn mesh_head( pub fn mesh_head(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, head: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(head) = head {
kind: ArmorKind::Head(head),
..
})) = loadout.head.as_ref().map(|i| &i.kind)
{
match self.0.map.get(head) { match self.0.map.get(head) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -931,14 +892,10 @@ impl HumArmorTabardSpec {
pub fn mesh_tabard( pub fn mesh_tabard(
&self, &self,
body: &Body, body: &Body,
loadout: &Loadout, tabard: Option<&str>,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
let spec = if let Some(ItemKind::Armor(Armor { let spec = if let Some(tabard) = tabard {
kind: ArmorKind::Tabard(tabard),
..
})) = loadout.tabard.as_ref().map(|i| &i.kind)
{
match self.0.map.get(tabard) { match self.0.map.get(tabard) {
Some(spec) => spec, Some(spec) => spec,
None => { None => {
@ -3403,7 +3360,7 @@ impl QuadrupedLowLateralSpec {
/// ///
pub fn mesh_object( pub fn mesh_object(
obj: object::Body, obj: &object::Body,
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes, generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
) -> BoneMeshes { ) -> BoneMeshes {
use object::Body; use object::Body;

View File

@ -481,6 +481,9 @@ impl FigureMgr {
min: player_pos - 2.0, min: player_pos - 2.0,
max: player_pos + 2.0, max: player_pos + 2.0,
}; };
let camera_mode = camera.get_mode();
let character_state_storage = state.read_storage::<common::comp::CharacterState>();
let character_state = character_state_storage.get(scene_data.player_entity);
let focus_pos = anim::vek::Vec3::<f32>::from(camera.get_focus_pos()); let focus_pos = anim::vek::Vec3::<f32>::from(camera.get_focus_pos());
@ -521,6 +524,13 @@ impl FigureMgr {
{ {
let vel = (anim::vek::Vec3::<f32>::from(vel.0),); let vel = (anim::vek::Vec3::<f32>::from(vel.0),);
let is_player = scene_data.player_entity == entity; let is_player = scene_data.player_entity == entity;
let player_camera_mode = if is_player {
camera_mode
} else {
CameraMode::default()
};
let player_character_state = if is_player { character_state } else { None };
let (pos, ori) = interpolated let (pos, ori) = interpolated
.map(|i| { .map(|i| {
( (
@ -654,8 +664,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1024,8 +1034,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1125,8 +1135,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1226,8 +1236,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1324,8 +1334,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1420,8 +1430,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1499,8 +1509,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = let state =
@ -1574,8 +1584,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = let state =
@ -1650,8 +1660,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1729,8 +1739,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1808,8 +1818,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = self let state = self
@ -1904,8 +1914,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = let state =
@ -1980,8 +1990,8 @@ impl FigureMgr {
*body, *body,
loadout, loadout,
tick, tick,
CameraMode::default(), player_camera_mode,
None, player_character_state,
); );
let state = let state =