mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
character viewpoint
This commit is contained in:
parent
bf44ebd12b
commit
a165bc09bc
@ -64,4 +64,5 @@ gameinput-mapzoomin = Increase map zoom
|
|||||||
gameinput-mapzoomout = Decrease map zoom
|
gameinput-mapzoomout = Decrease map zoom
|
||||||
gameinput-greet = Greet
|
gameinput-greet = Greet
|
||||||
gameinput-map-locationmarkerbutton = Set a waypoint in the Map
|
gameinput-map-locationmarkerbutton = Set a waypoint in the Map
|
||||||
gameinput-spectatespeedboost = Spectate speed boost
|
gameinput-spectatespeedboost = Spectate speed boost
|
||||||
|
gameinput-spectateviewpoint = Spectate viewpoint
|
@ -150,6 +150,8 @@ pub enum GameInput {
|
|||||||
MapSetMarker,
|
MapSetMarker,
|
||||||
#[strum(serialize = "gameinput.spectatespeedboost")]
|
#[strum(serialize = "gameinput.spectatespeedboost")]
|
||||||
SpectateSpeedBoost,
|
SpectateSpeedBoost,
|
||||||
|
#[strum(serialize = "gameinput.spectateviewpoint")]
|
||||||
|
SpectateViewpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameInput {
|
impl GameInput {
|
||||||
|
@ -3,7 +3,7 @@ use super::{
|
|||||||
img_ids::{Imgs, ImgsRot},
|
img_ids::{Imgs, ImgsRot},
|
||||||
item_imgs::ItemImgs,
|
item_imgs::ItemImgs,
|
||||||
slots::{ArmorSlot, EquipSlot, InventorySlot, SlotManager},
|
slots::{ArmorSlot, EquipSlot, InventorySlot, SlotManager},
|
||||||
Show, CRITICAL_HP_COLOR, LOW_HP_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
HudInfo, Show, CRITICAL_HP_COLOR, LOW_HP_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
game_input::GameInput,
|
game_input::GameInput,
|
||||||
@ -563,6 +563,7 @@ widget_ids! {
|
|||||||
#[derive(WidgetCommon)]
|
#[derive(WidgetCommon)]
|
||||||
pub struct Bag<'a> {
|
pub struct Bag<'a> {
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
global_state: &'a GlobalState,
|
global_state: &'a GlobalState,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
@ -589,6 +590,7 @@ impl<'a> Bag<'a> {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
global_state: &'a GlobalState,
|
global_state: &'a GlobalState,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
@ -610,6 +612,7 @@ impl<'a> Bag<'a> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client,
|
client,
|
||||||
|
info,
|
||||||
global_state,
|
global_state,
|
||||||
imgs,
|
imgs,
|
||||||
item_imgs,
|
item_imgs,
|
||||||
@ -695,7 +698,7 @@ impl<'a> Widget for Bag<'a> {
|
|||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.desc_text_color(TEXT_COLOR);
|
.desc_text_color(TEXT_COLOR);
|
||||||
let inventories = self.client.inventories();
|
let inventories = self.client.inventories();
|
||||||
let inventory = match inventories.get(self.client.entity()) {
|
let inventory = match inventories.get(self.info.viewpoint_entity) {
|
||||||
Some(l) => l,
|
Some(l) => l,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
@ -733,6 +736,7 @@ impl<'a> Widget for Bag<'a> {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
self.client,
|
self.client,
|
||||||
|
self.info,
|
||||||
self.imgs,
|
self.imgs,
|
||||||
self.item_imgs,
|
self.item_imgs,
|
||||||
self.pulse,
|
self.pulse,
|
||||||
@ -759,7 +763,7 @@ impl<'a> Widget for Bag<'a> {
|
|||||||
true,
|
true,
|
||||||
&item_tooltip,
|
&item_tooltip,
|
||||||
self.stats.name.to_string(),
|
self.stats.name.to_string(),
|
||||||
self.client.entity(),
|
self.info.viewpoint_entity,
|
||||||
true,
|
true,
|
||||||
inventory,
|
inventory,
|
||||||
&state.bg_ids,
|
&state.bg_ids,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
img_ids::{Imgs, ImgsRot},
|
img_ids::{Imgs, ImgsRot},
|
||||||
BLACK, CRITICAL_HP_COLOR, LOW_HP_COLOR, QUALITY_LEGENDARY, TEXT_COLOR,
|
HudInfo, BLACK, CRITICAL_HP_COLOR, LOW_HP_COLOR, QUALITY_LEGENDARY, TEXT_COLOR,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
game_input::GameInput,
|
game_input::GameInput,
|
||||||
@ -51,6 +51,7 @@ widget_ids! {
|
|||||||
#[derive(WidgetCommon)]
|
#[derive(WidgetCommon)]
|
||||||
pub struct Buttons<'a> {
|
pub struct Buttons<'a> {
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
show_bag: bool,
|
show_bag: bool,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
@ -68,6 +69,7 @@ pub struct Buttons<'a> {
|
|||||||
impl<'a> Buttons<'a> {
|
impl<'a> Buttons<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
show_bag: bool,
|
show_bag: bool,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
@ -81,6 +83,7 @@ impl<'a> Buttons<'a> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client,
|
client,
|
||||||
|
info,
|
||||||
show_bag,
|
show_bag,
|
||||||
imgs,
|
imgs,
|
||||||
fonts,
|
fonts,
|
||||||
@ -192,7 +195,7 @@ impl<'a> Widget for Buttons<'a> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let invs = self.client.inventories();
|
let invs = self.client.inventories();
|
||||||
let inventory = match invs.get(self.client.entity()) {
|
let inventory = match invs.get(self.info.viewpoint_entity) {
|
||||||
Some(inv) => inv,
|
Some(inv) => inv,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,7 @@ use super::{
|
|||||||
img_ids::{Imgs, ImgsRot},
|
img_ids::{Imgs, ImgsRot},
|
||||||
item_imgs::{animate_by_pulse, ItemImgs},
|
item_imgs::{animate_by_pulse, ItemImgs},
|
||||||
slots::{CraftSlot, CraftSlotInfo, SlotManager},
|
slots::{CraftSlot, CraftSlotInfo, SlotManager},
|
||||||
Show, TEXT_COLOR, TEXT_DULL_RED_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
HudInfo, Show, TEXT_COLOR, TEXT_DULL_RED_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||||
};
|
};
|
||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
fonts::Fonts,
|
fonts::Fonts,
|
||||||
@ -137,6 +137,7 @@ impl Default for CraftingShow {
|
|||||||
#[derive(WidgetCommon)]
|
#[derive(WidgetCommon)]
|
||||||
pub struct Crafting<'a> {
|
pub struct Crafting<'a> {
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
localized_strings: &'a Localization,
|
localized_strings: &'a Localization,
|
||||||
@ -156,6 +157,7 @@ pub struct Crafting<'a> {
|
|||||||
impl<'a> Crafting<'a> {
|
impl<'a> Crafting<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
localized_strings: &'a Localization,
|
localized_strings: &'a Localization,
|
||||||
@ -171,6 +173,7 @@ impl<'a> Crafting<'a> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client,
|
client,
|
||||||
|
info,
|
||||||
imgs,
|
imgs,
|
||||||
fonts,
|
fonts,
|
||||||
localized_strings,
|
localized_strings,
|
||||||
@ -321,6 +324,7 @@ impl<'a> Widget for Crafting<'a> {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
self.client,
|
self.client,
|
||||||
|
self.info,
|
||||||
self.imgs,
|
self.imgs,
|
||||||
self.item_imgs,
|
self.item_imgs,
|
||||||
self.pulse,
|
self.pulse,
|
||||||
|
@ -4,6 +4,8 @@ use common::comp::{
|
|||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::HudInfo;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub enum Slot {
|
pub enum Slot {
|
||||||
One = 0,
|
One = 0,
|
||||||
@ -63,22 +65,22 @@ impl State {
|
|||||||
// TODO: remove pending UI
|
// TODO: remove pending UI
|
||||||
// Adds ability slots if missing and should be present
|
// Adds ability slots if missing and should be present
|
||||||
// Removes ability slots if not there and shouldn't be present
|
// Removes ability slots if not there and shouldn't be present
|
||||||
pub fn maintain_abilities(&mut self, client: &client::Client) {
|
pub fn maintain_abilities(&mut self, client: &client::Client, info: &HudInfo) {
|
||||||
use specs::WorldExt;
|
use specs::WorldExt;
|
||||||
if let Some(active_abilities) = client
|
if let Some(active_abilities) = client
|
||||||
.state()
|
.state()
|
||||||
.ecs()
|
.ecs()
|
||||||
.read_storage::<comp::ActiveAbilities>()
|
.read_storage::<comp::ActiveAbilities>()
|
||||||
.get(client.entity())
|
.get(info.viewpoint_entity)
|
||||||
{
|
{
|
||||||
use common::comp::ability::AuxiliaryAbility;
|
use common::comp::ability::AuxiliaryAbility;
|
||||||
for ((i, ability), hotbar_slot) in active_abilities
|
for ((i, ability), hotbar_slot) in active_abilities
|
||||||
.auxiliary_set(
|
.auxiliary_set(
|
||||||
client.inventories().get(client.entity()),
|
client.inventories().get(info.viewpoint_entity),
|
||||||
client
|
client
|
||||||
.state()
|
.state()
|
||||||
.read_storage::<comp::SkillSet>()
|
.read_storage::<comp::SkillSet>()
|
||||||
.get(client.entity()),
|
.get(info.viewpoint_entity),
|
||||||
)
|
)
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -2,7 +2,7 @@ use super::{
|
|||||||
animate_by_pulse, get_quality_col,
|
animate_by_pulse, get_quality_col,
|
||||||
img_ids::{Imgs, ImgsRot},
|
img_ids::{Imgs, ImgsRot},
|
||||||
item_imgs::ItemImgs,
|
item_imgs::ItemImgs,
|
||||||
Show, Windows, TEXT_COLOR,
|
HudInfo, Show, Windows, TEXT_COLOR,
|
||||||
};
|
};
|
||||||
use crate::ui::{fonts::Fonts, ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable};
|
use crate::ui::{fonts::Fonts, ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
@ -51,6 +51,7 @@ pub struct LootScroller<'a> {
|
|||||||
new_messages: &'a mut VecDeque<LootMessage>,
|
new_messages: &'a mut VecDeque<LootMessage>,
|
||||||
|
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
show: &'a Show,
|
show: &'a Show,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
@ -68,6 +69,7 @@ impl<'a> LootScroller<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
new_messages: &'a mut VecDeque<LootMessage>,
|
new_messages: &'a mut VecDeque<LootMessage>,
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
show: &'a Show,
|
show: &'a Show,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
@ -81,6 +83,7 @@ impl<'a> LootScroller<'a> {
|
|||||||
Self {
|
Self {
|
||||||
new_messages,
|
new_messages,
|
||||||
client,
|
client,
|
||||||
|
info,
|
||||||
show,
|
show,
|
||||||
imgs,
|
imgs,
|
||||||
item_imgs,
|
item_imgs,
|
||||||
@ -143,6 +146,7 @@ impl<'a> Widget for LootScroller<'a> {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
self.client,
|
self.client,
|
||||||
|
self.info,
|
||||||
self.imgs,
|
self.imgs,
|
||||||
self.item_imgs,
|
self.item_imgs,
|
||||||
self.pulse,
|
self.pulse,
|
||||||
|
@ -501,6 +501,8 @@ pub struct DebugInfo {
|
|||||||
pub struct HudInfo {
|
pub struct HudInfo {
|
||||||
pub is_aiming: bool,
|
pub is_aiming: bool,
|
||||||
pub is_first_person: bool,
|
pub is_first_person: bool,
|
||||||
|
pub viewpoint_entity: specs::Entity,
|
||||||
|
pub mutable_viewpoint: bool,
|
||||||
pub target_entity: Option<specs::Entity>,
|
pub target_entity: Option<specs::Entity>,
|
||||||
pub selected_entity: Option<(specs::Entity, Instant)>,
|
pub selected_entity: Option<(specs::Entity, Instant)>,
|
||||||
}
|
}
|
||||||
@ -1278,7 +1280,7 @@ impl Hud {
|
|||||||
let players = ecs.read_storage::<comp::Player>();
|
let players = ecs.read_storage::<comp::Player>();
|
||||||
let msm = ecs.read_resource::<MaterialStatManifest>();
|
let msm = ecs.read_resource::<MaterialStatManifest>();
|
||||||
let entities = ecs.entities();
|
let entities = ecs.entities();
|
||||||
let me = client.entity();
|
let me = info.viewpoint_entity;
|
||||||
let poises = ecs.read_storage::<comp::Poise>();
|
let poises = ecs.read_storage::<comp::Poise>();
|
||||||
let alignments = ecs.read_storage::<comp::Alignment>();
|
let alignments = ecs.read_storage::<comp::Alignment>();
|
||||||
let is_mount = ecs.read_storage::<Is<Mount>>();
|
let is_mount = ecs.read_storage::<Is<Mount>>();
|
||||||
@ -2585,7 +2587,7 @@ impl Hud {
|
|||||||
|
|
||||||
// Bag button and nearby icons
|
// Bag button and nearby icons
|
||||||
let ecs = client.state().ecs();
|
let ecs = client.state().ecs();
|
||||||
let entity = client.entity();
|
let entity = info.viewpoint_entity;
|
||||||
let stats = ecs.read_storage::<comp::Stats>();
|
let stats = ecs.read_storage::<comp::Stats>();
|
||||||
let skill_sets = ecs.read_storage::<comp::SkillSet>();
|
let skill_sets = ecs.read_storage::<comp::SkillSet>();
|
||||||
let buffs = ecs.read_storage::<comp::Buffs>();
|
let buffs = ecs.read_storage::<comp::Buffs>();
|
||||||
@ -2593,6 +2595,7 @@ impl Hud {
|
|||||||
if let (Some(player_stats), Some(skill_set)) = (stats.get(entity), skill_sets.get(entity)) {
|
if let (Some(player_stats), Some(skill_set)) = (stats.get(entity), skill_sets.get(entity)) {
|
||||||
match Buttons::new(
|
match Buttons::new(
|
||||||
client,
|
client,
|
||||||
|
&info,
|
||||||
self.show.bag,
|
self.show.bag,
|
||||||
&self.imgs,
|
&self.imgs,
|
||||||
&self.fonts,
|
&self.fonts,
|
||||||
@ -2705,14 +2708,12 @@ impl Hud {
|
|||||||
// Skillbar
|
// Skillbar
|
||||||
// Get player stats
|
// Get player stats
|
||||||
let ecs = client.state().ecs();
|
let ecs = client.state().ecs();
|
||||||
let entity = client.entity();
|
let entity = info.viewpoint_entity;
|
||||||
let healths = ecs.read_storage::<Health>();
|
let healths = ecs.read_storage::<Health>();
|
||||||
let inventories = ecs.read_storage::<comp::Inventory>();
|
let inventories = ecs.read_storage::<comp::Inventory>();
|
||||||
let energies = ecs.read_storage::<comp::Energy>();
|
let energies = ecs.read_storage::<comp::Energy>();
|
||||||
let skillsets = ecs.read_storage::<comp::SkillSet>();
|
let skillsets = ecs.read_storage::<comp::SkillSet>();
|
||||||
let active_abilities = ecs.read_storage::<comp::ActiveAbilities>();
|
let active_abilities = ecs.read_storage::<comp::ActiveAbilities>();
|
||||||
let character_states = ecs.read_storage::<comp::CharacterState>();
|
|
||||||
let controllers = ecs.read_storage::<comp::Controller>();
|
|
||||||
let bodies = ecs.read_storage::<comp::Body>();
|
let bodies = ecs.read_storage::<comp::Body>();
|
||||||
let poises = ecs.read_storage::<comp::Poise>();
|
let poises = ecs.read_storage::<comp::Poise>();
|
||||||
// Combo floater stuffs
|
// Combo floater stuffs
|
||||||
@ -2722,25 +2723,16 @@ impl Hud {
|
|||||||
});
|
});
|
||||||
self.floaters.combo_floater = self.floaters.combo_floater.filter(|f| f.timer > 0_f64);
|
self.floaters.combo_floater = self.floaters.combo_floater.filter(|f| f.timer > 0_f64);
|
||||||
|
|
||||||
if let (
|
if let (Some(health), Some(inventory), Some(energy), Some(skillset), Some(body)) = (
|
||||||
Some(health),
|
|
||||||
Some(inventory),
|
|
||||||
Some(energy),
|
|
||||||
Some(skillset),
|
|
||||||
Some(body),
|
|
||||||
Some(_character_state),
|
|
||||||
Some(_controller),
|
|
||||||
) = (
|
|
||||||
healths.get(entity),
|
healths.get(entity),
|
||||||
inventories.get(entity),
|
inventories.get(entity),
|
||||||
energies.get(entity),
|
energies.get(entity),
|
||||||
skillsets.get(entity),
|
skillsets.get(entity),
|
||||||
bodies.get(entity),
|
bodies.get(entity),
|
||||||
character_states.get(entity),
|
|
||||||
controllers.get(entity).map(|c| &c.inputs),
|
|
||||||
) {
|
) {
|
||||||
Skillbar::new(
|
Skillbar::new(
|
||||||
client,
|
client,
|
||||||
|
&info,
|
||||||
global_state,
|
global_state,
|
||||||
&self.imgs,
|
&self.imgs,
|
||||||
&self.item_imgs,
|
&self.item_imgs,
|
||||||
@ -2775,8 +2767,8 @@ impl Hud {
|
|||||||
Some(body),
|
Some(body),
|
||||||
Some(poise),
|
Some(poise),
|
||||||
) = (
|
) = (
|
||||||
stats.get(client.entity()),
|
stats.get(info.viewpoint_entity),
|
||||||
skill_sets.get(client.entity()),
|
skill_sets.get(info.viewpoint_entity),
|
||||||
healths.get(entity),
|
healths.get(entity),
|
||||||
energies.get(entity),
|
energies.get(entity),
|
||||||
bodies.get(entity),
|
bodies.get(entity),
|
||||||
@ -2784,6 +2776,7 @@ impl Hud {
|
|||||||
) {
|
) {
|
||||||
match Bag::new(
|
match Bag::new(
|
||||||
client,
|
client,
|
||||||
|
&info,
|
||||||
global_state,
|
global_state,
|
||||||
&self.imgs,
|
&self.imgs,
|
||||||
&self.item_imgs,
|
&self.item_imgs,
|
||||||
@ -2828,6 +2821,7 @@ impl Hud {
|
|||||||
if self.show.trade {
|
if self.show.trade {
|
||||||
if let Some(action) = Trade::new(
|
if let Some(action) = Trade::new(
|
||||||
client,
|
client,
|
||||||
|
&info,
|
||||||
&self.imgs,
|
&self.imgs,
|
||||||
&self.item_imgs,
|
&self.item_imgs,
|
||||||
&self.fonts,
|
&self.fonts,
|
||||||
@ -2871,14 +2865,10 @@ impl Hud {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Buffs
|
// Buffs
|
||||||
let ecs = client.state().ecs();
|
|
||||||
let entity = client.entity();
|
|
||||||
let health = ecs.read_storage::<Health>();
|
|
||||||
let energy = ecs.read_storage::<comp::Energy>();
|
|
||||||
if let (Some(player_buffs), Some(health), Some(energy)) = (
|
if let (Some(player_buffs), Some(health), Some(energy)) = (
|
||||||
buffs.get(client.entity()),
|
buffs.get(info.viewpoint_entity),
|
||||||
health.get(entity),
|
healths.get(entity),
|
||||||
energy.get(entity),
|
energies.get(entity),
|
||||||
) {
|
) {
|
||||||
for event in BuffsBar::new(
|
for event in BuffsBar::new(
|
||||||
&self.imgs,
|
&self.imgs,
|
||||||
@ -2905,6 +2895,7 @@ impl Hud {
|
|||||||
for event in Crafting::new(
|
for event in Crafting::new(
|
||||||
//&self.show,
|
//&self.show,
|
||||||
client,
|
client,
|
||||||
|
&info,
|
||||||
&self.imgs,
|
&self.imgs,
|
||||||
&self.fonts,
|
&self.fonts,
|
||||||
&*i18n,
|
&*i18n,
|
||||||
@ -3038,6 +3029,7 @@ impl Hud {
|
|||||||
LootScroller::new(
|
LootScroller::new(
|
||||||
&mut self.new_loot_messages,
|
&mut self.new_loot_messages,
|
||||||
client,
|
client,
|
||||||
|
&info,
|
||||||
&self.show,
|
&self.show,
|
||||||
&self.imgs,
|
&self.imgs,
|
||||||
&self.item_imgs,
|
&self.item_imgs,
|
||||||
@ -3107,49 +3099,45 @@ impl Hud {
|
|||||||
if self.show.social {
|
if self.show.social {
|
||||||
let ecs = client.state().ecs();
|
let ecs = client.state().ecs();
|
||||||
let _stats = ecs.read_storage::<comp::Stats>();
|
let _stats = ecs.read_storage::<comp::Stats>();
|
||||||
let me = client.entity();
|
for event in Social::new(
|
||||||
if let Some(_stats) = stats.get(me) {
|
&self.show,
|
||||||
for event in Social::new(
|
client,
|
||||||
&self.show,
|
&self.imgs,
|
||||||
client,
|
&self.fonts,
|
||||||
&self.imgs,
|
i18n,
|
||||||
&self.fonts,
|
info.selected_entity,
|
||||||
i18n,
|
&self.rot_imgs,
|
||||||
info.selected_entity,
|
tooltip_manager,
|
||||||
&self.rot_imgs,
|
)
|
||||||
tooltip_manager,
|
.set(self.ids.social_window, ui_widgets)
|
||||||
)
|
{
|
||||||
.set(self.ids.social_window, ui_widgets)
|
match event {
|
||||||
{
|
social::Event::Close => {
|
||||||
match event {
|
self.show.social(false);
|
||||||
social::Event::Close => {
|
if !self.show.bag {
|
||||||
self.show.social(false);
|
self.show.want_grab = true;
|
||||||
if !self.show.bag {
|
self.force_ungrab = false;
|
||||||
self.show.want_grab = true;
|
} else {
|
||||||
self.force_ungrab = false;
|
self.force_ungrab = true
|
||||||
} else {
|
};
|
||||||
self.force_ungrab = true
|
},
|
||||||
};
|
social::Event::Focus(widget_id) => {
|
||||||
},
|
self.to_focus = Some(Some(widget_id));
|
||||||
social::Event::Focus(widget_id) => {
|
},
|
||||||
self.to_focus = Some(Some(widget_id));
|
social::Event::Invite(uid) => events.push(Event::InviteMember(uid)),
|
||||||
},
|
social::Event::SearchPlayers(search_key) => {
|
||||||
social::Event::Invite(uid) => events.push(Event::InviteMember(uid)),
|
self.show.search_social_players(search_key)
|
||||||
social::Event::SearchPlayers(search_key) => {
|
},
|
||||||
self.show.search_social_players(search_key)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diary
|
// Diary
|
||||||
if self.show.diary {
|
if self.show.diary {
|
||||||
let entity = client.entity();
|
let entity = info.viewpoint_entity;
|
||||||
let skill_sets = ecs.read_storage::<comp::SkillSet>();
|
let skill_sets = ecs.read_storage::<comp::SkillSet>();
|
||||||
if let (
|
if let (
|
||||||
Some(skill_set),
|
Some(skill_set),
|
||||||
Some(active_abilities),
|
|
||||||
Some(inventory),
|
Some(inventory),
|
||||||
Some(health),
|
Some(health),
|
||||||
Some(energy),
|
Some(energy),
|
||||||
@ -3157,7 +3145,6 @@ impl Hud {
|
|||||||
Some(poise),
|
Some(poise),
|
||||||
) = (
|
) = (
|
||||||
skill_sets.get(entity),
|
skill_sets.get(entity),
|
||||||
active_abilities.get(entity),
|
|
||||||
inventories.get(entity),
|
inventories.get(entity),
|
||||||
healths.get(entity),
|
healths.get(entity),
|
||||||
energies.get(entity),
|
energies.get(entity),
|
||||||
@ -3169,7 +3156,7 @@ impl Hud {
|
|||||||
client,
|
client,
|
||||||
global_state,
|
global_state,
|
||||||
skill_set,
|
skill_set,
|
||||||
active_abilities,
|
active_abilities.get(entity).unwrap_or(&Default::default()),
|
||||||
inventory,
|
inventory,
|
||||||
health,
|
health,
|
||||||
energy,
|
energy,
|
||||||
@ -3386,7 +3373,7 @@ impl Hud {
|
|||||||
) = (a, b)
|
) = (a, b)
|
||||||
{
|
{
|
||||||
if let Some(item) = inventories
|
if let Some(item) = inventories
|
||||||
.get(client.entity())
|
.get(info.viewpoint_entity)
|
||||||
.and_then(|inv| inv.get(slot))
|
.and_then(|inv| inv.get(slot))
|
||||||
{
|
{
|
||||||
self.hotbar.add_inventory_link(h, item);
|
self.hotbar.add_inventory_link(h, item);
|
||||||
@ -3423,7 +3410,7 @@ impl Hud {
|
|||||||
events.push(Event::ChangeAbility(index, ability));
|
events.push(Event::ChangeAbility(index, ability));
|
||||||
},
|
},
|
||||||
(AbilitySlot::Slot(a), AbilitySlot::Slot(b)) => {
|
(AbilitySlot::Slot(a), AbilitySlot::Slot(b)) => {
|
||||||
let me = client.entity();
|
let me = info.viewpoint_entity;
|
||||||
if let Some(active_abilities) = active_abilities.get(me) {
|
if let Some(active_abilities) = active_abilities.get(me) {
|
||||||
let ability_a = active_abilities
|
let ability_a = active_abilities
|
||||||
.auxiliary_set(inventories.get(me), skill_sets.get(me))
|
.auxiliary_set(inventories.get(me), skill_sets.get(me))
|
||||||
@ -3447,7 +3434,7 @@ impl Hud {
|
|||||||
} else if let (Inventory(i), Crafting(c)) = (a, b) {
|
} else if let (Inventory(i), Crafting(c)) = (a, b) {
|
||||||
// Add item to crafting input
|
// Add item to crafting input
|
||||||
if inventories
|
if inventories
|
||||||
.get(client.entity())
|
.get(info.viewpoint_entity)
|
||||||
.and_then(|inv| inv.get(i.slot))
|
.and_then(|inv| inv.get(i.slot))
|
||||||
.map_or(false, |item| {
|
.map_or(false, |item| {
|
||||||
(c.requirement)(item, client.component_recipe_book(), c.info)
|
(c.requirement)(item, client.component_recipe_book(), c.info)
|
||||||
@ -3508,7 +3495,7 @@ impl Hud {
|
|||||||
});
|
});
|
||||||
} else if let (Inventory(i), Hotbar(h)) = (a, b) {
|
} else if let (Inventory(i), Hotbar(h)) = (a, b) {
|
||||||
if let Some(item) = inventories
|
if let Some(item) = inventories
|
||||||
.get(client.entity())
|
.get(info.viewpoint_entity)
|
||||||
.and_then(|inv| inv.get(i.slot))
|
.and_then(|inv| inv.get(i.slot))
|
||||||
{
|
{
|
||||||
self.hotbar.add_inventory_link(h, item);
|
self.hotbar.add_inventory_link(h, item);
|
||||||
@ -3545,7 +3532,7 @@ impl Hud {
|
|||||||
events.push(Event::ChangeAbility(index, ability));
|
events.push(Event::ChangeAbility(index, ability));
|
||||||
},
|
},
|
||||||
(AbilitySlot::Slot(a), AbilitySlot::Slot(b)) => {
|
(AbilitySlot::Slot(a), AbilitySlot::Slot(b)) => {
|
||||||
let me = client.entity();
|
let me = info.viewpoint_entity;
|
||||||
if let Some(active_abilities) = active_abilities.get(me) {
|
if let Some(active_abilities) = active_abilities.get(me) {
|
||||||
let ability_a = active_abilities
|
let ability_a = active_abilities
|
||||||
.auxiliary_set(inventories.get(me), skill_sets.get(me))
|
.auxiliary_set(inventories.get(me), skill_sets.get(me))
|
||||||
@ -3592,7 +3579,7 @@ impl Hud {
|
|||||||
// Used from hotbar
|
// Used from hotbar
|
||||||
self.hotbar.get(h).map(|s| match s {
|
self.hotbar.get(h).map(|s| match s {
|
||||||
hotbar::SlotContents::Inventory(i, _) => {
|
hotbar::SlotContents::Inventory(i, _) => {
|
||||||
if let Some(inv) = inventories.get(client.entity()) {
|
if let Some(inv) = inventories.get(info.viewpoint_entity) {
|
||||||
// If the item in the inactive main hand is the same as the item
|
// If the item in the inactive main hand is the same as the item
|
||||||
// pressed in the hotbar, then swap active and inactive hands
|
// pressed in the hotbar, then swap active and inactive hands
|
||||||
// instead of looking for
|
// instead of looking for
|
||||||
@ -3643,7 +3630,7 @@ impl Hud {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
let who = match ecs
|
let who = match ecs
|
||||||
.uid_from_entity(client.entity())
|
.uid_from_entity(info.viewpoint_entity)
|
||||||
.and_then(|uid| trade.which_party(uid))
|
.and_then(|uid| trade.which_party(uid))
|
||||||
{
|
{
|
||||||
Some(who) => who,
|
Some(who) => who,
|
||||||
@ -3752,7 +3739,7 @@ impl Hud {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.hotbar.maintain_abilities(client);
|
self.hotbar.maintain_abilities(client, &info);
|
||||||
|
|
||||||
// Temporary Example Quest
|
// Temporary Example Quest
|
||||||
let arrow_ani = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.8; //Animation timer
|
let arrow_ani = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.8; //Animation timer
|
||||||
|
@ -2,8 +2,8 @@ use super::{
|
|||||||
hotbar,
|
hotbar,
|
||||||
img_ids::{Imgs, ImgsRot},
|
img_ids::{Imgs, ImgsRot},
|
||||||
item_imgs::ItemImgs,
|
item_imgs::ItemImgs,
|
||||||
slots, util, BarNumbers, ShortcutNumbers, BLACK, CRITICAL_HP_COLOR, HP_COLOR, LOW_HP_COLOR,
|
slots, util, BarNumbers, HudInfo, ShortcutNumbers, BLACK, CRITICAL_HP_COLOR, HP_COLOR,
|
||||||
QUALITY_EPIC, STAMINA_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0,
|
LOW_HP_COLOR, QUALITY_EPIC, STAMINA_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
game_input::GameInput,
|
game_input::GameInput,
|
||||||
@ -242,6 +242,7 @@ fn slot_entries(state: &State, slot_offset: f64) -> [SlotEntry; 10] {
|
|||||||
#[derive(WidgetCommon)]
|
#[derive(WidgetCommon)]
|
||||||
pub struct Skillbar<'a> {
|
pub struct Skillbar<'a> {
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
global_state: &'a GlobalState,
|
global_state: &'a GlobalState,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
@ -271,6 +272,7 @@ impl<'a> Skillbar<'a> {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
global_state: &'a GlobalState,
|
global_state: &'a GlobalState,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
@ -295,6 +297,7 @@ impl<'a> Skillbar<'a> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client,
|
client,
|
||||||
|
info,
|
||||||
global_state,
|
global_state,
|
||||||
imgs,
|
imgs,
|
||||||
item_imgs,
|
item_imgs,
|
||||||
@ -576,6 +579,7 @@ impl<'a> Skillbar<'a> {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
self.client,
|
self.client,
|
||||||
|
self.info,
|
||||||
self.imgs,
|
self.imgs,
|
||||||
self.item_imgs,
|
self.item_imgs,
|
||||||
self.pulse,
|
self.pulse,
|
||||||
|
@ -31,7 +31,7 @@ use super::{
|
|||||||
img_ids::{Imgs, ImgsRot},
|
img_ids::{Imgs, ImgsRot},
|
||||||
item_imgs::ItemImgs,
|
item_imgs::ItemImgs,
|
||||||
slots::{SlotKind, SlotManager, TradeSlot},
|
slots::{SlotKind, SlotManager, TradeSlot},
|
||||||
Hud, Show, TradeAmountInput, TEXT_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
Hud, HudInfo, Show, TradeAmountInput, TEXT_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||||
};
|
};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
@ -75,6 +75,7 @@ widget_ids! {
|
|||||||
#[derive(WidgetCommon)]
|
#[derive(WidgetCommon)]
|
||||||
pub struct Trade<'a> {
|
pub struct Trade<'a> {
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
@ -92,6 +93,7 @@ pub struct Trade<'a> {
|
|||||||
impl<'a> Trade<'a> {
|
impl<'a> Trade<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
@ -105,6 +107,7 @@ impl<'a> Trade<'a> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client,
|
client,
|
||||||
|
info,
|
||||||
imgs,
|
imgs,
|
||||||
item_imgs,
|
item_imgs,
|
||||||
fonts,
|
fonts,
|
||||||
@ -313,6 +316,7 @@ impl<'a> Trade<'a> {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
self.client,
|
self.client,
|
||||||
|
self.info,
|
||||||
self.imgs,
|
self.imgs,
|
||||||
self.item_imgs,
|
self.item_imgs,
|
||||||
self.pulse,
|
self.pulse,
|
||||||
|
@ -16,7 +16,7 @@ const CLIPPING_MODE_DISTANCE: f32 = 20.0;
|
|||||||
pub const MIN_ZOOM: f32 = 0.1;
|
pub const MIN_ZOOM: f32 = 0.1;
|
||||||
|
|
||||||
// Possible TODO: Add more modes
|
// Possible TODO: Add more modes
|
||||||
#[derive(PartialEq, Clone, Copy, Eq, Hash)]
|
#[derive(PartialEq, Debug, Clone, Copy, Eq, Hash)]
|
||||||
pub enum CameraMode {
|
pub enum CameraMode {
|
||||||
FirstPerson = 0,
|
FirstPerson = 0,
|
||||||
ThirdPerson = 1,
|
ThirdPerson = 1,
|
||||||
@ -130,7 +130,11 @@ fn clamp_and_modulate(ori: Vec3<f32>) -> Vec3<f32> {
|
|||||||
/// e = floor(ln(near/(far - near))/ln(2))
|
/// e = floor(ln(near/(far - near))/ln(2))
|
||||||
/// db/dz = 2^(2-e) / ((1 / far - 1 / near) * (far)^2)
|
/// db/dz = 2^(2-e) / ((1 / far - 1 / near) * (far)^2)
|
||||||
/// ```
|
/// ```
|
||||||
///CameraMode::ThirdPerson
|
///
|
||||||
|
/// Then the maximum precision you can safely use to get a change in the
|
||||||
|
/// integer representation of the mantissa (assuming 32-bit floating points)
|
||||||
|
/// is around:
|
||||||
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// abs(2^(-23) / (db/dz)).
|
/// abs(2^(-23) / (db/dz)).
|
||||||
/// ```
|
/// ```
|
||||||
@ -721,10 +725,8 @@ impl Camera {
|
|||||||
|
|
||||||
/// Cycle the camera to its next valid mode. If is_admin is false then only
|
/// Cycle the camera to its next valid mode. If is_admin is false then only
|
||||||
/// modes which are accessible without admin access will be cycled to.
|
/// modes which are accessible without admin access will be cycled to.
|
||||||
pub fn next_mode(&mut self, is_admin: bool, is_spectator: bool) {
|
pub fn next_mode(&mut self, is_admin: bool, has_target: bool) {
|
||||||
if is_spectator && is_admin {
|
if has_target {
|
||||||
self.set_mode(CameraMode::Freefly);
|
|
||||||
} else {
|
|
||||||
self.set_mode(match self.mode {
|
self.set_mode(match self.mode {
|
||||||
CameraMode::ThirdPerson => CameraMode::FirstPerson,
|
CameraMode::ThirdPerson => CameraMode::FirstPerson,
|
||||||
CameraMode::FirstPerson => {
|
CameraMode::FirstPerson => {
|
||||||
@ -736,6 +738,8 @@ impl Camera {
|
|||||||
},
|
},
|
||||||
CameraMode::Freefly => CameraMode::ThirdPerson,
|
CameraMode::Freefly => CameraMode::ThirdPerson,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
self.set_mode(CameraMode::Freefly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,7 +707,7 @@ impl FigureMgr {
|
|||||||
// Get player position.
|
// Get player position.
|
||||||
let player_pos = ecs
|
let player_pos = ecs
|
||||||
.read_storage::<Pos>()
|
.read_storage::<Pos>()
|
||||||
.get(scene_data.player_entity)
|
.get(scene_data.viewpoint_entity)
|
||||||
.map_or(anim::vek::Vec3::zero(), |pos| anim::vek::Vec3::from(pos.0));
|
.map_or(anim::vek::Vec3::zero(), |pos| anim::vek::Vec3::from(pos.0));
|
||||||
let visible_aabb = anim::vek::Aabb {
|
let visible_aabb = anim::vek::Aabb {
|
||||||
min: player_pos - 2.0,
|
min: player_pos - 2.0,
|
||||||
@ -716,7 +716,7 @@ impl FigureMgr {
|
|||||||
let camera_mode = camera.get_mode();
|
let camera_mode = camera.get_mode();
|
||||||
let character_state_storage = state.read_storage::<CharacterState>();
|
let character_state_storage = state.read_storage::<CharacterState>();
|
||||||
let slow_jobs = state.slow_job_pool();
|
let slow_jobs = state.slow_job_pool();
|
||||||
let character_state = character_state_storage.get(scene_data.player_entity);
|
let character_state = character_state_storage.get(scene_data.viewpoint_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());
|
||||||
|
|
||||||
@ -771,13 +771,13 @@ impl FigureMgr {
|
|||||||
let rel_vel = anim::vek::Vec3::<f32>::from(vel.0 - physics.ground_vel);
|
let rel_vel = anim::vek::Vec3::<f32>::from(vel.0 - physics.ground_vel);
|
||||||
|
|
||||||
let look_dir = controller.map(|c| c.inputs.look_dir).unwrap_or_default();
|
let look_dir = controller.map(|c| c.inputs.look_dir).unwrap_or_default();
|
||||||
let is_player = scene_data.player_entity == entity;
|
let is_viewpoint = scene_data.viewpoint_entity == entity;
|
||||||
let player_camera_mode = if is_player {
|
let viewpoint_camera_mode = if is_viewpoint {
|
||||||
camera_mode
|
camera_mode
|
||||||
} else {
|
} else {
|
||||||
CameraMode::default()
|
CameraMode::default()
|
||||||
};
|
};
|
||||||
let player_character_state = if is_player { character_state } else { None };
|
let viewpoint_character_state = if is_viewpoint { character_state } else { None };
|
||||||
|
|
||||||
let (pos, ori) = interpolated
|
let (pos, ori) = interpolated
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
@ -941,7 +941,7 @@ impl FigureMgr {
|
|||||||
dt,
|
dt,
|
||||||
_lpindex: lpindex,
|
_lpindex: lpindex,
|
||||||
_visible: in_frustum,
|
_visible: in_frustum,
|
||||||
is_player,
|
is_player: is_viewpoint,
|
||||||
_camera: camera,
|
_camera: camera,
|
||||||
terrain,
|
terrain,
|
||||||
ground_vel: physics.ground_vel,
|
ground_vel: physics.ground_vel,
|
||||||
@ -956,8 +956,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -1856,8 +1856,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -2056,8 +2056,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -2373,8 +2373,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -2730,8 +2730,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -2834,8 +2834,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -2917,8 +2917,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -3444,8 +3444,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -3531,8 +3531,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -3710,8 +3710,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -4002,8 +4002,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -4325,8 +4325,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -4408,8 +4408,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -5030,8 +5030,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -5271,8 +5271,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -5393,8 +5393,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
item_key,
|
item_key,
|
||||||
);
|
);
|
||||||
@ -5453,8 +5453,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
Arc::clone(vol),
|
Arc::clone(vol),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -5484,8 +5484,8 @@ impl FigureMgr {
|
|||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
player_camera_mode,
|
viewpoint_camera_mode,
|
||||||
player_character_state,
|
viewpoint_character_state,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -116,7 +116,8 @@ pub struct Scene {
|
|||||||
pub struct SceneData<'a> {
|
pub struct SceneData<'a> {
|
||||||
pub client: &'a Client,
|
pub client: &'a Client,
|
||||||
pub state: &'a State,
|
pub state: &'a State,
|
||||||
pub player_entity: specs::Entity,
|
pub viewpoint_entity: specs::Entity,
|
||||||
|
pub mutable_viewpoint: bool,
|
||||||
pub target_entity: Option<specs::Entity>,
|
pub target_entity: Option<specs::Entity>,
|
||||||
pub loaded_distance: f32,
|
pub loaded_distance: f32,
|
||||||
pub view_distance: u32,
|
pub view_distance: u32,
|
||||||
@ -502,71 +503,104 @@ impl Scene {
|
|||||||
|
|
||||||
let dt = ecs.fetch::<DeltaTime>().0;
|
let dt = ecs.fetch::<DeltaTime>().0;
|
||||||
|
|
||||||
let player_pos = ecs
|
let positions = ecs.read_storage::<comp::Pos>();
|
||||||
.read_storage::<comp::Pos>()
|
|
||||||
.get(scene_data.player_entity)
|
|
||||||
.map_or(Vec3::zero(), |pos| pos.0);
|
|
||||||
|
|
||||||
let player_rolling = ecs
|
let viewpoint_pos = if let Some(viewpoint_pos) =
|
||||||
.read_storage::<comp::CharacterState>()
|
positions.get(scene_data.viewpoint_entity).map(|pos| pos.0)
|
||||||
.get(scene_data.player_entity)
|
{
|
||||||
.map_or(false, |cs| cs.is_dodge());
|
let viewpoint_ori = ecs
|
||||||
|
.read_storage::<comp::Ori>()
|
||||||
|
.get(scene_data.viewpoint_entity)
|
||||||
|
.map_or(Quaternion::identity(), |ori| ori.to_quat());
|
||||||
|
|
||||||
let is_running = ecs
|
let viewpoint_rolling = ecs
|
||||||
.read_storage::<comp::Vel>()
|
.read_storage::<comp::CharacterState>()
|
||||||
.get(scene_data.player_entity)
|
.get(scene_data.viewpoint_entity)
|
||||||
.map(|v| v.0.magnitude_squared() > RUNNING_THRESHOLD.powi(2))
|
.map_or(false, |cs| cs.is_dodge());
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
let on_ground = ecs
|
let is_running = ecs
|
||||||
.read_storage::<comp::PhysicsState>()
|
.read_storage::<comp::Vel>()
|
||||||
.get(scene_data.player_entity)
|
.get(scene_data.viewpoint_entity)
|
||||||
.map(|p| p.on_ground.is_some());
|
.map(|v| v.0.magnitude_squared() > RUNNING_THRESHOLD.powi(2))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
let (player_height, player_eye_height) = scene_data
|
let on_ground = ecs
|
||||||
.state
|
.read_storage::<comp::PhysicsState>()
|
||||||
.ecs()
|
.get(scene_data.viewpoint_entity)
|
||||||
.read_storage::<comp::Body>()
|
.map(|p| p.on_ground.is_some());
|
||||||
.get(scene_data.player_entity)
|
|
||||||
.map_or((1.0, 0.0), |b| (b.height(), b.eye_height()));
|
|
||||||
|
|
||||||
// Add the analog input to camera
|
let (viewpoint_height, viewpoint_eye_height) = scene_data
|
||||||
self.camera
|
.state
|
||||||
.rotate_by(Vec3::from([self.camera_input_state.x, 0.0, 0.0]));
|
.ecs()
|
||||||
self.camera
|
.read_storage::<comp::Body>()
|
||||||
.rotate_by(Vec3::from([0.0, self.camera_input_state.y, 0.0]));
|
.get(scene_data.viewpoint_entity)
|
||||||
|
.map_or((1.0, 0.0), |b| (b.height(), b.eye_height()));
|
||||||
|
|
||||||
// Alter camera position to match player.
|
if scene_data.mutable_viewpoint || matches!(self.camera.get_mode(), CameraMode::Freefly)
|
||||||
let tilt = self.camera.get_orientation().y;
|
{
|
||||||
let dist = self.camera.get_distance();
|
// Add the analog input to camera if it's a mutable viewpoint
|
||||||
|
self.camera
|
||||||
|
.rotate_by(Vec3::from([self.camera_input_state.x, 0.0, 0.0]));
|
||||||
|
self.camera
|
||||||
|
.rotate_by(Vec3::from([0.0, self.camera_input_state.y, 0.0]));
|
||||||
|
} else {
|
||||||
|
// Otherwise set the cameras rotation to the viewpoints
|
||||||
|
let q = viewpoint_ori;
|
||||||
|
let sinr_cosp = 2.0 * (q.w * q.x + q.y * q.z);
|
||||||
|
let cosr_cosp = 1.0 - 2.0 * (q.x * q.x + q.y * q.y);
|
||||||
|
let roll = sinr_cosp.atan2(cosr_cosp);
|
||||||
|
|
||||||
let up = match self.camera.get_mode() {
|
let sinp = 2.0 * (q.w * q.y - q.z * q.x);
|
||||||
CameraMode::FirstPerson => {
|
let pitch = if sinp.abs() >= 1.0 {
|
||||||
if player_rolling {
|
std::f32::consts::FRAC_PI_2.copysign(sinp)
|
||||||
player_height * 0.42
|
|
||||||
} else if is_running && on_ground.unwrap_or(false) {
|
|
||||||
player_eye_height + (scene_data.state.get_time() as f32 * 17.0).sin() * 0.05
|
|
||||||
} else {
|
} else {
|
||||||
player_eye_height
|
sinp.asin()
|
||||||
}
|
};
|
||||||
},
|
|
||||||
CameraMode::ThirdPerson if scene_data.is_aiming => player_height * 1.16,
|
|
||||||
CameraMode::ThirdPerson => player_eye_height,
|
|
||||||
CameraMode::Freefly => 0.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
match self.camera.get_mode() {
|
let siny_cosp = 2.0 * (q.w * q.z + q.x * q.y);
|
||||||
CameraMode::FirstPerson | CameraMode::ThirdPerson => {
|
let cosy_cosp = 1.0 - 2.0 * (q.y * q.y + q.z * q.z);
|
||||||
self.camera.set_focus_pos(
|
let yaw = siny_cosp.atan2(cosy_cosp);
|
||||||
player_pos + Vec3::unit_z() * (up - tilt.min(0.0).sin() * dist * 0.6),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
CameraMode::Freefly => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Tick camera for interpolation.
|
self.camera
|
||||||
self.camera
|
.set_orientation_instant(Vec3::new(yaw, pitch, -roll));
|
||||||
.update(scene_data.state.get_time(), dt, scene_data.mouse_smoothing);
|
}
|
||||||
|
|
||||||
|
// Alter camera position to match player.
|
||||||
|
let tilt = self.camera.get_orientation().y;
|
||||||
|
let dist = self.camera.get_distance();
|
||||||
|
|
||||||
|
let up = match self.camera.get_mode() {
|
||||||
|
CameraMode::FirstPerson => {
|
||||||
|
if viewpoint_rolling {
|
||||||
|
viewpoint_height * 0.42
|
||||||
|
} else if is_running && on_ground.unwrap_or(false) {
|
||||||
|
viewpoint_eye_height
|
||||||
|
+ (scene_data.state.get_time() as f32 * 17.0).sin() * 0.05
|
||||||
|
} else {
|
||||||
|
viewpoint_eye_height
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CameraMode::ThirdPerson if scene_data.is_aiming => viewpoint_height * 1.16,
|
||||||
|
CameraMode::ThirdPerson => viewpoint_eye_height,
|
||||||
|
CameraMode::Freefly => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.camera.get_mode() {
|
||||||
|
CameraMode::FirstPerson | CameraMode::ThirdPerson => {
|
||||||
|
self.camera.set_focus_pos(
|
||||||
|
viewpoint_pos + Vec3::unit_z() * (up - tilt.min(0.0).sin() * dist * 0.6),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
CameraMode::Freefly => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tick camera for interpolation.
|
||||||
|
self.camera
|
||||||
|
.update(scene_data.state.get_time(), dt, scene_data.mouse_smoothing);
|
||||||
|
viewpoint_pos
|
||||||
|
} else {
|
||||||
|
Vec3::zero()
|
||||||
|
};
|
||||||
|
|
||||||
// Compute camera matrices.
|
// Compute camera matrices.
|
||||||
self.camera.compute_dependents(&*scene_data.state.terrain());
|
self.camera.compute_dependents(&*scene_data.state.terrain());
|
||||||
@ -617,7 +651,7 @@ impl Scene {
|
|||||||
.filter(|(pos, _, light_anim, h)| {
|
.filter(|(pos, _, light_anim, h)| {
|
||||||
light_anim.col != Rgb::zero()
|
light_anim.col != Rgb::zero()
|
||||||
&& light_anim.strength > 0.0
|
&& light_anim.strength > 0.0
|
||||||
&& (pos.0.distance_squared(player_pos) as f32)
|
&& (pos.0.distance_squared(viewpoint_pos) as f32)
|
||||||
< loaded_distance.powi(2) + LIGHT_DIST_RADIUS
|
< loaded_distance.powi(2) + LIGHT_DIST_RADIUS
|
||||||
&& h.map_or(true, |h| !h.is_dead)
|
&& h.map_or(true, |h| !h.is_dead)
|
||||||
})
|
})
|
||||||
@ -632,7 +666,7 @@ impl Scene {
|
|||||||
.map(|el| el.light.with_strength((el.fadeout)(el.timeout))),
|
.map(|el| el.light.with_strength((el.fadeout)(el.timeout))),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
lights.sort_by_key(|light| light.get_pos().distance_squared(player_pos) as i32);
|
lights.sort_by_key(|light| light.get_pos().distance_squared(viewpoint_pos) as i32);
|
||||||
lights.truncate(MAX_LIGHT_COUNT);
|
lights.truncate(MAX_LIGHT_COUNT);
|
||||||
renderer.update_consts(&mut self.data.lights, lights);
|
renderer.update_consts(&mut self.data.lights, lights);
|
||||||
|
|
||||||
@ -657,7 +691,7 @@ impl Scene {
|
|||||||
.join()
|
.join()
|
||||||
.filter(|(_, _, _, _, health)| !health.is_dead)
|
.filter(|(_, _, _, _, health)| !health.is_dead)
|
||||||
.filter(|(pos, _, _, _, _)| {
|
.filter(|(pos, _, _, _, _)| {
|
||||||
(pos.0.distance_squared(player_pos) as f32)
|
(pos.0.distance_squared(viewpoint_pos) as f32)
|
||||||
< (loaded_distance.min(SHADOW_MAX_DIST) + SHADOW_DIST_RADIUS).powi(2)
|
< (loaded_distance.min(SHADOW_MAX_DIST) + SHADOW_DIST_RADIUS).powi(2)
|
||||||
})
|
})
|
||||||
.map(|(pos, interpolated, scale, _, _)| {
|
.map(|(pos, interpolated, scale, _, _)| {
|
||||||
@ -668,7 +702,7 @@ impl Scene {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
shadows.sort_by_key(|shadow| shadow.get_pos().distance_squared(player_pos) as i32);
|
shadows.sort_by_key(|shadow| shadow.get_pos().distance_squared(viewpoint_pos) as i32);
|
||||||
shadows.truncate(MAX_SHADOW_COUNT);
|
shadows.truncate(MAX_SHADOW_COUNT);
|
||||||
renderer.update_consts(&mut self.data.shadows, &shadows);
|
renderer.update_consts(&mut self.data.shadows, &shadows);
|
||||||
|
|
||||||
@ -1139,7 +1173,7 @@ impl Scene {
|
|||||||
self.sfx_mgr.maintain(
|
self.sfx_mgr.maintain(
|
||||||
audio,
|
audio,
|
||||||
scene_data.state,
|
scene_data.state,
|
||||||
scene_data.player_entity,
|
scene_data.viewpoint_entity,
|
||||||
&self.camera,
|
&self.camera,
|
||||||
&self.terrain,
|
&self.terrain,
|
||||||
client,
|
client,
|
||||||
|
@ -1166,7 +1166,7 @@ impl ParticleMgr {
|
|||||||
let time = scene_data.state.get_time();
|
let time = scene_data.state.get_time();
|
||||||
let player_pos = scene_data
|
let player_pos = scene_data
|
||||||
.state
|
.state
|
||||||
.read_component_copied::<Interpolated>(scene_data.player_entity)
|
.read_component_copied::<Interpolated>(scene_data.viewpoint_entity)
|
||||||
.map(|i| i.pos)
|
.map(|i| i.pos)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let player_chunk = player_pos.xy().map2(TerrainChunk::RECT_SIZE, |e, sz| {
|
let player_chunk = player_pos.xy().map2(TerrainChunk::RECT_SIZE, |e, sz| {
|
||||||
|
@ -88,6 +88,7 @@ pub struct SessionState {
|
|||||||
is_aiming: bool,
|
is_aiming: bool,
|
||||||
target_entity: Option<specs::Entity>,
|
target_entity: Option<specs::Entity>,
|
||||||
selected_entity: Option<(specs::Entity, std::time::Instant)>,
|
selected_entity: Option<(specs::Entity, std::time::Instant)>,
|
||||||
|
viewpoint_entity: Option<specs::Entity>,
|
||||||
interactable: Option<Interactable>,
|
interactable: Option<Interactable>,
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
mumble_link: SharedLink,
|
mumble_link: SharedLink,
|
||||||
@ -149,6 +150,7 @@ impl SessionState {
|
|||||||
is_aiming: false,
|
is_aiming: false,
|
||||||
target_entity: None,
|
target_entity: None,
|
||||||
selected_entity: None,
|
selected_entity: None,
|
||||||
|
viewpoint_entity: None,
|
||||||
interactable: None,
|
interactable: None,
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
mumble_link,
|
mumble_link,
|
||||||
@ -162,6 +164,14 @@ impl SessionState {
|
|||||||
self.key_state.auto_walk = false;
|
self.key_state.auto_walk = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the entity that is the current viewpoint, and a bool if the client
|
||||||
|
/// is allowed to edit it's data.
|
||||||
|
fn viewpoint_entity(&self) -> (specs::Entity, bool) {
|
||||||
|
self.viewpoint_entity
|
||||||
|
.map(|e| (e, false))
|
||||||
|
.unwrap_or_else(|| (self.client.borrow().entity(), true))
|
||||||
|
}
|
||||||
|
|
||||||
/// Tick the session (and the client attached to it).
|
/// Tick the session (and the client attached to it).
|
||||||
fn tick(
|
fn tick(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -548,12 +558,11 @@ impl PlayState for SessionState {
|
|||||||
if !self.inputs_state.insert(input) {
|
if !self.inputs_state.insert(input) {
|
||||||
self.inputs_state.remove(&input);
|
self.inputs_state.remove(&input);
|
||||||
}
|
}
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
GameInput::Primary => {
|
GameInput::Primary => {
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
// Mine and build targets can be the same block. make building take
|
// Mine and build targets can be the same block. make building
|
||||||
// precedence.
|
// take precedence.
|
||||||
// Order of precedence: build, then mining, then attack.
|
// Order of precedence: build, then mining, then attack.
|
||||||
if let Some(build_target) = build_target.filter(|bt| {
|
if let Some(build_target) = build_target.filter(|bt| {
|
||||||
state && can_build && nearest_block_dist == Some(bt.distance)
|
state && can_build && nearest_block_dist == Some(bt.distance)
|
||||||
@ -890,16 +899,18 @@ impl PlayState for SessionState {
|
|||||||
// Prevent accessing camera modes which aren't available in
|
// Prevent accessing camera modes which aren't available in
|
||||||
// multiplayer unless you are an
|
// multiplayer unless you are an
|
||||||
// admin. This is an easily bypassed clientside check.
|
// admin. This is an easily bypassed clientside check.
|
||||||
// The server should do its own filtering of which entities are sent
|
// The server should do its own filtering of which entities are
|
||||||
// to clients to prevent abuse.
|
// sent to clients to
|
||||||
|
// prevent abuse.
|
||||||
let camera = self.scene.camera_mut();
|
let camera = self.scene.camera_mut();
|
||||||
let client = self.client.borrow();
|
let client = self.client.borrow();
|
||||||
camera.next_mode(
|
camera.next_mode(
|
||||||
client.is_moderator(),
|
client.is_moderator(),
|
||||||
client
|
client
|
||||||
.presence()
|
.presence()
|
||||||
.map(|presence| presence == PresenceKind::Spectator)
|
.map(|presence| presence != PresenceKind::Spectator)
|
||||||
.unwrap_or(false),
|
.unwrap_or(true)
|
||||||
|
|| self.viewpoint_entity.is_some(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
GameInput::Select => {
|
GameInput::Select => {
|
||||||
@ -920,6 +931,24 @@ impl PlayState for SessionState {
|
|||||||
client.decline_invite();
|
client.decline_invite();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
GameInput::SpectateViewpoint if state => {
|
||||||
|
if self.viewpoint_entity.is_some() {
|
||||||
|
self.viewpoint_entity = None;
|
||||||
|
self.scene.camera_mut().set_mode(CameraMode::Freefly);
|
||||||
|
} else if let Some(interactable) = self.interactable {
|
||||||
|
if self.scene.camera().get_mode() == CameraMode::Freefly {
|
||||||
|
match interactable {
|
||||||
|
Interactable::Block(_, _, _) => {},
|
||||||
|
Interactable::Entity(entity) => {
|
||||||
|
self.viewpoint_entity = Some(entity);
|
||||||
|
self.scene
|
||||||
|
.camera_mut()
|
||||||
|
.set_mode(CameraMode::FirstPerson);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -949,97 +978,121 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If auto-gliding, point camera into the wind
|
if self.viewpoint_entity.map_or(false, |entity| {
|
||||||
if let Some(dir) = self
|
!self
|
||||||
.auto_walk
|
.client
|
||||||
.then_some(self.client.borrow())
|
.borrow()
|
||||||
.filter(|client| client.is_gliding())
|
.state()
|
||||||
.and_then(|client| {
|
.ecs()
|
||||||
let ecs = client.state().ecs();
|
.read_storage::<Pos>()
|
||||||
let entity = client.entity();
|
.contains(entity)
|
||||||
let fluid = ecs
|
}) {
|
||||||
.read_storage::<comp::PhysicsState>()
|
self.viewpoint_entity = None;
|
||||||
.get(entity)?
|
self.scene.camera_mut().set_mode(CameraMode::Freefly);
|
||||||
.in_fluid?;
|
|
||||||
ecs.read_storage::<Vel>()
|
|
||||||
.get(entity)
|
|
||||||
.map(|vel| fluid.relative_flow(vel).0)
|
|
||||||
.map(|rel_flow| {
|
|
||||||
let is_wind_downwards = rel_flow.dot(Vec3::unit_z()).is_sign_negative();
|
|
||||||
if !self.free_look {
|
|
||||||
if is_wind_downwards {
|
|
||||||
self.scene.camera().forward_xy().into()
|
|
||||||
} else {
|
|
||||||
let windwards = rel_flow
|
|
||||||
* self
|
|
||||||
.scene
|
|
||||||
.camera()
|
|
||||||
.forward_xy()
|
|
||||||
.dot(rel_flow.xy())
|
|
||||||
.signum();
|
|
||||||
Plane::from(Dir::new(self.scene.camera().right()))
|
|
||||||
.projection(windwards)
|
|
||||||
}
|
|
||||||
} else if is_wind_downwards {
|
|
||||||
Vec3::from(-rel_flow.xy())
|
|
||||||
} else {
|
|
||||||
-rel_flow
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.and_then(Dir::from_unnormalized)
|
|
||||||
})
|
|
||||||
{
|
|
||||||
self.key_state.auto_walk = false;
|
|
||||||
self.inputs.move_dir = Vec2::zero();
|
|
||||||
self.inputs.look_dir = dir;
|
|
||||||
} else {
|
|
||||||
self.key_state.auto_walk = self.auto_walk;
|
|
||||||
if !self.free_look {
|
|
||||||
self.walk_forward_dir = self.scene.camera().forward_xy();
|
|
||||||
self.walk_right_dir = self.scene.camera().right_xy();
|
|
||||||
self.inputs.look_dir =
|
|
||||||
Dir::from_unnormalized(cam_dir + aim_dir_offset).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.inputs.strafing = matches!(
|
|
||||||
self.scene.camera().get_mode(),
|
let (viewpoint_entity, mutable_viewpoint) = self.viewpoint_entity();
|
||||||
camera::CameraMode::FirstPerson
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get the current state of movement related inputs
|
// Get the current state of movement related inputs
|
||||||
let input_vec = self.key_state.dir_vec();
|
let input_vec = self.key_state.dir_vec();
|
||||||
let (axis_right, axis_up) = (input_vec[0], input_vec[1]);
|
let (axis_right, axis_up) = (input_vec[0], input_vec[1]);
|
||||||
let dt = global_state.clock.get_stable_dt().as_secs_f32();
|
let dt = global_state.clock.get_stable_dt().as_secs_f32();
|
||||||
|
|
||||||
// Auto camera mode
|
if mutable_viewpoint {
|
||||||
if global_state.settings.gameplay.auto_camera
|
// If auto-gliding, point camera into the wind
|
||||||
&& matches!(
|
if let Some(dir) = self
|
||||||
|
.auto_walk
|
||||||
|
.then_some(self.client.borrow())
|
||||||
|
.filter(|client| client.is_gliding())
|
||||||
|
.and_then(|client| {
|
||||||
|
let ecs = client.state().ecs();
|
||||||
|
let entity = client.entity();
|
||||||
|
let fluid = ecs
|
||||||
|
.read_storage::<comp::PhysicsState>()
|
||||||
|
.get(entity)?
|
||||||
|
.in_fluid?;
|
||||||
|
ecs.read_storage::<Vel>()
|
||||||
|
.get(entity)
|
||||||
|
.map(|vel| fluid.relative_flow(vel).0)
|
||||||
|
.map(|rel_flow| {
|
||||||
|
let is_wind_downwards =
|
||||||
|
rel_flow.dot(Vec3::unit_z()).is_sign_negative();
|
||||||
|
if !self.free_look {
|
||||||
|
if is_wind_downwards {
|
||||||
|
self.scene.camera().forward_xy().into()
|
||||||
|
} else {
|
||||||
|
let windwards = rel_flow
|
||||||
|
* self
|
||||||
|
.scene
|
||||||
|
.camera()
|
||||||
|
.forward_xy()
|
||||||
|
.dot(rel_flow.xy())
|
||||||
|
.signum();
|
||||||
|
Plane::from(Dir::new(self.scene.camera().right()))
|
||||||
|
.projection(windwards)
|
||||||
|
}
|
||||||
|
} else if is_wind_downwards {
|
||||||
|
Vec3::from(-rel_flow.xy())
|
||||||
|
} else {
|
||||||
|
-rel_flow
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and_then(Dir::from_unnormalized)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
self.key_state.auto_walk = false;
|
||||||
|
self.inputs.move_dir = Vec2::zero();
|
||||||
|
self.inputs.look_dir = dir;
|
||||||
|
} else {
|
||||||
|
self.key_state.auto_walk = self.auto_walk;
|
||||||
|
if !self.free_look {
|
||||||
|
self.walk_forward_dir = self.scene.camera().forward_xy();
|
||||||
|
self.walk_right_dir = self.scene.camera().right_xy();
|
||||||
|
self.inputs.look_dir =
|
||||||
|
Dir::from_unnormalized(cam_dir + aim_dir_offset).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.inputs.strafing = matches!(
|
||||||
self.scene.camera().get_mode(),
|
self.scene.camera().get_mode(),
|
||||||
camera::CameraMode::ThirdPerson | camera::CameraMode::FirstPerson
|
camera::CameraMode::FirstPerson
|
||||||
)
|
);
|
||||||
&& input_vec.magnitude_squared() > 0.0
|
|
||||||
{
|
// Auto camera mode
|
||||||
let camera = self.scene.camera_mut();
|
if global_state.settings.gameplay.auto_camera
|
||||||
let ori = camera.get_orientation();
|
&& matches!(
|
||||||
camera.set_orientation_instant(Vec3::new(
|
self.scene.camera().get_mode(),
|
||||||
ori.x
|
camera::CameraMode::ThirdPerson | camera::CameraMode::FirstPerson
|
||||||
+ input_vec.x
|
)
|
||||||
* (3.0 - input_vec.y * 1.5 * if is_aiming { 1.5 } else { 1.0 })
|
&& input_vec.magnitude_squared() > 0.0
|
||||||
* dt,
|
{
|
||||||
std::f32::consts::PI * if is_aiming { 0.015 } else { 0.1 },
|
let camera = self.scene.camera_mut();
|
||||||
0.0,
|
let ori = camera.get_orientation();
|
||||||
));
|
camera.set_orientation_instant(Vec3::new(
|
||||||
|
ori.x
|
||||||
|
+ input_vec.x
|
||||||
|
* (3.0 - input_vec.y * 1.5 * if is_aiming { 1.5 } else { 1.0 })
|
||||||
|
* dt,
|
||||||
|
std::f32::consts::PI * if is_aiming { 0.015 } else { 0.1 },
|
||||||
|
0.0,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inputs.climb = self.key_state.climb();
|
||||||
|
self.inputs.move_z =
|
||||||
|
self.key_state.swim_up as i32 as f32 - self.key_state.swim_down as i32 as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.scene.camera().get_mode() {
|
match self.scene.camera().get_mode() {
|
||||||
CameraMode::FirstPerson | CameraMode::ThirdPerson => {
|
CameraMode::FirstPerson | CameraMode::ThirdPerson => {
|
||||||
// Move the player character based on their walking direction.
|
if mutable_viewpoint {
|
||||||
// This could be different from the camera direction if free look is enabled.
|
// Move the player character based on their walking direction.
|
||||||
self.inputs.move_dir =
|
// This could be different from the camera direction if free look is
|
||||||
self.walk_right_dir * axis_right + self.walk_forward_dir * axis_up;
|
// enabled.
|
||||||
|
self.inputs.move_dir =
|
||||||
|
self.walk_right_dir * axis_right + self.walk_forward_dir * axis_up;
|
||||||
|
}
|
||||||
self.freefly_vel = Vec3::zero();
|
self.freefly_vel = Vec3::zero();
|
||||||
},
|
},
|
||||||
|
|
||||||
CameraMode::Freefly => {
|
CameraMode::Freefly => {
|
||||||
// Move the camera freely in 3d space. Apply acceleration so that
|
// Move the camera freely in 3d space. Apply acceleration so that
|
||||||
// the movement feels more natural and controlled.
|
// the movement feels more natural and controlled.
|
||||||
@ -1084,10 +1137,6 @@ impl PlayState for SessionState {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
self.inputs.climb = self.key_state.climb();
|
|
||||||
self.inputs.move_z =
|
|
||||||
self.key_state.swim_up as i32 as f32 - self.key_state.swim_down as i32 as f32;
|
|
||||||
|
|
||||||
let mut outcomes = Vec::new();
|
let mut outcomes = Vec::new();
|
||||||
|
|
||||||
// Runs if either in a multiplayer server or the singleplayer server is unpaused
|
// Runs if either in a multiplayer server or the singleplayer server is unpaused
|
||||||
@ -1177,6 +1226,8 @@ impl PlayState for SessionState {
|
|||||||
self.scene.camera().get_mode(),
|
self.scene.camera().get_mode(),
|
||||||
camera::CameraMode::FirstPerson
|
camera::CameraMode::FirstPerson
|
||||||
),
|
),
|
||||||
|
viewpoint_entity,
|
||||||
|
mutable_viewpoint,
|
||||||
target_entity: self.target_entity,
|
target_entity: self.target_entity,
|
||||||
selected_entity: self.selected_entity,
|
selected_entity: self.selected_entity,
|
||||||
},
|
},
|
||||||
@ -1608,7 +1659,8 @@ impl PlayState for SessionState {
|
|||||||
let scene_data = SceneData {
|
let scene_data = SceneData {
|
||||||
client: &client,
|
client: &client,
|
||||||
state: client.state(),
|
state: client.state(),
|
||||||
player_entity: client.entity(),
|
viewpoint_entity,
|
||||||
|
mutable_viewpoint: mutable_viewpoint || self.free_look,
|
||||||
// Only highlight if interactable
|
// Only highlight if interactable
|
||||||
target_entity: self.interactable.and_then(Interactable::entity),
|
target_entity: self.interactable.and_then(Interactable::entity),
|
||||||
loaded_distance: client.loaded_distance(),
|
loaded_distance: client.loaded_distance(),
|
||||||
@ -1688,10 +1740,13 @@ impl PlayState for SessionState {
|
|||||||
|
|
||||||
let client = self.client.borrow();
|
let client = self.client.borrow();
|
||||||
|
|
||||||
|
let (viewpoint_entity, mutable_viewpoint) = self.viewpoint_entity();
|
||||||
|
|
||||||
let scene_data = SceneData {
|
let scene_data = SceneData {
|
||||||
client: &client,
|
client: &client,
|
||||||
state: client.state(),
|
state: client.state(),
|
||||||
player_entity: client.entity(),
|
viewpoint_entity,
|
||||||
|
mutable_viewpoint,
|
||||||
// Only highlight if interactable
|
// Only highlight if interactable
|
||||||
target_entity: self.interactable.and_then(Interactable::entity),
|
target_entity: self.interactable.and_then(Interactable::entity),
|
||||||
loaded_distance: client.loaded_distance(),
|
loaded_distance: client.loaded_distance(),
|
||||||
|
@ -190,6 +190,7 @@ impl ControlSettings {
|
|||||||
GameInput::MapZoomOut => KeyMouse::Key(VirtualKeyCode::Minus),
|
GameInput::MapZoomOut => KeyMouse::Key(VirtualKeyCode::Minus),
|
||||||
GameInput::MapSetMarker => KeyMouse::Mouse(MouseButton::Middle),
|
GameInput::MapSetMarker => KeyMouse::Mouse(MouseButton::Middle),
|
||||||
GameInput::SpectateSpeedBoost => KeyMouse::Key(VirtualKeyCode::LControl),
|
GameInput::SpectateSpeedBoost => KeyMouse::Key(VirtualKeyCode::LControl),
|
||||||
|
GameInput::SpectateViewpoint => KeyMouse::Mouse(MouseButton::Middle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
mod pixel_art;
|
mod pixel_art;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
|
|
||||||
pub use renderer::{SampleStrat, Transform};
|
pub use renderer::{SampleStrat, Transform};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -3,7 +3,7 @@ use crate::hud::{
|
|||||||
get_quality_col,
|
get_quality_col,
|
||||||
img_ids::Imgs,
|
img_ids::Imgs,
|
||||||
item_imgs::{animate_by_pulse, ItemImgs},
|
item_imgs::{animate_by_pulse, ItemImgs},
|
||||||
util,
|
util, HudInfo,
|
||||||
};
|
};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{
|
use common::{
|
||||||
@ -291,6 +291,7 @@ pub struct ItemTooltip<'a> {
|
|||||||
transparency: f32,
|
transparency: f32,
|
||||||
image_frame: ImageFrame,
|
image_frame: ImageFrame,
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
pulse: f32,
|
pulse: f32,
|
||||||
@ -352,6 +353,7 @@ impl<'a> ItemTooltip<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
image_frame: ImageFrame,
|
image_frame: ImageFrame,
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
info: &'a HudInfo,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
pulse: f32,
|
pulse: f32,
|
||||||
@ -369,6 +371,7 @@ impl<'a> ItemTooltip<'a> {
|
|||||||
image: None,
|
image: None,
|
||||||
image_dims: None,
|
image_dims: None,
|
||||||
client,
|
client,
|
||||||
|
info,
|
||||||
imgs,
|
imgs,
|
||||||
item_imgs,
|
item_imgs,
|
||||||
pulse,
|
pulse,
|
||||||
@ -448,7 +451,7 @@ impl<'a> Widget for ItemTooltip<'a> {
|
|||||||
let i18n = &self.localized_strings;
|
let i18n = &self.localized_strings;
|
||||||
|
|
||||||
let inventories = self.client.inventories();
|
let inventories = self.client.inventories();
|
||||||
let inventory = match inventories.get(self.client.entity()) {
|
let inventory = match inventories.get(self.info.viewpoint_entity) {
|
||||||
Some(l) => l,
|
Some(l) => l,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user