From 73a985656eb2b7e4e84fe12febbd00f4cb14655e Mon Sep 17 00:00:00 2001
From: scott-c <xodster@gmail.com>
Date: Sun, 5 Jul 2020 23:11:45 +0800
Subject: [PATCH 1/2] fix 1h second item cache issue #661

---
 voxygen/src/scene/figure/cache.rs | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs
index 68c2ac550f..a65d6fd31c 100644
--- a/voxygen/src/scene/figure/cache.rs
+++ b/voxygen/src/scene/figure/cache.rs
@@ -32,6 +32,7 @@ enum FigureKey {
 struct CharacterCacheKey {
     state: Option<Discriminant<CharacterState>>, // TODO: Can this be simplified?
     active_tool: Option<ToolKind>,
+    second_tool: Option<ToolKind>,
     shoulder: Option<Item>,
     chest: Option<Item>,
     belt: Option<Item>,
@@ -53,6 +54,13 @@ impl CharacterCacheKey {
             } else {
                 None
             },
+            second_tool: if let Some(ItemKind::Tool(tool)) =
+                loadout.second_item.as_ref().map(|i| &i.item.kind)
+            {
+                Some(tool.kind)
+            } else {
+                None
+            },
             shoulder: loadout.shoulder.clone(),
             chest: loadout.chest.clone(),
             belt: loadout.belt.clone(),

From d3142cab09a604a4390a9cce8a92871ee66fc3cf Mon Sep 17 00:00:00 2001
From: scott-c <xodster@gmail.com>
Date: Mon, 6 Jul 2020 00:21:12 +0800
Subject: [PATCH 2/2] Fix 1h models in character select idle animation #662

---
 voxygen/examples/character_renderer.rs |  2 +-
 voxygen/src/anim/src/character/idle.rs | 53 ++++++++++++++++++++++----
 voxygen/src/menu/char_selection/mod.rs | 11 ++++--
 voxygen/src/scene/simple.rs            | 31 +++++++++++++--
 4 files changed, 82 insertions(+), 15 deletions(-)

diff --git a/voxygen/examples/character_renderer.rs b/voxygen/examples/character_renderer.rs
index 3a70178704..cf0aee4f53 100644
--- a/voxygen/examples/character_renderer.rs
+++ b/voxygen/examples/character_renderer.rs
@@ -62,7 +62,7 @@ fn main() {
     scene
         .camera_mut()
         .update(0.0, 1.0 / 60.0, scene_data.mouse_smoothing);
-    scene.maintain(&mut renderer, scene_data);
+    scene.maintain(&mut renderer, scene_data, Some(&loadout));
 
     // Render
     renderer.clear();
diff --git a/voxygen/src/anim/src/character/idle.rs b/voxygen/src/anim/src/character/idle.rs
index 5b294b84a1..4a73cede6a 100644
--- a/voxygen/src/anim/src/character/idle.rs
+++ b/voxygen/src/anim/src/character/idle.rs
@@ -1,11 +1,12 @@
 use super::{super::Animation, CharacterSkeleton, SkeletonAttr};
+use common::comp::item::{Hands, ToolKind};
 use std::f32::consts::PI;
 use vek::*;
 
 pub struct IdleAnimation;
 
 impl Animation for IdleAnimation {
-    type Dependency = f64;
+    type Dependency = (Option<ToolKind>, Option<ToolKind>, f64);
     type Skeleton = CharacterSkeleton;
 
     #[cfg(feature = "use-dyn-lib")]
@@ -14,7 +15,7 @@ impl Animation for IdleAnimation {
     #[cfg_attr(feature = "be-dyn-lib", export_name = "character_idle")]
     fn update_skeleton_inner(
         skeleton: &Self::Skeleton,
-        _global_time: f64,
+        (active_tool_kind, second_tool_kind, _global_time): Self::Dependency,
         anim_time: f64,
         _rate: &mut f32,
         skeleton_attr: &SkeletonAttr,
@@ -105,12 +106,41 @@ impl Animation for IdleAnimation {
 
         next.glider.scale = Vec3::one() * 0.0;
 
-        next.main.offset = Vec3::new(-7.0, -5.0, 15.0);
-        next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
-        next.main.scale = Vec3::one() + head_abs * -0.05;
+        match active_tool_kind {
+            Some(ToolKind::Dagger(_)) => {
+                next.main.offset = Vec3::new(-4.0, -5.0, 7.0);
+                next.main.ori =
+                    Quaternion::rotation_y(0.25 * PI) * Quaternion::rotation_z(1.5 * PI);
+            },
+            Some(ToolKind::Shield(_)) => {
+                next.main.offset = Vec3::new(-0.0, -5.0, 3.0);
+                next.main.ori =
+                    Quaternion::rotation_y(0.25 * PI) * Quaternion::rotation_z(-1.5 * PI);
+            },
+            _ => {
+                next.main.offset = Vec3::new(-7.0, -5.0, 15.0);
+                next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
+            },
+        }
+        next.main.scale = Vec3::one();
 
-        next.second.offset = Vec3::new(0.0, 0.0, 0.0);
-        next.second.scale = Vec3::one() * 0.0;
+        match second_tool_kind {
+            Some(ToolKind::Dagger(_)) => {
+                next.second.offset = Vec3::new(4.0, -6.0, 7.0);
+                next.second.ori =
+                    Quaternion::rotation_y(-0.25 * PI) * Quaternion::rotation_z(-1.5 * PI);
+            },
+            Some(ToolKind::Shield(_)) => {
+                next.second.offset = Vec3::new(0.0, -4.0, 3.0);
+                next.second.ori =
+                    Quaternion::rotation_y(-0.25 * PI) * Quaternion::rotation_z(1.5 * PI);
+            },
+            _ => {
+                next.second.offset = Vec3::new(-7.0, -5.0, 15.0);
+                next.second.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
+            },
+        }
+        next.second.scale = Vec3::one();
 
         next.lantern.offset = Vec3::new(
             skeleton_attr.lantern.0,
@@ -135,6 +165,15 @@ impl Animation for IdleAnimation {
         next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
         next.r_control.ori = Quaternion::rotation_x(0.0);
         next.r_control.scale = Vec3::one();
+
+        next.second.scale = match (
+            active_tool_kind.map(|tk| tk.into_hands()),
+            second_tool_kind.map(|tk| tk.into_hands()),
+        ) {
+            (Some(Hands::OneHand), Some(Hands::OneHand)) => Vec3::one(),
+            (_, _) => Vec3::zero(),
+        };
+
         next
     }
 }
diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs
index e57f919023..3deb98c5d8 100644
--- a/voxygen/src/menu/char_selection/mod.rs
+++ b/voxygen/src/menu/char_selection/mod.rs
@@ -117,6 +117,8 @@ impl PlayState for CharSelectionState {
                     }
                 });
 
+            let loadout = self.char_selection_ui.get_loadout();
+
             // Maintain the scene.
             {
                 let client = self.client.borrow();
@@ -133,12 +135,13 @@ impl PlayState for CharSelectionState {
                         .figure_lod_render_distance
                         as f32,
                 };
-                self.scene
-                    .maintain(global_state.window.renderer_mut(), scene_data);
+                self.scene.maintain(
+                    global_state.window.renderer_mut(),
+                    scene_data,
+                    loadout.as_ref(),
+                );
             }
-
             // Render the scene.
-            let loadout = self.char_selection_ui.get_loadout();
             self.scene.render(
                 global_state.window.renderer_mut(),
                 self.client.borrow().get_tick(),
diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs
index 3988e64739..192ffc008e 100644
--- a/voxygen/src/scene/simple.rs
+++ b/voxygen/src/scene/simple.rs
@@ -16,7 +16,7 @@ use anim::{
     Animation, Skeleton,
 };
 use common::{
-    comp::{humanoid, Body, Loadout},
+    comp::{humanoid, item::ItemKind, Body, Loadout},
     figure::Segment,
     terrain::BlockKind,
     vol::{BaseVol, ReadVol, Vox},
@@ -157,7 +157,12 @@ impl Scene {
         }
     }
 
-    pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: SceneData) {
+    pub fn maintain(
+        &mut self,
+        renderer: &mut Renderer,
+        scene_data: SceneData,
+        loadout: Option<&Loadout>,
+    ) {
         self.camera
             .update(scene_data.time, 1.0 / 60.0, scene_data.mouse_smoothing);
 
@@ -191,10 +196,30 @@ impl Scene {
 
         self.figure_model_cache.clean(scene_data.tick);
 
+        let active_item_kind = loadout
+            .and_then(|l| l.active_item.as_ref())
+            .map(|i| &i.item.kind);
+
+        let active_tool_kind = if let Some(ItemKind::Tool(tool)) = active_item_kind {
+            Some(tool.kind)
+        } else {
+            None
+        };
+
+        let second_item_kind = loadout
+            .and_then(|l| l.second_item.as_ref())
+            .map(|i| &i.item.kind);
+
+        let second_tool_kind = if let Some(ItemKind::Tool(tool)) = second_item_kind {
+            Some(tool.kind)
+        } else {
+            None
+        };
+
         if let Some(body) = scene_data.body {
             let tgt_skeleton = IdleAnimation::update_skeleton(
                 self.figure_state.skeleton_mut(),
-                scene_data.time,
+                (active_tool_kind, second_tool_kind, scene_data.time),
                 scene_data.time,
                 &mut 0.0,
                 &SkeletonAttr::from(&body),