From 2a5e66400f4e84b689ea8944c13e096dfda23b6f Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Tue, 4 May 2021 16:12:26 -0400 Subject: [PATCH] Show hitbox cylinders based on actual ECS data, and add a settings toggle in voxygen for it. --- assets/voxygen/i18n/en/hud/hud_settings.ron | 1 + voxygen/src/hud/settings_window/interface.rs | 28 ++++++++- voxygen/src/render/pipelines/debug.rs | 4 +- voxygen/src/scene/debug.rs | 3 +- voxygen/src/session/mod.rs | 65 +++++++++++++++----- voxygen/src/session/settings_change.rs | 4 ++ voxygen/src/settings/interface.rs | 2 + 7 files changed, 86 insertions(+), 21 deletions(-) diff --git a/assets/voxygen/i18n/en/hud/hud_settings.ron b/assets/voxygen/i18n/en/hud/hud_settings.ron index 1160fd6c17..24023e2ba3 100644 --- a/assets/voxygen/i18n/en/hud/hud_settings.ron +++ b/assets/voxygen/i18n/en/hud/hud_settings.ron @@ -10,6 +10,7 @@ "hud.settings.press_behavior.hold": "Hold", "hud.settings.help_window": "Help Window", "hud.settings.debug_info": "Debug Info", + "hud.settings.show_hitboxes": "Show hitboxes", "hud.settings.tips_on_startup": "Tips-On-Startup", "hud.settings.ui_scale": "UI-Scale", "hud.settings.relative_scaling": "Relative Scaling", diff --git a/voxygen/src/hud/settings_window/interface.rs b/voxygen/src/hud/settings_window/interface.rs index 0d67613e96..4a4c5cb32f 100644 --- a/voxygen/src/hud/settings_window/interface.rs +++ b/voxygen/src/hud/settings_window/interface.rs @@ -36,6 +36,8 @@ widget_ids! { load_tips_button_label, debug_button, debug_button_label, + hitboxes_button, + hitboxes_button_label, ch_title, ch_transp_slider, ch_transp_value, @@ -239,9 +241,33 @@ impl<'a> Widget for Interface<'a> { .color(TEXT_COLOR) .set(state.ids.debug_button_label, ui); + // Hitboxes + let show_hitboxes = ToggleButton::new( + self.global_state.settings.interface.toggle_hitboxes, + self.imgs.checkbox, + self.imgs.checkbox_checked, + ) + .w_h(18.0, 18.0) + .down_from(state.ids.debug_button, 8.0) + .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) + .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) + .set(state.ids.hitboxes_button, ui); + + if self.global_state.settings.interface.toggle_hitboxes != show_hitboxes { + events.push(ToggleHitboxes(show_hitboxes)); + } + + Text::new(&self.localized_strings.get("hud.settings.show_hitboxes")) + .right_from(state.ids.hitboxes_button, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .graphics_for(state.ids.hitboxes_button) + .color(TEXT_COLOR) + .set(state.ids.hitboxes_button_label, ui); + // Ui Scale Text::new(&self.localized_strings.get("hud.settings.ui_scale")) - .down_from(state.ids.debug_button, 20.0) + .down_from(state.ids.hitboxes_button, 20.0) .font_size(self.fonts.cyri.scale(18)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) diff --git a/voxygen/src/render/pipelines/debug.rs b/voxygen/src/render/pipelines/debug.rs index 3c8dd51032..8318b5691d 100644 --- a/voxygen/src/render/pipelines/debug.rs +++ b/voxygen/src/render/pipelines/debug.rs @@ -1,6 +1,4 @@ -use super::{ - super::{AaMode, Bound, Consts, GlobalsLayouts, Vertex as VertexTrait}, -}; +use super::super::{AaMode, Bound, Consts, GlobalsLayouts, Vertex as VertexTrait}; use bytemuck::{Pod, Zeroable}; use std::mem; use vek::*; diff --git a/voxygen/src/scene/debug.rs b/voxygen/src/scene/debug.rs index 507d40b62b..428272b979 100644 --- a/voxygen/src/scene/debug.rs +++ b/voxygen/src/scene/debug.rs @@ -1,6 +1,5 @@ use crate::render::{ - Bound, Consts, DebugLocals, DebugVertex, FirstPassDrawer, Mesh, - Model, Quad, Renderer, Tri, + Bound, Consts, DebugLocals, DebugVertex, FirstPassDrawer, Mesh, Model, Quad, Renderer, Tri, }; use hashbrown::{HashMap, HashSet}; use vek::*; diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index 9d8bfa6b1c..ccd5b1c683 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -44,6 +44,7 @@ use crate::{ window::{AnalogGameInput, Event, GameInput}, Direction, Error, GlobalState, PlayState, PlayStateResult, }; +use hashbrown::HashMap; use settings_change::Language::ChangeLanguage; /// The action to perform after a tick @@ -73,7 +74,7 @@ pub struct SessionState { selected_entity: Option<(specs::Entity, std::time::Instant)>, interactable: Option, saved_zoom_dist: Option, - player_hitbox: DebugShapeId, + hitboxes: HashMap, } /// Represents an active game session (i.e., the one being played). @@ -101,10 +102,6 @@ impl SessionState { let hud = Hud::new(global_state, &client.borrow()); let walk_forward_dir = scene.camera().forward_xy(); let walk_right_dir = scene.camera().right_xy(); - let player_hitbox = scene.debug.add_shape(DebugShape::Cylinder { - radius: 0.4, - height: 1.75, - }); Self { scene, @@ -125,7 +122,7 @@ impl SessionState { selected_entity: None, interactable: None, saved_zoom_dist: None, - player_hitbox, + hitboxes: HashMap::new(), } } @@ -145,16 +142,54 @@ impl SessionState { span!(_guard, "tick", "Session::tick"); let mut client = self.client.borrow_mut(); - if let Some(player_pos) = client - .state() - .ecs() - .read_component::() - .get(client.entity()) { - let pos = [player_pos.0.x, player_pos.0.y, player_pos.0.z, 0.0]; - self.scene - .debug - .set_pos_and_color(self.player_hitbox, pos, [1.0, 0.0, 0.0, 0.5]); + let ecs = client.state().ecs(); + let mut current_entities = hashbrown::HashSet::new(); + let scene = &mut self.scene; + let hitboxes = &mut self.hitboxes; + if global_state.settings.interface.toggle_hitboxes { + let positions = ecs.read_component::(); + let colliders = ecs.read_component::(); + let groups = ecs.read_component::(); + for (entity, pos, collider, group) in + (&ecs.entities(), &positions, &colliders, groups.maybe()).join() + { + if let comp::Collider::Box { + radius, + z_min, + z_max, + } = collider + { + current_entities.insert(entity); + let shape_id = hitboxes.entry(entity).or_insert_with(|| { + scene.debug.add_shape(DebugShape::Cylinder { + radius: *radius, + height: *z_max - *z_min, + }) + }); + let hb_pos = [pos.0.x, pos.0.y, pos.0.z + *z_min, 0.0]; + let color = if group == Some(&comp::group::ENEMY) { + [1.0, 0.0, 0.0, 0.5] + } else if group == Some(&comp::group::NPC) { + [0.0, 0.0, 1.0, 0.5] + } else { + [0.0, 1.0, 0.0, 0.5] + }; + scene.debug.set_pos_and_color(*shape_id, hb_pos, color); + } + } + } + let mut to_remove = Vec::new(); + hitboxes.retain(|k, v| { + let keep = current_entities.contains(k); + if !keep { + to_remove.push(*v); + } + keep + }); + for shape_id in to_remove.into_iter() { + scene.debug.remove_shape(shape_id); + } } for event in client.tick(self.inputs.clone(), dt, crate::ecs::sys::add_local_systems)? { match event { diff --git a/voxygen/src/session/settings_change.rs b/voxygen/src/session/settings_change.rs index db4cc70b0e..e46627b347 100644 --- a/voxygen/src/session/settings_change.rs +++ b/voxygen/src/session/settings_change.rs @@ -96,6 +96,7 @@ pub enum Interface { SpeechBubbleIcon(bool), ToggleHelp(bool), ToggleDebug(bool), + ToggleHitboxes(bool), ToggleTips(bool), CrosshairTransp(f32), @@ -445,6 +446,9 @@ impl SettingsChange { Interface::ToggleDebug(toggle_debug) => { settings.interface.toggle_debug = toggle_debug; }, + Interface::ToggleHitboxes(toggle_hitboxes) => { + settings.interface.toggle_hitboxes = toggle_hitboxes; + }, Interface::ToggleTips(loading_tips) => { settings.interface.loading_tips = loading_tips; }, diff --git a/voxygen/src/settings/interface.rs b/voxygen/src/settings/interface.rs index 4e898a9977..c0dd4fa9b6 100644 --- a/voxygen/src/settings/interface.rs +++ b/voxygen/src/settings/interface.rs @@ -10,6 +10,7 @@ use vek::*; #[serde(default)] pub struct InterfaceSettings { pub toggle_debug: bool, + pub toggle_hitboxes: bool, pub sct: bool, pub sct_player_batch: bool, pub sct_damage_batch: bool, @@ -43,6 +44,7 @@ impl Default for InterfaceSettings { fn default() -> Self { Self { toggle_debug: false, + toggle_hitboxes: false, sct: true, sct_player_batch: false, sct_damage_batch: false,