mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'hqurve/settings-cleanup' into 'master'
Settings changes from the ui are now wrapped into a single enum and handling was moved to session/settings_change.rs, also settings.rs was split up See merge request veloren/veloren!2130
This commit is contained in:
commit
219f577106
@ -5,6 +5,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
i18n::Localization,
|
i18n::Localization,
|
||||||
|
session::settings_change::{Interface as InterfaceChange, Interface::*},
|
||||||
ui::{fonts::Fonts, img_ids, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
ui::{fonts::Fonts, img_ids, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
@ -117,15 +118,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
MapZoom(f64),
|
SettingsChange(InterfaceChange),
|
||||||
MapDrag(Vec2<f64>),
|
|
||||||
ShowDifficulties(bool),
|
|
||||||
ShowTowns(bool),
|
|
||||||
ShowCastles(bool),
|
|
||||||
ShowDungeons(bool),
|
|
||||||
ShowCaves(bool),
|
|
||||||
ShowTrees(bool),
|
|
||||||
ShowTopoMap(bool),
|
|
||||||
Close,
|
Close,
|
||||||
RequestSiteInfo(SiteId),
|
RequestSiteInfo(SiteId),
|
||||||
}
|
}
|
||||||
@ -315,7 +308,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.sum();
|
.sum();
|
||||||
// Drag represents offset of view from the player_pos in chunk coords
|
// Drag represents offset of view from the player_pos in chunk coords
|
||||||
let drag_new = drag + dragged / map_size / zoom * max_zoom;
|
let drag_new = drag + dragged / map_size / zoom * max_zoom;
|
||||||
events.push(Event::MapDrag(drag_new));
|
events.push(Event::SettingsChange(MapDrag(drag_new)));
|
||||||
|
|
||||||
let rect_src = position::Rect::from_xy_dim(
|
let rect_src = position::Rect::from_xy_dim(
|
||||||
[
|
[
|
||||||
@ -366,7 +359,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
let new_zoom_lvl = (self.global_state.settings.interface.map_zoom
|
let new_zoom_lvl = (self.global_state.settings.interface.map_zoom
|
||||||
* (scrolled * 0.05 * -1.0).exp2())
|
* (scrolled * 0.05 * -1.0).exp2())
|
||||||
.clamped(1.25, max_zoom / 64.0);
|
.clamped(1.25, max_zoom / 64.0);
|
||||||
events.push(Event::MapZoom(new_zoom_lvl as f64));
|
events.push(Event::SettingsChange(MapZoom(new_zoom_lvl as f64)));
|
||||||
// Icon settings
|
// Icon settings
|
||||||
// Alignment
|
// Alignment
|
||||||
Rectangle::fill_with([150.0, 200.0], color::TRANSPARENT)
|
Rectangle::fill_with([150.0, 200.0], color::TRANSPARENT)
|
||||||
@ -398,7 +391,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.set(state.ids.show_difficulty_box, ui)
|
.set(state.ids.show_difficulty_box, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ShowDifficulties(!show_difficulty));
|
events.push(Event::SettingsChange(MapShowDifficulty(!show_difficulty)));
|
||||||
}
|
}
|
||||||
Text::new(i18n.get("hud.map.difficulty"))
|
Text::new(i18n.get("hud.map.difficulty"))
|
||||||
.right_from(state.ids.show_difficulty_box, 10.0)
|
.right_from(state.ids.show_difficulty_box, 10.0)
|
||||||
@ -432,7 +425,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.set(state.ids.show_towns_box, ui)
|
.set(state.ids.show_towns_box, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ShowTowns(!show_towns));
|
events.push(Event::SettingsChange(MapShowTowns(!show_towns)));
|
||||||
}
|
}
|
||||||
Text::new(i18n.get("hud.map.towns"))
|
Text::new(i18n.get("hud.map.towns"))
|
||||||
.right_from(state.ids.show_towns_box, 10.0)
|
.right_from(state.ids.show_towns_box, 10.0)
|
||||||
@ -466,7 +459,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.set(state.ids.show_castles_box, ui)
|
.set(state.ids.show_castles_box, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ShowCastles(!show_castles));
|
events.push(Event::SettingsChange(MapShowCastles(!show_castles)));
|
||||||
}
|
}
|
||||||
Text::new(i18n.get("hud.map.castles"))
|
Text::new(i18n.get("hud.map.castles"))
|
||||||
.right_from(state.ids.show_castles_box, 10.0)
|
.right_from(state.ids.show_castles_box, 10.0)
|
||||||
@ -500,7 +493,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.set(state.ids.show_dungeons_box, ui)
|
.set(state.ids.show_dungeons_box, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ShowDungeons(!show_dungeons));
|
events.push(Event::SettingsChange(MapShowDungeons(!show_dungeons)));
|
||||||
}
|
}
|
||||||
Text::new(i18n.get("hud.map.dungeons"))
|
Text::new(i18n.get("hud.map.dungeons"))
|
||||||
.right_from(state.ids.show_dungeons_box, 10.0)
|
.right_from(state.ids.show_dungeons_box, 10.0)
|
||||||
@ -534,7 +527,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.set(state.ids.show_caves_box, ui)
|
.set(state.ids.show_caves_box, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ShowCaves(!show_caves));
|
events.push(Event::SettingsChange(MapShowCaves(!show_caves)));
|
||||||
}
|
}
|
||||||
Text::new(i18n.get("hud.map.caves"))
|
Text::new(i18n.get("hud.map.caves"))
|
||||||
.right_from(state.ids.show_caves_box, 10.0)
|
.right_from(state.ids.show_caves_box, 10.0)
|
||||||
@ -568,7 +561,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.set(state.ids.show_trees_box, ui)
|
.set(state.ids.show_trees_box, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ShowTrees(!show_trees));
|
events.push(Event::SettingsChange(MapShowTrees(!show_trees)));
|
||||||
}
|
}
|
||||||
Text::new(i18n.get("hud.map.trees"))
|
Text::new(i18n.get("hud.map.trees"))
|
||||||
.right_from(state.ids.show_trees_box, 10.0)
|
.right_from(state.ids.show_trees_box, 10.0)
|
||||||
@ -898,7 +891,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.set(state.ids.recenter_button, ui)
|
.set(state.ids.recenter_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::MapDrag(Vec2::zero()));
|
events.push(Event::SettingsChange(MapDrag(Vec2::zero())));
|
||||||
};
|
};
|
||||||
|
|
||||||
Image::new(self.imgs.m_move_ico)
|
Image::new(self.imgs.m_move_ico)
|
||||||
@ -942,7 +935,7 @@ impl<'a> Widget for Map<'a> {
|
|||||||
.set(state.ids.map_mode_btn, ui)
|
.set(state.ids.map_mode_btn, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ShowTopoMap(!show_topo_map));
|
events.push(Event::SettingsChange(MapShowTopoMap(!show_topo_map)));
|
||||||
};
|
};
|
||||||
Button::image(self.imgs.map_mode_overlay)
|
Button::image(self.imgs.map_mode_overlay)
|
||||||
.w_h(92.0, icon_size.y)
|
.w_h(92.0, icon_size.y)
|
||||||
|
@ -4,6 +4,7 @@ use super::{
|
|||||||
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
session::settings_change::{Interface as InterfaceChange, Interface::*},
|
||||||
ui::{fonts::Fonts, img_ids},
|
ui::{fonts::Fonts, img_ids},
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
@ -85,8 +86,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Show(bool),
|
SettingsChange(InterfaceChange),
|
||||||
FaceNorth(bool),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for MiniMap<'a> {
|
impl<'a> Widget for MiniMap<'a> {
|
||||||
@ -227,7 +227,7 @@ impl<'a> Widget for MiniMap<'a> {
|
|||||||
.set(state.ids.mmap_north_button, ui)
|
.set(state.ids.mmap_north_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
return Some(Event::FaceNorth(!is_facing_north));
|
return Some(Event::SettingsChange(MinimapFaceNorth(!is_facing_north)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload zoom in case it changed.
|
// Reload zoom in case it changed.
|
||||||
@ -502,7 +502,7 @@ impl<'a> Widget for MiniMap<'a> {
|
|||||||
.set(state.ids.mmap_button, ui)
|
.set(state.ids.mmap_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
return Some(Event::Show(!show_minimap));
|
return Some(Event::SettingsChange(MinimapShow(!show_minimap)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Subregion name display
|
// TODO: Subregion name display
|
||||||
|
@ -50,15 +50,17 @@ use trade::Trade;
|
|||||||
use crate::{
|
use crate::{
|
||||||
ecs::{comp as vcomp, comp::HpFloaterList},
|
ecs::{comp as vcomp, comp::HpFloaterList},
|
||||||
hud::{img_ids::ImgsRot, prompt_dialog::DialogOutcomeEvent},
|
hud::{img_ids::ImgsRot, prompt_dialog::DialogOutcomeEvent},
|
||||||
i18n::{LanguageMetadata, Localization},
|
i18n::Localization,
|
||||||
render::{Consts, Globals, RenderMode, Renderer},
|
render::{Consts, Globals, Renderer},
|
||||||
scene::camera::{self, Camera},
|
scene::camera::{self, Camera},
|
||||||
session::Interactable,
|
session::{
|
||||||
settings::Fps,
|
settings_change::{Interface as InterfaceChange, SettingsChange},
|
||||||
|
Interactable,
|
||||||
|
},
|
||||||
ui::{
|
ui::{
|
||||||
fonts::Fonts, img_ids::Rotations, slot, slot::SlotKey, Graphic, Ingameable, ScaleMode, Ui,
|
fonts::Fonts, img_ids::Rotations, slot, slot::SlotKey, Graphic, Ingameable, ScaleMode, Ui,
|
||||||
},
|
},
|
||||||
window::{Event as WinEvent, FullScreenSettings, GameInput},
|
window::{Event as WinEvent, GameInput},
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
@ -351,55 +353,8 @@ pub struct HudInfo {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
ToggleTips(bool),
|
|
||||||
SendMessage(String),
|
SendMessage(String),
|
||||||
AdjustMousePan(u32),
|
|
||||||
AdjustMouseZoom(u32),
|
|
||||||
AdjustCameraClamp(u32),
|
|
||||||
ToggleZoomInvert(bool),
|
|
||||||
ToggleMouseYInvert(bool),
|
|
||||||
ToggleControllerYInvert(bool),
|
|
||||||
ToggleSmoothPan(bool),
|
|
||||||
AdjustViewDistance(u32),
|
|
||||||
AdjustLodDetail(u32),
|
|
||||||
AdjustSpriteRenderDistance(u32),
|
|
||||||
AdjustFigureLoDRenderDistance(u32),
|
|
||||||
AdjustMusicVolume(f32),
|
|
||||||
AdjustSfxVolume(f32),
|
|
||||||
//ChangeAudioDevice(String),
|
|
||||||
ChangeMaxFPS(Fps),
|
|
||||||
ChangeFOV(u16),
|
|
||||||
ChangeGamma(f32),
|
|
||||||
ChangeExposure(f32),
|
|
||||||
ChangeAmbiance(f32),
|
|
||||||
MapZoom(f64),
|
|
||||||
MapDrag(Vec2<f64>),
|
|
||||||
MapShowTopoMap(bool),
|
|
||||||
MapShowDifficulty(bool),
|
|
||||||
MapShowTowns(bool),
|
|
||||||
MapShowDungeons(bool),
|
|
||||||
MapShowCastles(bool),
|
|
||||||
MapShowCaves(bool),
|
|
||||||
MapShowTrees(bool),
|
|
||||||
AdjustWindowSize([u16; 2]),
|
|
||||||
ChangeFullscreenMode(FullScreenSettings),
|
|
||||||
ToggleParticlesEnabled(bool),
|
|
||||||
CrosshairTransp(f32),
|
|
||||||
ChatTransp(f32),
|
|
||||||
ChatCharName(bool),
|
|
||||||
CrosshairType(CrosshairType),
|
|
||||||
BuffPosition(BuffPosition),
|
|
||||||
ToggleXpBar(XpBar),
|
|
||||||
Intro(Intro),
|
|
||||||
ToggleBarNumbers(BarNumbers),
|
|
||||||
ToggleShortcutNumbers(ShortcutNumbers),
|
|
||||||
Sct(bool),
|
|
||||||
SctPlayerBatch(bool),
|
|
||||||
SctDamageBatch(bool),
|
|
||||||
SpeechBubbleDarkMode(bool),
|
|
||||||
SpeechBubbleIcon(bool),
|
|
||||||
ToggleDebug(bool),
|
|
||||||
UiScale(ScaleChange),
|
|
||||||
CharacterSelection,
|
CharacterSelection,
|
||||||
UseSlot {
|
UseSlot {
|
||||||
slot: comp::slot::Slot,
|
slot: comp::slot::Slot,
|
||||||
@ -423,19 +378,7 @@ pub enum Event {
|
|||||||
Ability4(bool),
|
Ability4(bool),
|
||||||
Logout,
|
Logout,
|
||||||
Quit,
|
Quit,
|
||||||
ChangeLanguage(Box<LanguageMetadata>),
|
|
||||||
ChangeBinding(GameInput),
|
|
||||||
ResetInterfaceSettings,
|
|
||||||
ResetGameplaySettings,
|
|
||||||
ResetKeyBindings,
|
|
||||||
ResetGraphicsSettings,
|
|
||||||
ResetAudioSettings,
|
|
||||||
ChangeFreeLookBehavior(PressBehavior),
|
|
||||||
ChangeRenderMode(Box<RenderMode>),
|
|
||||||
ChangeAutoWalkBehavior(PressBehavior),
|
|
||||||
ChangeCameraClampBehavior(PressBehavior),
|
|
||||||
ChangeStopAutoWalkOnInput(bool),
|
|
||||||
ChangeAutoCamera(bool),
|
|
||||||
CraftRecipe(String),
|
CraftRecipe(String),
|
||||||
InviteMember(Uid),
|
InviteMember(Uid),
|
||||||
AcceptInvite,
|
AcceptInvite,
|
||||||
@ -445,9 +388,9 @@ pub enum Event {
|
|||||||
AssignLeader(Uid),
|
AssignLeader(Uid),
|
||||||
RemoveBuff(BuffKind),
|
RemoveBuff(BuffKind),
|
||||||
UnlockSkill(Skill),
|
UnlockSkill(Skill),
|
||||||
MinimapShow(bool),
|
|
||||||
MinimapFaceNorth(bool),
|
|
||||||
RequestSiteInfo(SiteId),
|
RequestSiteInfo(SiteId),
|
||||||
|
|
||||||
|
SettingsChange(SettingsChange),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Are these the possible layouts we want?
|
// TODO: Are these the possible layouts we want?
|
||||||
@ -1878,7 +1821,9 @@ impl Hud {
|
|||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
self.show.intro = false;
|
self.show.intro = false;
|
||||||
events.push(Event::Intro(Intro::Never));
|
events.push(Event::SettingsChange(
|
||||||
|
InterfaceChange::Intro(Intro::Never).into(),
|
||||||
|
));
|
||||||
self.show.want_grab = true;
|
self.show.want_grab = true;
|
||||||
}
|
}
|
||||||
if !self.show.crafting && !self.show.bag {
|
if !self.show.crafting && !self.show.bag {
|
||||||
@ -2247,11 +2192,8 @@ impl Hud {
|
|||||||
)
|
)
|
||||||
.set(self.ids.minimap, ui_widgets)
|
.set(self.ids.minimap, ui_widgets)
|
||||||
{
|
{
|
||||||
Some(minimap::Event::Show(show)) => {
|
Some(minimap::Event::SettingsChange(interface_change)) => {
|
||||||
events.push(Event::MinimapShow(show));
|
events.push(Event::SettingsChange(interface_change.into()));
|
||||||
},
|
|
||||||
Some(minimap::Event::FaceNorth(should_face_north)) => {
|
|
||||||
events.push(Event::MinimapFaceNorth(should_face_north))
|
|
||||||
},
|
},
|
||||||
None => {},
|
None => {},
|
||||||
}
|
}
|
||||||
@ -2556,29 +2498,6 @@ impl Hud {
|
|||||||
.set(self.ids.settings_window, ui_widgets)
|
.set(self.ids.settings_window, ui_widgets)
|
||||||
{
|
{
|
||||||
match event {
|
match event {
|
||||||
settings_window::Event::SpeechBubbleDarkMode(sbdm) => {
|
|
||||||
events.push(Event::SpeechBubbleDarkMode(sbdm));
|
|
||||||
},
|
|
||||||
settings_window::Event::SpeechBubbleIcon(sbi) => {
|
|
||||||
events.push(Event::SpeechBubbleIcon(sbi));
|
|
||||||
},
|
|
||||||
settings_window::Event::Sct(sct) => {
|
|
||||||
events.push(Event::Sct(sct));
|
|
||||||
},
|
|
||||||
settings_window::Event::SctPlayerBatch(sct_player_batch) => {
|
|
||||||
events.push(Event::SctPlayerBatch(sct_player_batch));
|
|
||||||
},
|
|
||||||
settings_window::Event::SctDamageBatch(sct_damage_batch) => {
|
|
||||||
events.push(Event::SctDamageBatch(sct_damage_batch));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleHelp => self.show.help = !self.show.help,
|
|
||||||
settings_window::Event::ToggleDebug => {
|
|
||||||
self.show.debug = !self.show.debug;
|
|
||||||
events.push(Event::ToggleDebug(self.show.debug));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleTips(loading_tips) => {
|
|
||||||
events.push(Event::ToggleTips(loading_tips));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeTab(tab) => self.show.open_setting_tab(tab),
|
settings_window::Event::ChangeTab(tab) => self.show.open_setting_tab(tab),
|
||||||
settings_window::Event::Close => {
|
settings_window::Event::Close => {
|
||||||
// Unpause the game if we are on singleplayer so that we can logout
|
// Unpause the game if we are on singleplayer so that we can logout
|
||||||
@ -2589,136 +2508,24 @@ impl Hud {
|
|||||||
|
|
||||||
self.show.settings(false)
|
self.show.settings(false)
|
||||||
},
|
},
|
||||||
settings_window::Event::AdjustMousePan(sensitivity) => {
|
settings_window::Event::SettingsChange(settings_change) => {
|
||||||
events.push(Event::AdjustMousePan(sensitivity));
|
match &settings_change {
|
||||||
|
SettingsChange::Interface(interface_change) => match interface_change {
|
||||||
|
InterfaceChange::ToggleHelp(toggle_help) => {
|
||||||
|
self.show.help = *toggle_help;
|
||||||
},
|
},
|
||||||
settings_window::Event::AdjustMouseZoom(sensitivity) => {
|
InterfaceChange::ToggleDebug(toggle_debug) => {
|
||||||
events.push(Event::AdjustMouseZoom(sensitivity));
|
self.show.debug = *toggle_debug;
|
||||||
},
|
},
|
||||||
settings_window::Event::AdjustCameraClamp(sensitivity) => {
|
InterfaceChange::ResetInterfaceSettings => {
|
||||||
events.push(Event::AdjustCameraClamp(sensitivity));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChatTransp(chat_transp) => {
|
|
||||||
events.push(Event::ChatTransp(chat_transp));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChatCharName(chat_char_name) => {
|
|
||||||
events.push(Event::ChatCharName(chat_char_name));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleZoomInvert(zoom_inverted) => {
|
|
||||||
events.push(Event::ToggleZoomInvert(zoom_inverted));
|
|
||||||
},
|
|
||||||
settings_window::Event::BuffPosition(buff_position) => {
|
|
||||||
events.push(Event::BuffPosition(buff_position));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleMouseYInvert(mouse_y_inverted) => {
|
|
||||||
events.push(Event::ToggleMouseYInvert(mouse_y_inverted));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleControllerYInvert(controller_y_inverted) => {
|
|
||||||
events.push(Event::ToggleControllerYInvert(controller_y_inverted));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleSmoothPan(smooth_pan_enabled) => {
|
|
||||||
events.push(Event::ToggleSmoothPan(smooth_pan_enabled));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustViewDistance(view_distance) => {
|
|
||||||
events.push(Event::AdjustViewDistance(view_distance));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustLodDetail(lod_detail) => {
|
|
||||||
events.push(Event::AdjustLodDetail(lod_detail));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustSpriteRenderDistance(view_distance) => {
|
|
||||||
events.push(Event::AdjustSpriteRenderDistance(view_distance));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustFigureLoDRenderDistance(view_distance) => {
|
|
||||||
events.push(Event::AdjustFigureLoDRenderDistance(view_distance));
|
|
||||||
},
|
|
||||||
settings_window::Event::CrosshairTransp(crosshair_transp) => {
|
|
||||||
events.push(Event::CrosshairTransp(crosshair_transp));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustMusicVolume(music_volume) => {
|
|
||||||
events.push(Event::AdjustMusicVolume(music_volume));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustSfxVolume(sfx_volume) => {
|
|
||||||
events.push(Event::AdjustSfxVolume(sfx_volume));
|
|
||||||
},
|
|
||||||
settings_window::Event::MaximumFPS(max_fps) => {
|
|
||||||
events.push(Event::ChangeMaxFPS(max_fps));
|
|
||||||
},
|
|
||||||
//settings_window::Event::ChangeAudioDevice(name) => {
|
|
||||||
// events.push(Event::ChangeAudioDevice(name));
|
|
||||||
//},
|
|
||||||
settings_window::Event::CrosshairType(crosshair_type) => {
|
|
||||||
events.push(Event::CrosshairType(crosshair_type));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleBarNumbers(bar_numbers) => {
|
|
||||||
events.push(Event::ToggleBarNumbers(bar_numbers));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleShortcutNumbers(shortcut_numbers) => {
|
|
||||||
events.push(Event::ToggleShortcutNumbers(shortcut_numbers));
|
|
||||||
},
|
|
||||||
settings_window::Event::UiScale(scale_change) => {
|
|
||||||
events.push(Event::UiScale(scale_change));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustFOV(new_fov) => {
|
|
||||||
events.push(Event::ChangeFOV(new_fov));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustGamma(new_gamma) => {
|
|
||||||
events.push(Event::ChangeGamma(new_gamma));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustExposure(new_exposure) => {
|
|
||||||
events.push(Event::ChangeExposure(new_exposure));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustAmbiance(new_ambiance) => {
|
|
||||||
events.push(Event::ChangeAmbiance(new_ambiance));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeRenderMode(new_render_mode) => {
|
|
||||||
events.push(Event::ChangeRenderMode(new_render_mode));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeLanguage(language) => {
|
|
||||||
events.push(Event::ChangeLanguage(language));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeFullscreenMode(new_fullscreen_settings) => {
|
|
||||||
events.push(Event::ChangeFullscreenMode(new_fullscreen_settings));
|
|
||||||
},
|
|
||||||
settings_window::Event::ToggleParticlesEnabled(particles_enabled) => {
|
|
||||||
events.push(Event::ToggleParticlesEnabled(particles_enabled));
|
|
||||||
},
|
|
||||||
settings_window::Event::AdjustWindowSize(new_size) => {
|
|
||||||
events.push(Event::AdjustWindowSize(new_size));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeBinding(game_input) => {
|
|
||||||
events.push(Event::ChangeBinding(game_input));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeFreeLookBehavior(behavior) => {
|
|
||||||
events.push(Event::ChangeFreeLookBehavior(behavior));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeAutoWalkBehavior(behavior) => {
|
|
||||||
events.push(Event::ChangeAutoWalkBehavior(behavior));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeCameraClampBehavior(behavior) => {
|
|
||||||
events.push(Event::ChangeCameraClampBehavior(behavior));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeStopAutoWalkOnInput(state) => {
|
|
||||||
events.push(Event::ChangeStopAutoWalkOnInput(state));
|
|
||||||
},
|
|
||||||
settings_window::Event::ChangeAutoCamera(state) => {
|
|
||||||
events.push(Event::ChangeAutoCamera(state));
|
|
||||||
},
|
|
||||||
settings_window::Event::ResetInterfaceSettings => {
|
|
||||||
self.show.help = false;
|
self.show.help = false;
|
||||||
self.show.debug = false;
|
self.show.debug = false;
|
||||||
events.push(Event::ResetInterfaceSettings);
|
|
||||||
},
|
},
|
||||||
settings_window::Event::ResetGameplaySettings => {
|
_ => {},
|
||||||
events.push(Event::ResetGameplaySettings);
|
|
||||||
},
|
},
|
||||||
settings_window::Event::ResetKeyBindings => {
|
_ => {},
|
||||||
events.push(Event::ResetKeyBindings);
|
}
|
||||||
},
|
events.push(Event::SettingsChange(settings_change));
|
||||||
settings_window::Event::ResetGraphicsSettings => {
|
|
||||||
events.push(Event::ResetGraphicsSettings);
|
|
||||||
},
|
|
||||||
settings_window::Event::ResetAudioSettings => {
|
|
||||||
events.push(Event::ResetAudioSettings);
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2818,32 +2625,8 @@ impl Hud {
|
|||||||
self.show.want_grab = true;
|
self.show.want_grab = true;
|
||||||
self.force_ungrab = false;
|
self.force_ungrab = false;
|
||||||
},
|
},
|
||||||
map::Event::ShowTopoMap(map_show_topo_map) => {
|
map::Event::SettingsChange(settings_change) => {
|
||||||
events.push(Event::MapShowTopoMap(map_show_topo_map));
|
events.push(Event::SettingsChange(settings_change.into()));
|
||||||
},
|
|
||||||
map::Event::ShowDifficulties(map_show_difficulties) => {
|
|
||||||
events.push(Event::MapShowDifficulty(map_show_difficulties));
|
|
||||||
},
|
|
||||||
map::Event::ShowTowns(map_show_towns) => {
|
|
||||||
events.push(Event::MapShowTowns(map_show_towns));
|
|
||||||
},
|
|
||||||
map::Event::ShowCastles(map_show_castles) => {
|
|
||||||
events.push(Event::MapShowCastles(map_show_castles));
|
|
||||||
},
|
|
||||||
map::Event::ShowDungeons(map_show_dungeons) => {
|
|
||||||
events.push(Event::MapShowDungeons(map_show_dungeons));
|
|
||||||
},
|
|
||||||
map::Event::MapZoom(map_zoom) => {
|
|
||||||
events.push(Event::MapZoom(map_zoom));
|
|
||||||
},
|
|
||||||
map::Event::MapDrag(map_drag) => {
|
|
||||||
events.push(Event::MapDrag(map_drag));
|
|
||||||
},
|
|
||||||
map::Event::ShowCaves(map_show_caves) => {
|
|
||||||
events.push(Event::MapShowCaves(map_show_caves));
|
|
||||||
},
|
|
||||||
map::Event::ShowTrees(map_show_trees) => {
|
|
||||||
events.push(Event::MapShowTrees(map_show_trees));
|
|
||||||
},
|
},
|
||||||
map::Event::RequestSiteInfo(id) => {
|
map::Event::RequestSiteInfo(id) => {
|
||||||
events.push(Event::RequestSiteInfo(id));
|
events.push(Event::RequestSiteInfo(id));
|
||||||
@ -2854,7 +2637,9 @@ impl Hud {
|
|||||||
// Reset the map position when it's not showing
|
// Reset the map position when it's not showing
|
||||||
let drag = &global_state.settings.interface.map_drag;
|
let drag = &global_state.settings.interface.map_drag;
|
||||||
if drag.x != 0.0 || drag.y != 0.0 {
|
if drag.x != 0.0 || drag.y != 0.0 {
|
||||||
events.push(Event::MapDrag(Vec2::zero()))
|
events.push(Event::SettingsChange(
|
||||||
|
InterfaceChange::MapDrag(Vec2::zero()).into(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use super::{Event, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hud::{img_ids::Imgs, ERROR_COLOR, TEXT_BIND_CONFLICT_COLOR, TEXT_COLOR},
|
hud::{img_ids::Imgs, ERROR_COLOR, TEXT_BIND_CONFLICT_COLOR, TEXT_COLOR},
|
||||||
i18n::Localization,
|
i18n::Localization,
|
||||||
|
session::settings_change::{Control as ControlChange, Control::*},
|
||||||
ui::fonts::Fonts,
|
ui::fonts::Fonts,
|
||||||
window::GameInput,
|
window::GameInput,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
@ -57,7 +58,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Controls<'a> {
|
impl<'a> Widget for Controls<'a> {
|
||||||
type Event = Vec<Event>;
|
type Event = Vec<ControlChange>;
|
||||||
type State = State;
|
type State = State;
|
||||||
type Style = ();
|
type Style = ();
|
||||||
|
|
||||||
@ -167,7 +168,7 @@ impl<'a> Widget for Controls<'a> {
|
|||||||
.set(button_id, ui)
|
.set(button_id, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeBinding(game_input));
|
events.push(ChangeBinding(game_input));
|
||||||
}
|
}
|
||||||
// Set the previous id to the current one for the next cycle
|
// Set the previous id to the current one for the next cycle
|
||||||
previous_element_id = Some(text_id);
|
previous_element_id = Some(text_id);
|
||||||
@ -188,7 +189,7 @@ impl<'a> Widget for Controls<'a> {
|
|||||||
.set(state.ids.reset_controls_button, ui)
|
.set(state.ids.reset_controls_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ResetKeyBindings);
|
events.push(ResetKeyBindings);
|
||||||
}
|
}
|
||||||
previous_element_id = Some(state.ids.reset_controls_button)
|
previous_element_id = Some(state.ids.reset_controls_button)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use super::{Event, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hud::{img_ids::Imgs, PressBehavior, MENU_BG, TEXT_COLOR},
|
hud::{img_ids::Imgs, PressBehavior, MENU_BG, TEXT_COLOR},
|
||||||
i18n::Localization,
|
i18n::Localization,
|
||||||
|
session::settings_change::{Gameplay as GameplayChange, Gameplay::*},
|
||||||
ui::{fonts::Fonts, ImageSlider, ToggleButton},
|
ui::{fonts::Fonts, ImageSlider, ToggleButton},
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
@ -81,7 +82,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Gameplay<'a> {
|
impl<'a> Widget for Gameplay<'a> {
|
||||||
type Event = Vec<Event>;
|
type Event = Vec<GameplayChange>;
|
||||||
type State = State;
|
type State = State;
|
||||||
type Style = ();
|
type Style = ();
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.mouse_pan_slider, ui)
|
.set(state.ids.mouse_pan_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustMousePan(new_val));
|
events.push(AdjustMousePan(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&format!("{}", display_pan))
|
Text::new(&format!("{}", display_pan))
|
||||||
@ -172,7 +173,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.mouse_zoom_slider, ui)
|
.set(state.ids.mouse_zoom_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustMouseZoom(new_val));
|
events.push(AdjustMouseZoom(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&format!("{}", display_zoom))
|
Text::new(&format!("{}", display_zoom))
|
||||||
@ -208,7 +209,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.camera_clamp_slider, ui)
|
.set(state.ids.camera_clamp_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustCameraClamp(new_val));
|
events.push(AdjustCameraClamp(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&format!("{}", display_clamp))
|
Text::new(&format!("{}", display_clamp))
|
||||||
@ -231,7 +232,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.mouse_zoom_invert_button, ui);
|
.set(state.ids.mouse_zoom_invert_button, ui);
|
||||||
|
|
||||||
if self.global_state.settings.gameplay.zoom_inversion != zoom_inverted {
|
if self.global_state.settings.gameplay.zoom_inversion != zoom_inverted {
|
||||||
events.push(Event::ToggleZoomInvert(
|
events.push(ToggleZoomInvert(
|
||||||
!self.global_state.settings.gameplay.zoom_inversion,
|
!self.global_state.settings.gameplay.zoom_inversion,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -261,7 +262,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.mouse_y_invert_button, ui);
|
.set(state.ids.mouse_y_invert_button, ui);
|
||||||
|
|
||||||
if self.global_state.settings.gameplay.mouse_y_inversion != mouse_y_inverted {
|
if self.global_state.settings.gameplay.mouse_y_inversion != mouse_y_inverted {
|
||||||
events.push(Event::ToggleMouseYInvert(
|
events.push(ToggleMouseYInvert(
|
||||||
!self.global_state.settings.gameplay.mouse_y_inversion,
|
!self.global_state.settings.gameplay.mouse_y_inversion,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -291,7 +292,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.controller_y_invert_button, ui);
|
.set(state.ids.controller_y_invert_button, ui);
|
||||||
|
|
||||||
if self.global_state.settings.controller.pan_invert_y != controller_y_inverted {
|
if self.global_state.settings.controller.pan_invert_y != controller_y_inverted {
|
||||||
events.push(Event::ToggleControllerYInvert(
|
events.push(ToggleControllerYInvert(
|
||||||
!self.global_state.settings.controller.pan_invert_y,
|
!self.global_state.settings.controller.pan_invert_y,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -321,7 +322,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.smooth_pan_toggle_button, ui);
|
.set(state.ids.smooth_pan_toggle_button, ui);
|
||||||
|
|
||||||
if self.global_state.settings.gameplay.smooth_pan_enable != smooth_pan_enabled {
|
if self.global_state.settings.gameplay.smooth_pan_enable != smooth_pan_enabled {
|
||||||
events.push(Event::ToggleSmoothPan(
|
events.push(ToggleSmoothPan(
|
||||||
!self.global_state.settings.gameplay.smooth_pan_enable,
|
!self.global_state.settings.gameplay.smooth_pan_enable,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -371,8 +372,8 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.free_look_behavior_list, ui)
|
.set(state.ids.free_look_behavior_list, ui)
|
||||||
{
|
{
|
||||||
match clicked {
|
match clicked {
|
||||||
0 => events.push(Event::ChangeFreeLookBehavior(PressBehavior::Toggle)),
|
0 => events.push(ChangeFreeLookBehavior(PressBehavior::Toggle)),
|
||||||
1 => events.push(Event::ChangeFreeLookBehavior(PressBehavior::Hold)),
|
1 => events.push(ChangeFreeLookBehavior(PressBehavior::Hold)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,8 +402,8 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.auto_walk_behavior_list, ui)
|
.set(state.ids.auto_walk_behavior_list, ui)
|
||||||
{
|
{
|
||||||
match clicked {
|
match clicked {
|
||||||
0 => events.push(Event::ChangeAutoWalkBehavior(PressBehavior::Toggle)),
|
0 => events.push(ChangeAutoWalkBehavior(PressBehavior::Toggle)),
|
||||||
1 => events.push(Event::ChangeAutoWalkBehavior(PressBehavior::Hold)),
|
1 => events.push(ChangeAutoWalkBehavior(PressBehavior::Hold)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -431,8 +432,8 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.camera_clamp_behavior_list, ui)
|
.set(state.ids.camera_clamp_behavior_list, ui)
|
||||||
{
|
{
|
||||||
match clicked {
|
match clicked {
|
||||||
0 => events.push(Event::ChangeCameraClampBehavior(PressBehavior::Toggle)),
|
0 => events.push(ChangeCameraClampBehavior(PressBehavior::Toggle)),
|
||||||
1 => events.push(Event::ChangeCameraClampBehavior(PressBehavior::Hold)),
|
1 => events.push(ChangeCameraClampBehavior(PressBehavior::Hold)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -452,7 +453,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
if self.global_state.settings.gameplay.stop_auto_walk_on_input
|
if self.global_state.settings.gameplay.stop_auto_walk_on_input
|
||||||
!= stop_auto_walk_on_input_toggle
|
!= stop_auto_walk_on_input_toggle
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeStopAutoWalkOnInput(
|
events.push(ChangeStopAutoWalkOnInput(
|
||||||
!self.global_state.settings.gameplay.stop_auto_walk_on_input,
|
!self.global_state.settings.gameplay.stop_auto_walk_on_input,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -482,7 +483,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.auto_camera_button, ui);
|
.set(state.ids.auto_camera_button, ui);
|
||||||
|
|
||||||
if self.global_state.settings.gameplay.auto_camera != auto_camera_toggle {
|
if self.global_state.settings.gameplay.auto_camera != auto_camera_toggle {
|
||||||
events.push(Event::ChangeAutoCamera(
|
events.push(ChangeAutoCamera(
|
||||||
!self.global_state.settings.gameplay.auto_camera,
|
!self.global_state.settings.gameplay.auto_camera,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -509,7 +510,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.set(state.ids.reset_gameplay_button, ui)
|
.set(state.ids.reset_gameplay_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ResetGameplaySettings);
|
events.push(ResetGameplaySettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
events
|
events
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use super::{Event, ScaleChange, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
use super::{ScaleChange, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hud::{
|
hud::{
|
||||||
img_ids::Imgs, BarNumbers, BuffPosition, CrosshairType, ShortcutNumbers, Show, TEXT_COLOR,
|
img_ids::Imgs, BarNumbers, BuffPosition, CrosshairType, ShortcutNumbers, Show, TEXT_COLOR,
|
||||||
},
|
},
|
||||||
i18n::Localization,
|
i18n::Localization,
|
||||||
|
session::settings_change::{Interface as InterfaceChange, Interface::*},
|
||||||
ui::{fonts::Fonts, ImageSlider, ScaleMode, ToggleButton},
|
ui::{fonts::Fonts, ImageSlider, ScaleMode, ToggleButton},
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
@ -126,7 +127,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Interface<'a> {
|
impl<'a> Widget for Interface<'a> {
|
||||||
type Event = Vec<Event>;
|
type Event = Vec<InterfaceChange>;
|
||||||
type State = State;
|
type State = State;
|
||||||
type Style = ();
|
type Style = ();
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.button_help, ui);
|
.set(state.ids.button_help, ui);
|
||||||
|
|
||||||
if self.show.help != show_help {
|
if self.show.help != show_help {
|
||||||
events.push(Event::ToggleHelp);
|
events.push(ToggleHelp(show_help));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&self.localized_strings.get("hud.settings.help_window"))
|
Text::new(&self.localized_strings.get("hud.settings.help_window"))
|
||||||
@ -209,7 +210,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.load_tips_button, ui);
|
.set(state.ids.load_tips_button, ui);
|
||||||
|
|
||||||
if self.global_state.settings.interface.loading_tips != show_tips {
|
if self.global_state.settings.interface.loading_tips != show_tips {
|
||||||
events.push(Event::ToggleTips(
|
events.push(ToggleTips(
|
||||||
!self.global_state.settings.interface.loading_tips,
|
!self.global_state.settings.interface.loading_tips,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -234,7 +235,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.debug_button, ui);
|
.set(state.ids.debug_button, ui);
|
||||||
|
|
||||||
if self.show.debug != show_debug {
|
if self.show.debug != show_debug {
|
||||||
events.push(Event::ToggleDebug);
|
events.push(ToggleDebug(show_debug));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&self.localized_strings.get("hud.settings.debug_info"))
|
Text::new(&self.localized_strings.get("hud.settings.debug_info"))
|
||||||
@ -277,7 +278,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.was_clicked()
|
.was_clicked()
|
||||||
&& !relative_selected
|
&& !relative_selected
|
||||||
{
|
{
|
||||||
events.push(Event::UiScale(ScaleChange::ToRelative));
|
events.push(UiScale(ScaleChange::ToRelative));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(self.localized_strings.get("hud.settings.relative_scaling"))
|
Text::new(self.localized_strings.get("hud.settings.relative_scaling"))
|
||||||
@ -312,7 +313,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.was_clicked()
|
.was_clicked()
|
||||||
&& !absolute_selected
|
&& !absolute_selected
|
||||||
{
|
{
|
||||||
events.push(Event::UiScale(ScaleChange::ToAbsolute));
|
events.push(UiScale(ScaleChange::ToAbsolute));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(self.localized_strings.get("hud.settings.custom_scaling"))
|
Text::new(self.localized_strings.get("hud.settings.custom_scaling"))
|
||||||
@ -339,7 +340,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.ui_scale_slider, ui)
|
.set(state.ids.ui_scale_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::UiScale(ScaleChange::Adjust(2.0f64.powf(new_val))));
|
events.push(UiScale(ScaleChange::Adjust(2.0f64.powf(new_val))));
|
||||||
}
|
}
|
||||||
// Custom Scaling Text
|
// Custom Scaling Text
|
||||||
Text::new(&format!("{:.2}", scale))
|
Text::new(&format!("{:.2}", scale))
|
||||||
@ -384,7 +385,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.ch_1_bg, ui)
|
.set(state.ids.ch_1_bg, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::CrosshairType(CrosshairType::Round));
|
events.push(CrosshairType(CrosshairType::Round));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crosshair
|
// Crosshair
|
||||||
@ -427,7 +428,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.ch_2_bg, ui)
|
.set(state.ids.ch_2_bg, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::CrosshairType(CrosshairType::RoundEdges));
|
events.push(CrosshairType(CrosshairType::RoundEdges));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crosshair
|
// Crosshair
|
||||||
@ -470,7 +471,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.ch_3_bg, ui)
|
.set(state.ids.ch_3_bg, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::CrosshairType(CrosshairType::Edges));
|
events.push(CrosshairType(CrosshairType::Edges));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crosshair
|
// Crosshair
|
||||||
@ -519,7 +520,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.ch_transp_slider, ui)
|
.set(state.ids.ch_transp_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::CrosshairTransp(new_val));
|
events.push(CrosshairTransp(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&format!("{:.2}", crosshair_transp,))
|
Text::new(&format!("{:.2}", crosshair_transp,))
|
||||||
@ -562,12 +563,8 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
match self.global_state.settings.interface.shortcut_numbers {
|
match self.global_state.settings.interface.shortcut_numbers {
|
||||||
ShortcutNumbers::On => {
|
ShortcutNumbers::On => events.push(ToggleShortcutNumbers(ShortcutNumbers::Off)),
|
||||||
events.push(Event::ToggleShortcutNumbers(ShortcutNumbers::Off))
|
ShortcutNumbers::Off => events.push(ToggleShortcutNumbers(ShortcutNumbers::On)),
|
||||||
},
|
|
||||||
ShortcutNumbers::Off => {
|
|
||||||
events.push(Event::ToggleShortcutNumbers(ShortcutNumbers::On))
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Text::new(&self.localized_strings.get("hud.settings.toggle_shortcuts"))
|
Text::new(&self.localized_strings.get("hud.settings.toggle_shortcuts"))
|
||||||
@ -596,7 +593,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.buff_pos_bar_button, ui)
|
.set(state.ids.buff_pos_bar_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::BuffPosition(BuffPosition::Bar))
|
events.push(BuffPosition(BuffPosition::Bar))
|
||||||
}
|
}
|
||||||
Text::new(&self.localized_strings.get("hud.settings.buffs_skillbar"))
|
Text::new(&self.localized_strings.get("hud.settings.buffs_skillbar"))
|
||||||
.right_from(state.ids.buff_pos_bar_button, 10.0)
|
.right_from(state.ids.buff_pos_bar_button, 10.0)
|
||||||
@ -623,7 +620,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.buff_pos_map_button, ui)
|
.set(state.ids.buff_pos_map_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::BuffPosition(BuffPosition::Map))
|
events.push(BuffPosition(BuffPosition::Map))
|
||||||
}
|
}
|
||||||
Text::new(&self.localized_strings.get("hud.settings.buffs_mmap"))
|
Text::new(&self.localized_strings.get("hud.settings.buffs_mmap"))
|
||||||
.right_from(state.ids.buff_pos_map_button, 10.0)
|
.right_from(state.ids.buff_pos_map_button, 10.0)
|
||||||
@ -669,7 +666,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.sct_show_radio, ui);
|
.set(state.ids.sct_show_radio, ui);
|
||||||
|
|
||||||
if self.global_state.settings.interface.sct != show_sct {
|
if self.global_state.settings.interface.sct != show_sct {
|
||||||
events.push(Event::Sct(!self.global_state.settings.interface.sct))
|
events.push(Sct(!self.global_state.settings.interface.sct))
|
||||||
}
|
}
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
@ -719,7 +716,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.sct_show_batch_radio, ui);
|
.set(state.ids.sct_show_batch_radio, ui);
|
||||||
|
|
||||||
if self.global_state.settings.interface.sct_damage_batch != show_sct_damage_batch {
|
if self.global_state.settings.interface.sct_damage_batch != show_sct_damage_batch {
|
||||||
events.push(Event::SctDamageBatch(
|
events.push(SctDamageBatch(
|
||||||
!self.global_state.settings.interface.sct_damage_batch,
|
!self.global_state.settings.interface.sct_damage_batch,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -762,7 +759,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.sct_batch_inc_radio, ui);
|
.set(state.ids.sct_batch_inc_radio, ui);
|
||||||
|
|
||||||
if self.global_state.settings.interface.sct_player_batch != show_sct_player_batch {
|
if self.global_state.settings.interface.sct_player_batch != show_sct_player_batch {
|
||||||
events.push(Event::SctPlayerBatch(
|
events.push(SctPlayerBatch(
|
||||||
!self.global_state.settings.interface.sct_player_batch,
|
!self.global_state.settings.interface.sct_player_batch,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -806,7 +803,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
||||||
.set(state.ids.speech_bubble_dark_mode_button, ui);
|
.set(state.ids.speech_bubble_dark_mode_button, ui);
|
||||||
if self.global_state.settings.interface.speech_bubble_dark_mode != speech_bubble_dark_mode {
|
if self.global_state.settings.interface.speech_bubble_dark_mode != speech_bubble_dark_mode {
|
||||||
events.push(Event::SpeechBubbleDarkMode(speech_bubble_dark_mode));
|
events.push(SpeechBubbleDarkMode(speech_bubble_dark_mode));
|
||||||
}
|
}
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
@ -830,7 +827,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
||||||
.set(state.ids.speech_bubble_icon_button, ui);
|
.set(state.ids.speech_bubble_icon_button, ui);
|
||||||
if self.global_state.settings.interface.speech_bubble_icon != speech_bubble_icon {
|
if self.global_state.settings.interface.speech_bubble_icon != speech_bubble_icon {
|
||||||
events.push(Event::SpeechBubbleIcon(speech_bubble_icon));
|
events.push(SpeechBubbleIcon(speech_bubble_icon));
|
||||||
}
|
}
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
@ -873,7 +870,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.show_bar_numbers_none_button, ui)
|
.set(state.ids.show_bar_numbers_none_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ToggleBarNumbers(BarNumbers::Off))
|
events.push(ToggleBarNumbers(BarNumbers::Off))
|
||||||
}
|
}
|
||||||
Text::new(&self.localized_strings.get("hud.settings.none"))
|
Text::new(&self.localized_strings.get("hud.settings.none"))
|
||||||
.right_from(state.ids.show_bar_numbers_none_button, 10.0)
|
.right_from(state.ids.show_bar_numbers_none_button, 10.0)
|
||||||
@ -904,7 +901,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.show_bar_numbers_values_button, ui)
|
.set(state.ids.show_bar_numbers_values_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ToggleBarNumbers(BarNumbers::Values))
|
events.push(ToggleBarNumbers(BarNumbers::Values))
|
||||||
}
|
}
|
||||||
Text::new(&self.localized_strings.get("hud.settings.values"))
|
Text::new(&self.localized_strings.get("hud.settings.values"))
|
||||||
.right_from(state.ids.show_bar_numbers_values_button, 10.0)
|
.right_from(state.ids.show_bar_numbers_values_button, 10.0)
|
||||||
@ -935,7 +932,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.show_bar_numbers_percentage_button, ui)
|
.set(state.ids.show_bar_numbers_percentage_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ToggleBarNumbers(BarNumbers::Percent))
|
events.push(ToggleBarNumbers(BarNumbers::Percent))
|
||||||
}
|
}
|
||||||
Text::new(&self.localized_strings.get("hud.settings.percentages"))
|
Text::new(&self.localized_strings.get("hud.settings.percentages"))
|
||||||
.right_from(state.ids.show_bar_numbers_percentage_button, 10.0)
|
.right_from(state.ids.show_bar_numbers_percentage_button, 10.0)
|
||||||
@ -977,7 +974,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.chat_transp_slider, ui)
|
.set(state.ids.chat_transp_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChatTransp(new_val));
|
events.push(ChatTransp(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Show character names in chat" toggle button
|
// "Show character names in chat" toggle button
|
||||||
@ -992,7 +989,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
||||||
.set(state.ids.chat_char_name_button, ui);
|
.set(state.ids.chat_char_name_button, ui);
|
||||||
if self.global_state.settings.interface.chat_character_name != chat_char_name {
|
if self.global_state.settings.interface.chat_character_name != chat_char_name {
|
||||||
events.push(Event::ChatCharName(
|
events.push(ChatCharName(
|
||||||
!self.global_state.settings.interface.chat_character_name,
|
!self.global_state.settings.interface.chat_character_name,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -1023,7 +1020,7 @@ impl<'a> Widget for Interface<'a> {
|
|||||||
.set(state.ids.reset_interface_button, ui)
|
.set(state.ids.reset_interface_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ResetInterfaceSettings);
|
events.push(ResetInterfaceSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
events
|
events
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use super::Event;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hud::{img_ids::Imgs, TEXT_COLOR},
|
hud::{img_ids::Imgs, TEXT_COLOR},
|
||||||
i18n::list_localizations,
|
i18n::list_localizations,
|
||||||
|
session::settings_change::{Language as LanguageChange, Language::*},
|
||||||
ui::fonts::Fonts,
|
ui::fonts::Fonts,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
@ -45,7 +44,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Language<'a> {
|
impl<'a> Widget for Language<'a> {
|
||||||
type Event = Vec<Event>;
|
type Event = Vec<LanguageChange>;
|
||||||
type State = State;
|
type State = State;
|
||||||
type Style = ();
|
type Style = ();
|
||||||
|
|
||||||
@ -114,7 +113,7 @@ impl<'a> Widget for Language<'a> {
|
|||||||
.set(state.ids.language_list[i], ui)
|
.set(state.ids.language_list[i], ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeLanguage(Box::new(language.to_owned())));
|
events.push(ChangeLanguage(Box::new(language.to_owned())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,15 +6,10 @@ mod sound;
|
|||||||
mod video;
|
mod video;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hud::{
|
hud::{img_ids::Imgs, Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN},
|
||||||
img_ids::Imgs, BarNumbers, BuffPosition, CrosshairType, PressBehavior, ShortcutNumbers,
|
i18n::Localization,
|
||||||
Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
session::settings_change::SettingsChange,
|
||||||
},
|
|
||||||
i18n::{LanguageMetadata, Localization},
|
|
||||||
render::RenderMode,
|
|
||||||
settings::Fps,
|
|
||||||
ui::fonts::Fonts,
|
ui::fonts::Fonts,
|
||||||
window::{FullScreenSettings, GameInput},
|
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
@ -120,59 +115,9 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
ToggleHelp,
|
|
||||||
ToggleDebug,
|
|
||||||
ToggleTips(bool),
|
|
||||||
ToggleBarNumbers(BarNumbers),
|
|
||||||
ToggleShortcutNumbers(ShortcutNumbers),
|
|
||||||
BuffPosition(BuffPosition),
|
|
||||||
ChangeTab(SettingsTab),
|
ChangeTab(SettingsTab),
|
||||||
Close,
|
Close,
|
||||||
AdjustMousePan(u32),
|
SettingsChange(SettingsChange),
|
||||||
AdjustMouseZoom(u32),
|
|
||||||
AdjustCameraClamp(u32),
|
|
||||||
ToggleZoomInvert(bool),
|
|
||||||
ToggleMouseYInvert(bool),
|
|
||||||
ToggleControllerYInvert(bool),
|
|
||||||
ToggleSmoothPan(bool),
|
|
||||||
AdjustViewDistance(u32),
|
|
||||||
AdjustSpriteRenderDistance(u32),
|
|
||||||
AdjustFigureLoDRenderDistance(u32),
|
|
||||||
AdjustFOV(u16),
|
|
||||||
AdjustLodDetail(u32),
|
|
||||||
AdjustGamma(f32),
|
|
||||||
AdjustExposure(f32),
|
|
||||||
AdjustAmbiance(f32),
|
|
||||||
AdjustWindowSize([u16; 2]),
|
|
||||||
ChangeFullscreenMode(FullScreenSettings),
|
|
||||||
ToggleParticlesEnabled(bool),
|
|
||||||
ChangeRenderMode(Box<RenderMode>),
|
|
||||||
AdjustMusicVolume(f32),
|
|
||||||
AdjustSfxVolume(f32),
|
|
||||||
//ChangeAudioDevice(String),
|
|
||||||
MaximumFPS(Fps),
|
|
||||||
CrosshairTransp(f32),
|
|
||||||
CrosshairType(CrosshairType),
|
|
||||||
UiScale(ScaleChange),
|
|
||||||
ChatTransp(f32),
|
|
||||||
ChatCharName(bool),
|
|
||||||
Sct(bool),
|
|
||||||
SctPlayerBatch(bool),
|
|
||||||
SctDamageBatch(bool),
|
|
||||||
SpeechBubbleDarkMode(bool),
|
|
||||||
SpeechBubbleIcon(bool),
|
|
||||||
ChangeLanguage(Box<LanguageMetadata>),
|
|
||||||
ChangeBinding(GameInput),
|
|
||||||
ResetInterfaceSettings,
|
|
||||||
ResetGameplaySettings,
|
|
||||||
ResetKeyBindings,
|
|
||||||
ResetGraphicsSettings,
|
|
||||||
ResetAudioSettings,
|
|
||||||
ChangeFreeLookBehavior(PressBehavior),
|
|
||||||
ChangeAutoWalkBehavior(PressBehavior),
|
|
||||||
ChangeCameraClampBehavior(PressBehavior),
|
|
||||||
ChangeStopAutoWalkOnInput(bool),
|
|
||||||
ChangeAutoCamera(bool),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -294,41 +239,63 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
let imgs = self.imgs;
|
let imgs = self.imgs;
|
||||||
let fonts = self.fonts;
|
let fonts = self.fonts;
|
||||||
let localized_strings = self.localized_strings;
|
let localized_strings = self.localized_strings;
|
||||||
for event in match self.show.settings_tab {
|
match self.show.settings_tab {
|
||||||
SettingsTab::Interface => {
|
SettingsTab::Interface => {
|
||||||
|
for change in
|
||||||
interface::Interface::new(global_state, show, imgs, fonts, localized_strings)
|
interface::Interface::new(global_state, show, imgs, fonts, localized_strings)
|
||||||
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
||||||
.wh_of(state.ids.settings_content_align)
|
.wh_of(state.ids.settings_content_align)
|
||||||
.set(state.ids.interface, ui)
|
.set(state.ids.interface, ui)
|
||||||
|
{
|
||||||
|
events.push(Event::SettingsChange(change.into()));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SettingsTab::Gameplay => {
|
SettingsTab::Gameplay => {
|
||||||
gameplay::Gameplay::new(global_state, imgs, fonts, localized_strings)
|
for change in gameplay::Gameplay::new(global_state, imgs, fonts, localized_strings)
|
||||||
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
||||||
.wh_of(state.ids.settings_content_align)
|
.wh_of(state.ids.settings_content_align)
|
||||||
.set(state.ids.gameplay, ui)
|
.set(state.ids.gameplay, ui)
|
||||||
|
{
|
||||||
|
events.push(Event::SettingsChange(change.into()));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SettingsTab::Controls => {
|
SettingsTab::Controls => {
|
||||||
controls::Controls::new(global_state, imgs, fonts, localized_strings)
|
for change in controls::Controls::new(global_state, imgs, fonts, localized_strings)
|
||||||
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
||||||
.wh_of(state.ids.settings_content_align)
|
.wh_of(state.ids.settings_content_align)
|
||||||
.set(state.ids.controls, ui)
|
.set(state.ids.controls, ui)
|
||||||
|
{
|
||||||
|
events.push(Event::SettingsChange(change.into()));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SettingsTab::Video => {
|
SettingsTab::Video => {
|
||||||
|
for change in
|
||||||
video::Video::new(global_state, imgs, fonts, localized_strings, self.fps)
|
video::Video::new(global_state, imgs, fonts, localized_strings, self.fps)
|
||||||
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
||||||
.wh_of(state.ids.settings_content_align)
|
.wh_of(state.ids.settings_content_align)
|
||||||
.set(state.ids.video, ui)
|
.set(state.ids.video, ui)
|
||||||
|
{
|
||||||
|
events.push(Event::SettingsChange(change.into()));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SettingsTab::Sound => sound::Sound::new(global_state, imgs, fonts, localized_strings)
|
SettingsTab::Sound => {
|
||||||
|
for change in sound::Sound::new(global_state, imgs, fonts, localized_strings)
|
||||||
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
||||||
.wh_of(state.ids.settings_content_align)
|
.wh_of(state.ids.settings_content_align)
|
||||||
.set(state.ids.sound, ui),
|
.set(state.ids.sound, ui)
|
||||||
SettingsTab::Lang => language::Language::new(global_state, imgs, fonts)
|
{
|
||||||
|
events.push(Event::SettingsChange(change.into()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SettingsTab::Lang => {
|
||||||
|
for change in language::Language::new(global_state, imgs, fonts)
|
||||||
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
|
||||||
.wh_of(state.ids.settings_content_align)
|
.wh_of(state.ids.settings_content_align)
|
||||||
.set(state.ids.language, ui),
|
.set(state.ids.language, ui)
|
||||||
} {
|
{
|
||||||
events.push(event);
|
events.push(Event::SettingsChange(change.into()));
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
events
|
events
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use super::{Event, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hud::{img_ids::Imgs, TEXT_COLOR},
|
hud::{img_ids::Imgs, TEXT_COLOR},
|
||||||
i18n::Localization,
|
i18n::Localization,
|
||||||
|
session::settings_change::{Audio as AudioChange, Audio::*},
|
||||||
ui::{fonts::Fonts, ImageSlider},
|
ui::{fonts::Fonts, ImageSlider},
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
@ -59,7 +60,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Sound<'a> {
|
impl<'a> Widget for Sound<'a> {
|
||||||
type Event = Vec<Event>;
|
type Event = Vec<AudioChange>;
|
||||||
type State = State;
|
type State = State;
|
||||||
type Style = ();
|
type Style = ();
|
||||||
|
|
||||||
@ -114,7 +115,7 @@ impl<'a> Widget for Sound<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.audio_volume_slider, ui)
|
.set(state.ids.audio_volume_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustMusicVolume(new_val));
|
events.push(AdjustMusicVolume(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SFX Volume -------------------------------------------------------
|
// SFX Volume -------------------------------------------------------
|
||||||
@ -143,7 +144,7 @@ impl<'a> Widget for Sound<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.sfx_volume_slider, ui)
|
.set(state.ids.sfx_volume_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustSfxVolume(new_val));
|
events.push(AdjustSfxVolume(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio Device Selector
|
// Audio Device Selector
|
||||||
@ -170,7 +171,7 @@ impl<'a> Widget for Sound<'a> {
|
|||||||
// .set(state.ids.audio_device_list, ui)
|
// .set(state.ids.audio_device_list, ui)
|
||||||
//{
|
//{
|
||||||
// let new_val = device_list[clicked].clone();
|
// let new_val = device_list[clicked].clone();
|
||||||
// events.push(Event::ChangeAudioDevice(new_val));
|
// events.push(ChangeAudioDevice(new_val));
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Reset the sound settings to the default settings
|
// Reset the sound settings to the default settings
|
||||||
@ -187,7 +188,7 @@ impl<'a> Widget for Sound<'a> {
|
|||||||
.set(state.ids.reset_sound_button, ui)
|
.set(state.ids.reset_sound_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ResetAudioSettings);
|
events.push(ResetAudioSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
events
|
events
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{Event, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hud::{
|
hud::{
|
||||||
@ -10,6 +10,7 @@ use crate::{
|
|||||||
AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode,
|
AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode,
|
||||||
UpscaleMode,
|
UpscaleMode,
|
||||||
},
|
},
|
||||||
|
session::settings_change::{Graphics as GraphicsChange, Graphics::*},
|
||||||
settings::Fps,
|
settings::Fps,
|
||||||
ui::{fonts::Fonts, ImageSlider, ToggleButton},
|
ui::{fonts::Fonts, ImageSlider, ToggleButton},
|
||||||
window::{FullScreenSettings, FullscreenMode},
|
window::{FullScreenSettings, FullscreenMode},
|
||||||
@ -145,7 +146,7 @@ const FPS_CHOICES: [Fps; 12] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
impl<'a> Widget for Video<'a> {
|
impl<'a> Widget for Video<'a> {
|
||||||
type Event = Vec<Event>;
|
type Event = Vec<GraphicsChange>;
|
||||||
type State = State;
|
type State = State;
|
||||||
type Style = ();
|
type Style = ();
|
||||||
|
|
||||||
@ -226,7 +227,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.vd_slider, ui)
|
.set(state.ids.vd_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustViewDistance(new_val));
|
events.push(AdjustViewDistance(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&format!(
|
Text::new(&format!(
|
||||||
@ -264,7 +265,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.max_fps_slider, ui)
|
.set(state.ids.max_fps_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::MaximumFPS(FPS_CHOICES[which]));
|
events.push(ChangeMaxFPS(FPS_CHOICES[which]));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&self.global_state.settings.graphics.max_fps.to_string())
|
Text::new(&self.global_state.settings.graphics.max_fps.to_string())
|
||||||
@ -296,7 +297,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.fov_slider, ui)
|
.set(state.ids.fov_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustFOV(new_val));
|
events.push(ChangeFOV(new_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&format!("{}", self.global_state.settings.graphics.fov))
|
Text::new(&format!("{}", self.global_state.settings.graphics.fov))
|
||||||
@ -329,7 +330,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.lod_detail_slider, ui)
|
.set(state.ids.lod_detail_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustLodDetail(
|
events.push(AdjustLodDetail(
|
||||||
(5.0f32.powf(new_val as f32 / 10.0) * 100.0) as u32,
|
(5.0f32.powf(new_val as f32 / 10.0) * 100.0) as u32,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -366,7 +367,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.gamma_slider, ui)
|
.set(state.ids.gamma_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustGamma(2.0f32.powf(new_val as f32 / 8.0)));
|
events.push(ChangeGamma(2.0f32.powf(new_val as f32 / 8.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&format!("{:.2}", self.global_state.settings.graphics.gamma))
|
Text::new(&format!("{:.2}", self.global_state.settings.graphics.gamma))
|
||||||
@ -391,7 +392,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.exposure_slider, ui)
|
.set(state.ids.exposure_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustExposure(new_val as f32 / 16.0));
|
events.push(ChangeExposure(new_val as f32 / 16.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(&self.localized_strings.get("hud.settings.exposure"))
|
Text::new(&self.localized_strings.get("hud.settings.exposure"))
|
||||||
@ -429,7 +430,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.ambiance_slider, ui)
|
.set(state.ids.ambiance_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustAmbiance(new_val as f32));
|
events.push(ChangeAmbiance(new_val as f32));
|
||||||
}
|
}
|
||||||
Text::new(&self.localized_strings.get("hud.settings.ambiance"))
|
Text::new(&self.localized_strings.get("hud.settings.ambiance"))
|
||||||
.up_from(state.ids.ambiance_slider, 8.0)
|
.up_from(state.ids.ambiance_slider, 8.0)
|
||||||
@ -465,7 +466,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.sprite_dist_slider, ui)
|
.set(state.ids.sprite_dist_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustSpriteRenderDistance(new_val));
|
events.push(AdjustSpriteRenderDistance(new_val));
|
||||||
}
|
}
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
@ -505,7 +506,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.figure_dist_slider, ui)
|
.set(state.ids.figure_dist_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustFigureLoDRenderDistance(new_val));
|
events.push(AdjustFigureLoDRenderDistance(new_val));
|
||||||
}
|
}
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
@ -569,7 +570,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.down_from(state.ids.aa_mode_text, 8.0)
|
.down_from(state.ids.aa_mode_text, 8.0)
|
||||||
.set(state.ids.aa_mode_list, ui)
|
.set(state.ids.aa_mode_list, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
|
events.push(ChangeRenderMode(Box::new(RenderMode {
|
||||||
aa: mode_list[clicked],
|
aa: mode_list[clicked],
|
||||||
..render_mode.clone()
|
..render_mode.clone()
|
||||||
})));
|
})));
|
||||||
@ -609,7 +610,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.down_from(state.ids.upscale_factor_text, 8.0)
|
.down_from(state.ids.upscale_factor_text, 8.0)
|
||||||
.set(state.ids.upscale_factor_list, ui)
|
.set(state.ids.upscale_factor_list, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
|
events.push(ChangeRenderMode(Box::new(RenderMode {
|
||||||
upscale_mode: UpscaleMode {
|
upscale_mode: UpscaleMode {
|
||||||
factor: upscale_factors[clicked],
|
factor: upscale_factors[clicked],
|
||||||
},
|
},
|
||||||
@ -667,7 +668,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.down_from(state.ids.cloud_mode_text, 8.0)
|
.down_from(state.ids.cloud_mode_text, 8.0)
|
||||||
.set(state.ids.cloud_mode_list, ui)
|
.set(state.ids.cloud_mode_list, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
|
events.push(ChangeRenderMode(Box::new(RenderMode {
|
||||||
cloud: mode_list[clicked],
|
cloud: mode_list[clicked],
|
||||||
..render_mode.clone()
|
..render_mode.clone()
|
||||||
})));
|
})));
|
||||||
@ -706,7 +707,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.down_from(state.ids.fluid_mode_text, 8.0)
|
.down_from(state.ids.fluid_mode_text, 8.0)
|
||||||
.set(state.ids.fluid_mode_list, ui)
|
.set(state.ids.fluid_mode_list, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
|
events.push(ChangeRenderMode(Box::new(RenderMode {
|
||||||
fluid: mode_list[clicked],
|
fluid: mode_list[clicked],
|
||||||
..render_mode.clone()
|
..render_mode.clone()
|
||||||
})));
|
})));
|
||||||
@ -752,7 +753,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.down_from(state.ids.lighting_mode_text, 8.0)
|
.down_from(state.ids.lighting_mode_text, 8.0)
|
||||||
.set(state.ids.lighting_mode_list, ui)
|
.set(state.ids.lighting_mode_list, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
|
events.push(ChangeRenderMode(Box::new(RenderMode {
|
||||||
lighting: mode_list[clicked],
|
lighting: mode_list[clicked],
|
||||||
..render_mode.clone()
|
..render_mode.clone()
|
||||||
})));
|
})));
|
||||||
@ -799,7 +800,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.down_from(state.ids.shadow_mode_text, 8.0)
|
.down_from(state.ids.shadow_mode_text, 8.0)
|
||||||
.set(state.ids.shadow_mode_list, ui)
|
.set(state.ids.shadow_mode_list, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
|
events.push(ChangeRenderMode(Box::new(RenderMode {
|
||||||
shadow: mode_list[clicked],
|
shadow: mode_list[clicked],
|
||||||
..render_mode.clone()
|
..render_mode.clone()
|
||||||
})));
|
})));
|
||||||
@ -832,7 +833,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.pad_track((5.0, 5.0))
|
.pad_track((5.0, 5.0))
|
||||||
.set(state.ids.shadow_mode_map_resolution_slider, ui)
|
.set(state.ids.shadow_mode_map_resolution_slider, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
|
events.push(ChangeRenderMode(Box::new(RenderMode {
|
||||||
shadow: ShadowMode::Map(ShadowMapMode {
|
shadow: ShadowMode::Map(ShadowMapMode {
|
||||||
resolution: 2.0f32.powf(f32::from(new_val) / 4.0),
|
resolution: 2.0f32.powf(f32::from(new_val) / 4.0),
|
||||||
}),
|
}),
|
||||||
@ -870,7 +871,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.set(state.ids.particles_button, ui);
|
.set(state.ids.particles_button, ui);
|
||||||
|
|
||||||
if self.global_state.settings.graphics.particles_enabled != particles_enabled {
|
if self.global_state.settings.graphics.particles_enabled != particles_enabled {
|
||||||
events.push(Event::ToggleParticlesEnabled(particles_enabled));
|
events.push(ToggleParticlesEnabled(particles_enabled));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolution
|
// Resolution
|
||||||
@ -907,7 +908,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.down_from(state.ids.resolution_label, 10.0)
|
.down_from(state.ids.resolution_label, 10.0)
|
||||||
.set(state.ids.resolution, ui)
|
.set(state.ids.resolution, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
|
events.push(ChangeFullscreenMode(FullScreenSettings {
|
||||||
resolution: resolutions[clicked],
|
resolution: resolutions[clicked],
|
||||||
..self.global_state.settings.graphics.fullscreen
|
..self.global_state.settings.graphics.fullscreen
|
||||||
}));
|
}));
|
||||||
@ -971,7 +972,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.right_from(state.ids.resolution, 8.0)
|
.right_from(state.ids.resolution, 8.0)
|
||||||
.set(state.ids.bit_depth, ui)
|
.set(state.ids.bit_depth, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
|
events.push(ChangeFullscreenMode(FullScreenSettings {
|
||||||
bit_depth: if clicked == 0 {
|
bit_depth: if clicked == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@ -1025,7 +1026,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.right_from(state.ids.bit_depth, 8.0)
|
.right_from(state.ids.bit_depth, 8.0)
|
||||||
.set(state.ids.refresh_rate, ui)
|
.set(state.ids.refresh_rate, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
|
events.push(ChangeFullscreenMode(FullScreenSettings {
|
||||||
refresh_rate: if clicked == 0 {
|
refresh_rate: if clicked == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@ -1055,7 +1056,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.set(state.ids.fullscreen_button, ui);
|
.set(state.ids.fullscreen_button, ui);
|
||||||
|
|
||||||
if self.global_state.settings.graphics.fullscreen.enabled != enabled {
|
if self.global_state.settings.graphics.fullscreen.enabled != enabled {
|
||||||
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
|
events.push(ChangeFullscreenMode(FullScreenSettings {
|
||||||
enabled,
|
enabled,
|
||||||
..self.global_state.settings.graphics.fullscreen
|
..self.global_state.settings.graphics.fullscreen
|
||||||
}));
|
}));
|
||||||
@ -1092,7 +1093,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.down_from(state.ids.fullscreen_mode_text, 8.0)
|
.down_from(state.ids.fullscreen_mode_text, 8.0)
|
||||||
.set(state.ids.fullscreen_mode_list, ui)
|
.set(state.ids.fullscreen_mode_list, ui)
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
|
events.push(ChangeFullscreenMode(FullScreenSettings {
|
||||||
mode: mode_list[clicked],
|
mode: mode_list[clicked],
|
||||||
..self.global_state.settings.graphics.fullscreen
|
..self.global_state.settings.graphics.fullscreen
|
||||||
}));
|
}));
|
||||||
@ -1112,7 +1113,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.set(state.ids.save_window_size_button, ui)
|
.set(state.ids.save_window_size_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::AdjustWindowSize(
|
events.push(AdjustWindowSize(
|
||||||
self.global_state
|
self.global_state
|
||||||
.window
|
.window
|
||||||
.logical_size()
|
.logical_size()
|
||||||
@ -1136,7 +1137,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.set(state.ids.reset_graphics_button, ui)
|
.set(state.ids.reset_graphics_button, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ResetGraphicsSettings);
|
events.push(ResetGraphicsSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
events
|
events
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
pub mod settings_change;
|
||||||
|
|
||||||
use std::{cell::RefCell, collections::HashSet, rc::Rc, time::Duration};
|
use std::{cell::RefCell, collections::HashSet, rc::Rc, time::Duration};
|
||||||
|
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
@ -7,7 +9,6 @@ use vek::*;
|
|||||||
|
|
||||||
use client::{self, Client};
|
use client::{self, Client};
|
||||||
use common::{
|
use common::{
|
||||||
assets::AssetExt,
|
|
||||||
comp,
|
comp,
|
||||||
comp::{
|
comp::{
|
||||||
inventory::slot::{EquipSlot, Slot},
|
inventory::slot::{EquipSlot, Slot},
|
||||||
@ -33,20 +34,16 @@ use common_net::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
audio::sfx::SfxEvent,
|
audio::sfx::SfxEvent,
|
||||||
controller::ControllerSettings,
|
|
||||||
hud::{DebugInfo, Event as HudEvent, Hud, HudInfo, PromptDialogSettings},
|
hud::{DebugInfo, Event as HudEvent, Hud, HudInfo, PromptDialogSettings},
|
||||||
i18n::{i18n_asset_key, Localization},
|
|
||||||
key_state::KeyState,
|
key_state::KeyState,
|
||||||
menu::char_selection::CharSelectionState,
|
menu::char_selection::CharSelectionState,
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
scene::{camera, CameraMode, Scene, SceneData},
|
scene::{camera, CameraMode, Scene, SceneData},
|
||||||
settings::{
|
settings::Settings,
|
||||||
AudioSettings, ControlSettings, GamepadSettings, GameplaySettings, GraphicsSettings,
|
|
||||||
InterfaceSettings, Settings,
|
|
||||||
},
|
|
||||||
window::{AnalogGameInput, Event, GameInput},
|
window::{AnalogGameInput, Event, GameInput},
|
||||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||||
};
|
};
|
||||||
|
use settings_change::Language::ChangeLanguage;
|
||||||
|
|
||||||
/// The action to perform after a tick
|
/// The action to perform after a tick
|
||||||
enum TickAction {
|
enum TickAction {
|
||||||
@ -903,9 +900,9 @@ impl PlayState for SessionState {
|
|||||||
|
|
||||||
// Look for changes in the localization files
|
// Look for changes in the localization files
|
||||||
if global_state.i18n.reloaded() {
|
if global_state.i18n.reloaded() {
|
||||||
hud_events.push(HudEvent::ChangeLanguage(Box::new(
|
hud_events.push(HudEvent::SettingsChange(
|
||||||
global_state.i18n.read().metadata.clone(),
|
ChangeLanguage(Box::new(global_state.i18n.read().metadata.clone())).into(),
|
||||||
)));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maintain the UI.
|
// Maintain the UI.
|
||||||
@ -925,153 +922,7 @@ impl PlayState for SessionState {
|
|||||||
HudEvent::Quit => {
|
HudEvent::Quit => {
|
||||||
return PlayStateResult::Shutdown;
|
return PlayStateResult::Shutdown;
|
||||||
},
|
},
|
||||||
HudEvent::AdjustMousePan(sensitivity) => {
|
|
||||||
global_state.window.pan_sensitivity = sensitivity;
|
|
||||||
global_state.settings.gameplay.pan_sensitivity = sensitivity;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustMouseZoom(sensitivity) => {
|
|
||||||
global_state.window.zoom_sensitivity = sensitivity;
|
|
||||||
global_state.settings.gameplay.zoom_sensitivity = sensitivity;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustCameraClamp(angle) => {
|
|
||||||
global_state.settings.gameplay.camera_clamp_angle = angle;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleZoomInvert(zoom_inverted) => {
|
|
||||||
global_state.window.zoom_inversion = zoom_inverted;
|
|
||||||
global_state.settings.gameplay.zoom_inversion = zoom_inverted;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::Sct(sct) => {
|
|
||||||
global_state.settings.interface.sct = sct;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::SctPlayerBatch(sct_player_batch) => {
|
|
||||||
global_state.settings.interface.sct_player_batch = sct_player_batch;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleTips(loading_tips) => {
|
|
||||||
global_state.settings.interface.loading_tips = loading_tips;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::SctDamageBatch(sct_damage_batch) => {
|
|
||||||
global_state.settings.interface.sct_damage_batch = sct_damage_batch;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::SpeechBubbleDarkMode(sbdm) => {
|
|
||||||
global_state.settings.interface.speech_bubble_dark_mode = sbdm;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::SpeechBubbleIcon(sbi) => {
|
|
||||||
global_state.settings.interface.speech_bubble_icon = sbi;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleDebug(toggle_debug) => {
|
|
||||||
global_state.settings.interface.toggle_debug = toggle_debug;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleMouseYInvert(mouse_y_inverted) => {
|
|
||||||
global_state.window.mouse_y_inversion = mouse_y_inverted;
|
|
||||||
global_state.settings.gameplay.mouse_y_inversion = mouse_y_inverted;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleControllerYInvert(controller_y_inverted) => {
|
|
||||||
global_state.window.controller_settings.pan_invert_y =
|
|
||||||
controller_y_inverted;
|
|
||||||
global_state.settings.controller.pan_invert_y = controller_y_inverted;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleSmoothPan(smooth_pan_enabled) => {
|
|
||||||
global_state.settings.gameplay.smooth_pan_enable = smooth_pan_enabled;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustViewDistance(view_distance) => {
|
|
||||||
self.client.borrow_mut().set_view_distance(view_distance);
|
|
||||||
|
|
||||||
global_state.settings.graphics.view_distance = view_distance;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustLodDetail(lod_detail) => {
|
|
||||||
self.scene.lod.set_detail(lod_detail);
|
|
||||||
|
|
||||||
global_state.settings.graphics.lod_detail = lod_detail;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustSpriteRenderDistance(sprite_render_distance) => {
|
|
||||||
global_state.settings.graphics.sprite_render_distance =
|
|
||||||
sprite_render_distance;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustFigureLoDRenderDistance(figure_lod_render_distance) => {
|
|
||||||
global_state.settings.graphics.figure_lod_render_distance =
|
|
||||||
figure_lod_render_distance;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::CrosshairTransp(crosshair_transp) => {
|
|
||||||
global_state.settings.interface.crosshair_transp = crosshair_transp;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChatTransp(chat_transp) => {
|
|
||||||
global_state.settings.interface.chat_transp = chat_transp;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChatCharName(chat_char_name) => {
|
|
||||||
global_state.settings.interface.chat_character_name = chat_char_name;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::CrosshairType(crosshair_type) => {
|
|
||||||
global_state.settings.interface.crosshair_type = crosshair_type;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::Intro(intro_show) => {
|
|
||||||
global_state.settings.interface.intro_show = intro_show;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleXpBar(xp_bar) => {
|
|
||||||
global_state.settings.interface.xp_bar = xp_bar;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleBarNumbers(bar_numbers) => {
|
|
||||||
global_state.settings.interface.bar_numbers = bar_numbers;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleShortcutNumbers(shortcut_numbers) => {
|
|
||||||
global_state.settings.interface.shortcut_numbers = shortcut_numbers;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::BuffPosition(buff_position) => {
|
|
||||||
global_state.settings.interface.buff_position = buff_position;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::UiScale(scale_change) => {
|
|
||||||
global_state.settings.interface.ui_scale =
|
|
||||||
self.hud.scale_change(scale_change);
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustMusicVolume(music_volume) => {
|
|
||||||
global_state.audio.set_music_volume(music_volume);
|
|
||||||
|
|
||||||
global_state.settings.audio.music_volume = music_volume;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustSfxVolume(sfx_volume) => {
|
|
||||||
global_state.audio.set_sfx_volume(sfx_volume);
|
|
||||||
|
|
||||||
global_state.settings.audio.sfx_volume = sfx_volume;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
//HudEvent::ChangeAudioDevice(name) => {
|
|
||||||
// global_state.audio.set_device(name.clone());
|
|
||||||
|
|
||||||
// global_state.settings.audio.output = AudioOutput::Device(name);
|
|
||||||
// global_state.settings.save_to_file_warn();
|
|
||||||
//},
|
|
||||||
HudEvent::ChangeMaxFPS(fps) => {
|
|
||||||
global_state.settings.graphics.max_fps = fps;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::RemoveBuff(buff_id) => {
|
HudEvent::RemoveBuff(buff_id) => {
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
client.remove_buff(buff_id);
|
client.remove_buff(buff_id);
|
||||||
@ -1317,124 +1168,12 @@ impl PlayState for SessionState {
|
|||||||
target_entity.map(|t| t.0),
|
target_entity.map(|t| t.0),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
HudEvent::ChangeFOV(new_fov) => {
|
|
||||||
global_state.settings.graphics.fov = new_fov;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
self.scene.camera_mut().set_fov_deg(new_fov);
|
|
||||||
self.scene
|
|
||||||
.camera_mut()
|
|
||||||
.compute_dependents(&*self.client.borrow().state().terrain());
|
|
||||||
},
|
|
||||||
HudEvent::MapZoom(map_zoom) => {
|
|
||||||
global_state.settings.interface.map_zoom = map_zoom;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MapDrag(map_drag) => {
|
|
||||||
global_state.settings.interface.map_drag = map_drag;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MapShowTopoMap(map_show_topo_map) => {
|
|
||||||
global_state.settings.interface.map_show_topo_map = map_show_topo_map;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MapShowDifficulty(map_show_difficulty) => {
|
|
||||||
global_state.settings.interface.map_show_difficulty = map_show_difficulty;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MapShowTowns(map_show_towns) => {
|
|
||||||
global_state.settings.interface.map_show_towns = map_show_towns;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MapShowDungeons(map_show_dungeons) => {
|
|
||||||
global_state.settings.interface.map_show_dungeons = map_show_dungeons;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MapShowCastles(map_show_castles) => {
|
|
||||||
global_state.settings.interface.map_show_castles = map_show_castles;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MapShowCaves(map_show_caves) => {
|
|
||||||
global_state.settings.interface.map_show_caves = map_show_caves;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MapShowTrees(map_show_trees) => {
|
|
||||||
global_state.settings.interface.map_show_trees = map_show_trees;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::RequestSiteInfo(id) => {
|
HudEvent::RequestSiteInfo(id) => {
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
client.request_site_economy(id);
|
client.request_site_economy(id);
|
||||||
},
|
},
|
||||||
HudEvent::ChangeGamma(new_gamma) => {
|
|
||||||
global_state.settings.graphics.gamma = new_gamma;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeExposure(new_exposure) => {
|
|
||||||
global_state.settings.graphics.exposure = new_exposure;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeAmbiance(new_ambiance) => {
|
|
||||||
global_state.settings.graphics.ambiance = new_ambiance;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeRenderMode(new_render_mode) => {
|
|
||||||
// Do this first so if it crashes the setting isn't saved :)
|
|
||||||
global_state
|
|
||||||
.window
|
|
||||||
.renderer_mut()
|
|
||||||
.set_render_mode((&*new_render_mode).clone())
|
|
||||||
.unwrap();
|
|
||||||
global_state.settings.graphics.render_mode = *new_render_mode;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeLanguage(new_language) => {
|
|
||||||
global_state.settings.language.selected_language =
|
|
||||||
new_language.language_identifier;
|
|
||||||
global_state.i18n = Localization::load_expect(&i18n_asset_key(
|
|
||||||
&global_state.settings.language.selected_language,
|
|
||||||
));
|
|
||||||
global_state.i18n.read().log_missing_entries();
|
|
||||||
self.hud.update_fonts(&global_state.i18n.read());
|
|
||||||
},
|
|
||||||
HudEvent::ChangeFullscreenMode(new_fullscreen_settings) => {
|
|
||||||
global_state
|
|
||||||
.window
|
|
||||||
.set_fullscreen_mode(new_fullscreen_settings);
|
|
||||||
global_state.settings.graphics.fullscreen = new_fullscreen_settings;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ToggleParticlesEnabled(particles_enabled) => {
|
|
||||||
global_state.settings.graphics.particles_enabled = particles_enabled;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::AdjustWindowSize(new_size) => {
|
|
||||||
global_state.window.set_size(new_size.into());
|
|
||||||
global_state.settings.graphics.window_size = new_size;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeBinding(game_input) => {
|
|
||||||
global_state.window.set_keybinding_mode(game_input);
|
|
||||||
},
|
|
||||||
HudEvent::ChangeFreeLookBehavior(behavior) => {
|
|
||||||
global_state.settings.gameplay.free_look_behavior = behavior;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeAutoWalkBehavior(behavior) => {
|
|
||||||
global_state.settings.gameplay.auto_walk_behavior = behavior;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeCameraClampBehavior(behavior) => {
|
|
||||||
global_state.settings.gameplay.camera_clamp_behavior = behavior;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeStopAutoWalkOnInput(state) => {
|
|
||||||
global_state.settings.gameplay.stop_auto_walk_on_input = state;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ChangeAutoCamera(state) => {
|
|
||||||
global_state.settings.gameplay.auto_camera = state;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::CraftRecipe(r) => {
|
HudEvent::CraftRecipe(r) => {
|
||||||
self.client.borrow_mut().craft_recipe(&r);
|
self.client.borrow_mut().craft_recipe(&r);
|
||||||
},
|
},
|
||||||
@ -1456,83 +1195,8 @@ impl PlayState for SessionState {
|
|||||||
HudEvent::AssignLeader(uid) => {
|
HudEvent::AssignLeader(uid) => {
|
||||||
self.client.borrow_mut().assign_group_leader(uid);
|
self.client.borrow_mut().assign_group_leader(uid);
|
||||||
},
|
},
|
||||||
HudEvent::MinimapShow(state) => {
|
HudEvent::SettingsChange(settings_change) => {
|
||||||
global_state.settings.interface.minimap_show = state;
|
settings_change.process(global_state, self);
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::MinimapFaceNorth(state) => {
|
|
||||||
global_state.settings.interface.minimap_face_north = state;
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ResetInterfaceSettings => {
|
|
||||||
// Reset Interface Settings
|
|
||||||
let tmp = global_state.settings.interface.intro_show;
|
|
||||||
global_state.settings.interface = InterfaceSettings::default();
|
|
||||||
global_state.settings.interface.intro_show = tmp;
|
|
||||||
// Update Current Scaling Mode
|
|
||||||
self.hud
|
|
||||||
.set_scaling_mode(global_state.settings.interface.ui_scale);
|
|
||||||
// Save to File
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ResetGameplaySettings => {
|
|
||||||
// Reset Gameplay Settings
|
|
||||||
global_state.settings.gameplay = GameplaySettings::default();
|
|
||||||
// Reset Gamepad and Controller Settings
|
|
||||||
global_state.settings.controller = GamepadSettings::default();
|
|
||||||
global_state.window.controller_settings =
|
|
||||||
ControllerSettings::from(&global_state.settings.controller);
|
|
||||||
// Pan Sensitivity
|
|
||||||
global_state.window.pan_sensitivity =
|
|
||||||
global_state.settings.gameplay.pan_sensitivity;
|
|
||||||
// Zoom Sensitivity
|
|
||||||
global_state.window.zoom_sensitivity =
|
|
||||||
global_state.settings.gameplay.zoom_sensitivity;
|
|
||||||
// Invert Scroll Zoom
|
|
||||||
global_state.window.zoom_inversion =
|
|
||||||
global_state.settings.gameplay.zoom_inversion;
|
|
||||||
// Invert Mouse Y Axis
|
|
||||||
global_state.window.mouse_y_inversion =
|
|
||||||
global_state.settings.gameplay.mouse_y_inversion;
|
|
||||||
// Save to File
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ResetKeyBindings => {
|
|
||||||
global_state.settings.controls = ControlSettings::default();
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
},
|
|
||||||
HudEvent::ResetGraphicsSettings => {
|
|
||||||
global_state.settings.graphics = GraphicsSettings::default();
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
let graphics = &global_state.settings.graphics;
|
|
||||||
// View distance
|
|
||||||
self.client
|
|
||||||
.borrow_mut()
|
|
||||||
.set_view_distance(graphics.view_distance);
|
|
||||||
// FOV
|
|
||||||
self.scene.camera_mut().set_fov_deg(graphics.fov);
|
|
||||||
self.scene
|
|
||||||
.camera_mut()
|
|
||||||
.compute_dependents(&*self.client.borrow().state().terrain());
|
|
||||||
// LoD
|
|
||||||
self.scene.lod.set_detail(graphics.lod_detail);
|
|
||||||
// Render mode
|
|
||||||
global_state
|
|
||||||
.window
|
|
||||||
.renderer_mut()
|
|
||||||
.set_render_mode(graphics.render_mode.clone())
|
|
||||||
.unwrap();
|
|
||||||
// Fullscreen mode
|
|
||||||
global_state.window.set_fullscreen_mode(graphics.fullscreen);
|
|
||||||
// Window size
|
|
||||||
global_state.window.set_size(graphics.window_size.into());
|
|
||||||
},
|
|
||||||
HudEvent::ResetAudioSettings => {
|
|
||||||
global_state.settings.audio = AudioSettings::default();
|
|
||||||
global_state.settings.save_to_file_warn();
|
|
||||||
let audio = &global_state.settings.audio;
|
|
||||||
global_state.audio.set_music_volume(audio.music_volume);
|
|
||||||
global_state.audio.set_sfx_volume(audio.sfx_volume);
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
459
voxygen/src/session/settings_change.rs
Normal file
459
voxygen/src/session/settings_change.rs
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
use super::SessionState;
|
||||||
|
use crate::{
|
||||||
|
controller::ControllerSettings,
|
||||||
|
hud::{
|
||||||
|
BarNumbers, BuffPosition, CrosshairType, Intro, PressBehavior, ScaleChange,
|
||||||
|
ShortcutNumbers, XpBar,
|
||||||
|
},
|
||||||
|
i18n::{i18n_asset_key, LanguageMetadata, Localization},
|
||||||
|
render::RenderMode,
|
||||||
|
settings::{
|
||||||
|
AudioSettings, ControlSettings, Fps, GamepadSettings, GameplaySettings, GraphicsSettings,
|
||||||
|
InterfaceSettings,
|
||||||
|
},
|
||||||
|
window::{FullScreenSettings, GameInput},
|
||||||
|
GlobalState,
|
||||||
|
};
|
||||||
|
use common::assets::AssetExt;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Audio {
|
||||||
|
AdjustMusicVolume(f32),
|
||||||
|
AdjustSfxVolume(f32),
|
||||||
|
//ChangeAudioDevice(String),
|
||||||
|
ResetAudioSettings,
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Control {
|
||||||
|
ChangeBinding(GameInput),
|
||||||
|
ResetKeyBindings,
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Gamepad {}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Gameplay {
|
||||||
|
AdjustMousePan(u32),
|
||||||
|
AdjustMouseZoom(u32),
|
||||||
|
AdjustCameraClamp(u32),
|
||||||
|
|
||||||
|
ToggleControllerYInvert(bool),
|
||||||
|
ToggleMouseYInvert(bool),
|
||||||
|
ToggleZoomInvert(bool),
|
||||||
|
|
||||||
|
ToggleSmoothPan(bool),
|
||||||
|
|
||||||
|
ChangeFreeLookBehavior(PressBehavior),
|
||||||
|
ChangeAutoWalkBehavior(PressBehavior),
|
||||||
|
ChangeCameraClampBehavior(PressBehavior),
|
||||||
|
ChangeStopAutoWalkOnInput(bool),
|
||||||
|
ChangeAutoCamera(bool),
|
||||||
|
|
||||||
|
ResetGameplaySettings,
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Graphics {
|
||||||
|
AdjustViewDistance(u32),
|
||||||
|
AdjustLodDetail(u32),
|
||||||
|
AdjustSpriteRenderDistance(u32),
|
||||||
|
AdjustFigureLoDRenderDistance(u32),
|
||||||
|
|
||||||
|
ChangeMaxFPS(Fps),
|
||||||
|
ChangeFOV(u16),
|
||||||
|
|
||||||
|
ChangeGamma(f32),
|
||||||
|
ChangeExposure(f32),
|
||||||
|
ChangeAmbiance(f32),
|
||||||
|
|
||||||
|
ChangeRenderMode(Box<RenderMode>),
|
||||||
|
|
||||||
|
ChangeFullscreenMode(FullScreenSettings),
|
||||||
|
ToggleParticlesEnabled(bool),
|
||||||
|
AdjustWindowSize([u16; 2]),
|
||||||
|
|
||||||
|
ResetGraphicsSettings,
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Interface {
|
||||||
|
Sct(bool),
|
||||||
|
SctPlayerBatch(bool),
|
||||||
|
SctDamageBatch(bool),
|
||||||
|
SpeechBubbleDarkMode(bool),
|
||||||
|
SpeechBubbleIcon(bool),
|
||||||
|
ToggleHelp(bool),
|
||||||
|
ToggleDebug(bool),
|
||||||
|
ToggleTips(bool),
|
||||||
|
|
||||||
|
CrosshairTransp(f32),
|
||||||
|
ChatTransp(f32),
|
||||||
|
ChatCharName(bool),
|
||||||
|
CrosshairType(CrosshairType),
|
||||||
|
Intro(Intro),
|
||||||
|
ToggleXpBar(XpBar),
|
||||||
|
ToggleBarNumbers(BarNumbers),
|
||||||
|
ToggleShortcutNumbers(ShortcutNumbers),
|
||||||
|
BuffPosition(BuffPosition),
|
||||||
|
|
||||||
|
UiScale(ScaleChange),
|
||||||
|
//Minimap
|
||||||
|
MinimapShow(bool),
|
||||||
|
MinimapFaceNorth(bool),
|
||||||
|
//Map settings
|
||||||
|
MapZoom(f64),
|
||||||
|
MapDrag(Vec2<f64>),
|
||||||
|
MapShowTopoMap(bool),
|
||||||
|
MapShowDifficulty(bool),
|
||||||
|
MapShowTowns(bool),
|
||||||
|
MapShowDungeons(bool),
|
||||||
|
MapShowCastles(bool),
|
||||||
|
MapShowCaves(bool),
|
||||||
|
MapShowTrees(bool),
|
||||||
|
|
||||||
|
ResetInterfaceSettings,
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Language {
|
||||||
|
ChangeLanguage(Box<LanguageMetadata>),
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Networking {}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum SettingsChange {
|
||||||
|
Audio(Audio),
|
||||||
|
Control(Control),
|
||||||
|
Gamepad(Gamepad),
|
||||||
|
Gameplay(Gameplay),
|
||||||
|
Graphics(Graphics),
|
||||||
|
Interface(Interface),
|
||||||
|
Language(Language),
|
||||||
|
Networking(Networking),
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! settings_change_from {
|
||||||
|
($i: ident) => {
|
||||||
|
impl From<$i> for SettingsChange {
|
||||||
|
fn from(change: $i) -> Self { SettingsChange::$i(change) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
settings_change_from!(Audio);
|
||||||
|
settings_change_from!(Control);
|
||||||
|
settings_change_from!(Gamepad);
|
||||||
|
settings_change_from!(Gameplay);
|
||||||
|
settings_change_from!(Graphics);
|
||||||
|
settings_change_from!(Interface);
|
||||||
|
settings_change_from!(Language);
|
||||||
|
settings_change_from!(Networking);
|
||||||
|
|
||||||
|
impl SettingsChange {
|
||||||
|
pub fn process(self, global_state: &mut GlobalState, session_state: &mut SessionState) {
|
||||||
|
let mut settings = &mut global_state.settings;
|
||||||
|
match self {
|
||||||
|
SettingsChange::Audio(audio_change) => {
|
||||||
|
match audio_change {
|
||||||
|
Audio::AdjustMusicVolume(music_volume) => {
|
||||||
|
global_state.audio.set_music_volume(music_volume);
|
||||||
|
|
||||||
|
settings.audio.music_volume = music_volume;
|
||||||
|
},
|
||||||
|
Audio::AdjustSfxVolume(sfx_volume) => {
|
||||||
|
global_state.audio.set_sfx_volume(sfx_volume);
|
||||||
|
|
||||||
|
settings.audio.sfx_volume = sfx_volume;
|
||||||
|
},
|
||||||
|
//Audio::ChangeAudioDevice(name) => {
|
||||||
|
// global_state.audio.set_device(name.clone());
|
||||||
|
|
||||||
|
// settings.audio.output = AudioOutput::Device(name);
|
||||||
|
//},
|
||||||
|
Audio::ResetAudioSettings => {
|
||||||
|
settings.audio = AudioSettings::default();
|
||||||
|
let audio = &settings.audio;
|
||||||
|
global_state.audio.set_music_volume(audio.music_volume);
|
||||||
|
global_state.audio.set_sfx_volume(audio.sfx_volume);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
settings.save_to_file_warn();
|
||||||
|
},
|
||||||
|
SettingsChange::Control(control_change) => match control_change {
|
||||||
|
Control::ChangeBinding(game_input) => {
|
||||||
|
global_state.window.set_keybinding_mode(game_input);
|
||||||
|
},
|
||||||
|
Control::ResetKeyBindings => {
|
||||||
|
settings.controls = ControlSettings::default();
|
||||||
|
settings.save_to_file_warn();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SettingsChange::Gamepad(gamepad_change) => match gamepad_change {},
|
||||||
|
SettingsChange::Gameplay(gameplay_change) => {
|
||||||
|
let mut window = &mut global_state.window;
|
||||||
|
match gameplay_change {
|
||||||
|
Gameplay::AdjustMousePan(sensitivity) => {
|
||||||
|
window.pan_sensitivity = sensitivity;
|
||||||
|
settings.gameplay.pan_sensitivity = sensitivity;
|
||||||
|
},
|
||||||
|
Gameplay::AdjustMouseZoom(sensitivity) => {
|
||||||
|
window.zoom_sensitivity = sensitivity;
|
||||||
|
settings.gameplay.zoom_sensitivity = sensitivity;
|
||||||
|
},
|
||||||
|
Gameplay::AdjustCameraClamp(angle) => {
|
||||||
|
settings.gameplay.camera_clamp_angle = angle;
|
||||||
|
},
|
||||||
|
Gameplay::ToggleControllerYInvert(controller_y_inverted) => {
|
||||||
|
window.controller_settings.pan_invert_y = controller_y_inverted;
|
||||||
|
settings.controller.pan_invert_y = controller_y_inverted;
|
||||||
|
},
|
||||||
|
Gameplay::ToggleMouseYInvert(mouse_y_inverted) => {
|
||||||
|
window.mouse_y_inversion = mouse_y_inverted;
|
||||||
|
settings.gameplay.mouse_y_inversion = mouse_y_inverted;
|
||||||
|
},
|
||||||
|
Gameplay::ToggleZoomInvert(zoom_inverted) => {
|
||||||
|
window.zoom_inversion = zoom_inverted;
|
||||||
|
settings.gameplay.zoom_inversion = zoom_inverted;
|
||||||
|
},
|
||||||
|
Gameplay::ToggleSmoothPan(smooth_pan_enabled) => {
|
||||||
|
settings.gameplay.smooth_pan_enable = smooth_pan_enabled;
|
||||||
|
},
|
||||||
|
Gameplay::ChangeFreeLookBehavior(behavior) => {
|
||||||
|
settings.gameplay.free_look_behavior = behavior;
|
||||||
|
},
|
||||||
|
Gameplay::ChangeAutoWalkBehavior(behavior) => {
|
||||||
|
settings.gameplay.auto_walk_behavior = behavior;
|
||||||
|
},
|
||||||
|
Gameplay::ChangeCameraClampBehavior(behavior) => {
|
||||||
|
settings.gameplay.camera_clamp_behavior = behavior;
|
||||||
|
},
|
||||||
|
Gameplay::ChangeStopAutoWalkOnInput(state) => {
|
||||||
|
settings.gameplay.stop_auto_walk_on_input = state;
|
||||||
|
},
|
||||||
|
Gameplay::ChangeAutoCamera(state) => {
|
||||||
|
settings.gameplay.auto_camera = state;
|
||||||
|
},
|
||||||
|
Gameplay::ResetGameplaySettings => {
|
||||||
|
// Reset Gameplay Settings
|
||||||
|
settings.gameplay = GameplaySettings::default();
|
||||||
|
// Reset Gamepad and Controller Settings
|
||||||
|
settings.controller = GamepadSettings::default();
|
||||||
|
window.controller_settings = ControllerSettings::from(&settings.controller);
|
||||||
|
// Pan Sensitivity
|
||||||
|
window.pan_sensitivity = settings.gameplay.pan_sensitivity;
|
||||||
|
// Zoom Sensitivity
|
||||||
|
window.zoom_sensitivity = settings.gameplay.zoom_sensitivity;
|
||||||
|
// Invert Scroll Zoom
|
||||||
|
window.zoom_inversion = settings.gameplay.zoom_inversion;
|
||||||
|
// Invert Mouse Y Axis
|
||||||
|
window.mouse_y_inversion = settings.gameplay.mouse_y_inversion;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
settings.save_to_file_warn();
|
||||||
|
},
|
||||||
|
SettingsChange::Graphics(graphics_change) => {
|
||||||
|
match graphics_change {
|
||||||
|
Graphics::AdjustViewDistance(view_distance) => {
|
||||||
|
session_state
|
||||||
|
.client
|
||||||
|
.borrow_mut()
|
||||||
|
.set_view_distance(view_distance);
|
||||||
|
|
||||||
|
settings.graphics.view_distance = view_distance;
|
||||||
|
},
|
||||||
|
Graphics::AdjustLodDetail(lod_detail) => {
|
||||||
|
session_state.scene.lod.set_detail(lod_detail);
|
||||||
|
|
||||||
|
settings.graphics.lod_detail = lod_detail;
|
||||||
|
},
|
||||||
|
Graphics::AdjustSpriteRenderDistance(sprite_render_distance) => {
|
||||||
|
settings.graphics.sprite_render_distance = sprite_render_distance;
|
||||||
|
},
|
||||||
|
Graphics::AdjustFigureLoDRenderDistance(figure_lod_render_distance) => {
|
||||||
|
settings.graphics.figure_lod_render_distance = figure_lod_render_distance;
|
||||||
|
},
|
||||||
|
Graphics::ChangeMaxFPS(fps) => {
|
||||||
|
settings.graphics.max_fps = fps;
|
||||||
|
},
|
||||||
|
Graphics::ChangeFOV(new_fov) => {
|
||||||
|
settings.graphics.fov = new_fov;
|
||||||
|
session_state.scene.camera_mut().set_fov_deg(new_fov);
|
||||||
|
session_state
|
||||||
|
.scene
|
||||||
|
.camera_mut()
|
||||||
|
.compute_dependents(&*session_state.client.borrow().state().terrain());
|
||||||
|
},
|
||||||
|
Graphics::ChangeGamma(new_gamma) => {
|
||||||
|
settings.graphics.gamma = new_gamma;
|
||||||
|
},
|
||||||
|
Graphics::ChangeExposure(new_exposure) => {
|
||||||
|
settings.graphics.exposure = new_exposure;
|
||||||
|
},
|
||||||
|
Graphics::ChangeAmbiance(new_ambiance) => {
|
||||||
|
settings.graphics.ambiance = new_ambiance;
|
||||||
|
},
|
||||||
|
Graphics::ChangeRenderMode(new_render_mode) => {
|
||||||
|
// Do this first so if it crashes the setting isn't saved :)
|
||||||
|
global_state
|
||||||
|
.window
|
||||||
|
.renderer_mut()
|
||||||
|
.set_render_mode((&*new_render_mode).clone())
|
||||||
|
.unwrap();
|
||||||
|
settings.graphics.render_mode = *new_render_mode;
|
||||||
|
},
|
||||||
|
Graphics::ChangeFullscreenMode(new_fullscreen_settings) => {
|
||||||
|
global_state
|
||||||
|
.window
|
||||||
|
.set_fullscreen_mode(new_fullscreen_settings);
|
||||||
|
settings.graphics.fullscreen = new_fullscreen_settings;
|
||||||
|
},
|
||||||
|
Graphics::ToggleParticlesEnabled(particles_enabled) => {
|
||||||
|
settings.graphics.particles_enabled = particles_enabled;
|
||||||
|
},
|
||||||
|
Graphics::AdjustWindowSize(new_size) => {
|
||||||
|
global_state.window.set_size(new_size.into());
|
||||||
|
settings.graphics.window_size = new_size;
|
||||||
|
},
|
||||||
|
Graphics::ResetGraphicsSettings => {
|
||||||
|
settings.graphics = GraphicsSettings::default();
|
||||||
|
let graphics = &settings.graphics;
|
||||||
|
// View distance
|
||||||
|
session_state
|
||||||
|
.client
|
||||||
|
.borrow_mut()
|
||||||
|
.set_view_distance(graphics.view_distance);
|
||||||
|
// FOV
|
||||||
|
session_state.scene.camera_mut().set_fov_deg(graphics.fov);
|
||||||
|
session_state
|
||||||
|
.scene
|
||||||
|
.camera_mut()
|
||||||
|
.compute_dependents(&*session_state.client.borrow().state().terrain());
|
||||||
|
// LoD
|
||||||
|
session_state.scene.lod.set_detail(graphics.lod_detail);
|
||||||
|
// Render mode
|
||||||
|
global_state
|
||||||
|
.window
|
||||||
|
.renderer_mut()
|
||||||
|
.set_render_mode(graphics.render_mode.clone())
|
||||||
|
.unwrap();
|
||||||
|
// Fullscreen mode
|
||||||
|
global_state.window.set_fullscreen_mode(graphics.fullscreen);
|
||||||
|
// Window size
|
||||||
|
global_state.window.set_size(graphics.window_size.into());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
settings.save_to_file_warn();
|
||||||
|
},
|
||||||
|
SettingsChange::Interface(interface_change) => {
|
||||||
|
match interface_change {
|
||||||
|
Interface::Sct(sct) => {
|
||||||
|
settings.interface.sct = sct;
|
||||||
|
},
|
||||||
|
Interface::SctPlayerBatch(sct_player_batch) => {
|
||||||
|
settings.interface.sct_player_batch = sct_player_batch;
|
||||||
|
},
|
||||||
|
Interface::SctDamageBatch(sct_damage_batch) => {
|
||||||
|
settings.interface.sct_damage_batch = sct_damage_batch;
|
||||||
|
},
|
||||||
|
Interface::SpeechBubbleDarkMode(sbdm) => {
|
||||||
|
settings.interface.speech_bubble_dark_mode = sbdm;
|
||||||
|
},
|
||||||
|
Interface::SpeechBubbleIcon(sbi) => {
|
||||||
|
settings.interface.speech_bubble_icon = sbi;
|
||||||
|
},
|
||||||
|
Interface::ToggleHelp(_) => {
|
||||||
|
// implemented in hud
|
||||||
|
},
|
||||||
|
Interface::ToggleDebug(toggle_debug) => {
|
||||||
|
settings.interface.toggle_debug = toggle_debug;
|
||||||
|
},
|
||||||
|
Interface::ToggleTips(loading_tips) => {
|
||||||
|
settings.interface.loading_tips = loading_tips;
|
||||||
|
},
|
||||||
|
Interface::CrosshairTransp(crosshair_transp) => {
|
||||||
|
settings.interface.crosshair_transp = crosshair_transp;
|
||||||
|
},
|
||||||
|
Interface::ChatTransp(chat_transp) => {
|
||||||
|
settings.interface.chat_transp = chat_transp;
|
||||||
|
},
|
||||||
|
Interface::ChatCharName(chat_char_name) => {
|
||||||
|
settings.interface.chat_character_name = chat_char_name;
|
||||||
|
},
|
||||||
|
Interface::CrosshairType(crosshair_type) => {
|
||||||
|
settings.interface.crosshair_type = crosshair_type;
|
||||||
|
},
|
||||||
|
Interface::Intro(intro_show) => {
|
||||||
|
settings.interface.intro_show = intro_show;
|
||||||
|
},
|
||||||
|
Interface::ToggleXpBar(xp_bar) => {
|
||||||
|
settings.interface.xp_bar = xp_bar;
|
||||||
|
},
|
||||||
|
Interface::ToggleBarNumbers(bar_numbers) => {
|
||||||
|
settings.interface.bar_numbers = bar_numbers;
|
||||||
|
},
|
||||||
|
Interface::ToggleShortcutNumbers(shortcut_numbers) => {
|
||||||
|
settings.interface.shortcut_numbers = shortcut_numbers;
|
||||||
|
},
|
||||||
|
Interface::BuffPosition(buff_position) => {
|
||||||
|
settings.interface.buff_position = buff_position;
|
||||||
|
},
|
||||||
|
Interface::UiScale(scale_change) => {
|
||||||
|
settings.interface.ui_scale = session_state.hud.scale_change(scale_change);
|
||||||
|
},
|
||||||
|
Interface::MinimapShow(state) => {
|
||||||
|
settings.interface.minimap_show = state;
|
||||||
|
},
|
||||||
|
Interface::MinimapFaceNorth(state) => {
|
||||||
|
settings.interface.minimap_face_north = state;
|
||||||
|
},
|
||||||
|
Interface::MapZoom(map_zoom) => {
|
||||||
|
settings.interface.map_zoom = map_zoom;
|
||||||
|
},
|
||||||
|
Interface::MapDrag(map_drag) => {
|
||||||
|
settings.interface.map_drag = map_drag;
|
||||||
|
},
|
||||||
|
Interface::MapShowTopoMap(map_show_topo_map) => {
|
||||||
|
settings.interface.map_show_topo_map = map_show_topo_map;
|
||||||
|
},
|
||||||
|
Interface::MapShowDifficulty(map_show_difficulty) => {
|
||||||
|
settings.interface.map_show_difficulty = map_show_difficulty;
|
||||||
|
},
|
||||||
|
Interface::MapShowTowns(map_show_towns) => {
|
||||||
|
settings.interface.map_show_towns = map_show_towns;
|
||||||
|
},
|
||||||
|
Interface::MapShowDungeons(map_show_dungeons) => {
|
||||||
|
settings.interface.map_show_dungeons = map_show_dungeons;
|
||||||
|
},
|
||||||
|
Interface::MapShowCastles(map_show_castles) => {
|
||||||
|
settings.interface.map_show_castles = map_show_castles;
|
||||||
|
},
|
||||||
|
Interface::MapShowCaves(map_show_caves) => {
|
||||||
|
settings.interface.map_show_caves = map_show_caves;
|
||||||
|
},
|
||||||
|
Interface::MapShowTrees(map_show_trees) => {
|
||||||
|
settings.interface.map_show_trees = map_show_trees;
|
||||||
|
},
|
||||||
|
Interface::ResetInterfaceSettings => {
|
||||||
|
// Reset Interface Settings
|
||||||
|
let tmp = settings.interface.intro_show;
|
||||||
|
settings.interface = InterfaceSettings::default();
|
||||||
|
settings.interface.intro_show = tmp;
|
||||||
|
// Update Current Scaling Mode
|
||||||
|
session_state
|
||||||
|
.hud
|
||||||
|
.set_scaling_mode(settings.interface.ui_scale);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
settings.save_to_file_warn();
|
||||||
|
},
|
||||||
|
SettingsChange::Language(language_change) => match language_change {
|
||||||
|
Language::ChangeLanguage(new_language) => {
|
||||||
|
settings.language.selected_language = new_language.language_identifier;
|
||||||
|
global_state.i18n = Localization::load_expect(&i18n_asset_key(
|
||||||
|
&settings.language.selected_language,
|
||||||
|
));
|
||||||
|
global_state.i18n.read().log_missing_entries();
|
||||||
|
session_state.hud.update_fonts(&global_state.i18n.read());
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SettingsChange::Networking(networking_change) => match networking_change {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,839 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
hud::{BarNumbers, BuffPosition, CrosshairType, Intro, PressBehavior, ShortcutNumbers, XpBar},
|
|
||||||
i18n,
|
|
||||||
render::RenderMode,
|
|
||||||
ui::ScaleMode,
|
|
||||||
window::{FullScreenSettings, GameInput, KeyMouse},
|
|
||||||
};
|
|
||||||
use directories_next::UserDirs;
|
|
||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::{fmt, fs, path::PathBuf};
|
|
||||||
use tracing::warn;
|
|
||||||
use vek::*;
|
|
||||||
use winit::event::{MouseButton, VirtualKeyCode};
|
|
||||||
// ControlSetting-like struct used by Serde, to handle not serializing/building
|
|
||||||
// post-deserializing the inverse_keybindings hashmap
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct ControlSettingsSerde {
|
|
||||||
keybindings: HashMap<GameInput, KeyMouse>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ControlSettings> for ControlSettingsSerde {
|
|
||||||
fn from(control_settings: ControlSettings) -> Self {
|
|
||||||
let mut user_bindings: HashMap<GameInput, KeyMouse> = HashMap::new();
|
|
||||||
// Do a delta between default() ControlSettings and the argument, and let
|
|
||||||
// keybindings be only the custom keybindings chosen by the user.
|
|
||||||
for (k, v) in control_settings.keybindings {
|
|
||||||
if ControlSettings::default_binding(k) != v {
|
|
||||||
// Keybinding chosen by the user
|
|
||||||
user_bindings.insert(k, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ControlSettingsSerde {
|
|
||||||
keybindings: user_bindings,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `ControlSettings` contains keybindings.
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(from = "ControlSettingsSerde", into = "ControlSettingsSerde")]
|
|
||||||
pub struct ControlSettings {
|
|
||||||
pub keybindings: HashMap<GameInput, KeyMouse>,
|
|
||||||
pub inverse_keybindings: HashMap<KeyMouse, HashSet<GameInput>>, // used in event loop
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ControlSettingsSerde> for ControlSettings {
|
|
||||||
fn from(control_serde: ControlSettingsSerde) -> Self {
|
|
||||||
let user_keybindings = control_serde.keybindings;
|
|
||||||
let mut control_settings = ControlSettings::default();
|
|
||||||
for (k, v) in user_keybindings {
|
|
||||||
control_settings.modify_binding(k, v);
|
|
||||||
}
|
|
||||||
control_settings
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Since Macbook trackpads lack middle click, on OS X we default to LShift
|
|
||||||
/// instead It is an imperfect heuristic, but hopefully it will be a slightly
|
|
||||||
/// better default, and the two places we default to middle click currently
|
|
||||||
/// (roll and wall jump) are both situations where you cannot glide (the other
|
|
||||||
/// default mapping for LShift).
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Key(VirtualKeyCode::LShift);
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Mouse(MouseButton::Middle);
|
|
||||||
|
|
||||||
impl ControlSettings {
|
|
||||||
pub fn get_binding(&self, game_input: GameInput) -> Option<KeyMouse> {
|
|
||||||
self.keybindings.get(&game_input).copied()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_associated_game_inputs(&self, key_mouse: &KeyMouse) -> Option<&HashSet<GameInput>> {
|
|
||||||
self.inverse_keybindings.get(key_mouse)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
|
||||||
self.keybindings.insert(game_input, key_mouse);
|
|
||||||
self.inverse_keybindings
|
|
||||||
.entry(key_mouse)
|
|
||||||
.or_default()
|
|
||||||
.insert(game_input);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn modify_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
|
||||||
// For the KeyMouse->GameInput hashmap, we first need to remove the GameInput
|
|
||||||
// from the old binding
|
|
||||||
if let Some(old_binding) = self.get_binding(game_input) {
|
|
||||||
self.inverse_keybindings
|
|
||||||
.entry(old_binding)
|
|
||||||
.or_default()
|
|
||||||
.remove(&game_input);
|
|
||||||
}
|
|
||||||
// then we add the GameInput to the proper key
|
|
||||||
self.inverse_keybindings
|
|
||||||
.entry(key_mouse)
|
|
||||||
.or_default()
|
|
||||||
.insert(game_input);
|
|
||||||
// For the GameInput->KeyMouse hashmap, just overwrite the value
|
|
||||||
self.keybindings.insert(game_input, key_mouse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if this key is used for multiple GameInputs that aren't
|
|
||||||
/// expected to be safe to have bound to the same key at the same time
|
|
||||||
pub fn has_conflicting_bindings(&self, key_mouse: KeyMouse) -> bool {
|
|
||||||
if let Some(game_inputs) = self.inverse_keybindings.get(&key_mouse) {
|
|
||||||
for a in game_inputs.iter() {
|
|
||||||
for b in game_inputs.iter() {
|
|
||||||
if !GameInput::can_share_bindings(*a, *b) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_binding(game_input: GameInput) -> KeyMouse {
|
|
||||||
// If a new GameInput is added, be sure to update GameInput::iterator() too!
|
|
||||||
match game_input {
|
|
||||||
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
|
||||||
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
|
||||||
GameInput::ToggleCursor => KeyMouse::Key(VirtualKeyCode::Comma),
|
|
||||||
GameInput::Escape => KeyMouse::Key(VirtualKeyCode::Escape),
|
|
||||||
GameInput::Chat => KeyMouse::Key(VirtualKeyCode::Return),
|
|
||||||
GameInput::Command => KeyMouse::Key(VirtualKeyCode::Slash),
|
|
||||||
GameInput::MoveForward => KeyMouse::Key(VirtualKeyCode::W),
|
|
||||||
GameInput::MoveLeft => KeyMouse::Key(VirtualKeyCode::A),
|
|
||||||
GameInput::MoveBack => KeyMouse::Key(VirtualKeyCode::S),
|
|
||||||
GameInput::MoveRight => KeyMouse::Key(VirtualKeyCode::D),
|
|
||||||
GameInput::Jump => KeyMouse::Key(VirtualKeyCode::Space),
|
|
||||||
GameInput::Sit => KeyMouse::Key(VirtualKeyCode::K),
|
|
||||||
GameInput::Dance => KeyMouse::Key(VirtualKeyCode::J),
|
|
||||||
GameInput::Glide => KeyMouse::Key(VirtualKeyCode::LShift),
|
|
||||||
GameInput::Climb => KeyMouse::Key(VirtualKeyCode::Space),
|
|
||||||
GameInput::ClimbDown => KeyMouse::Key(VirtualKeyCode::LControl),
|
|
||||||
GameInput::SwimUp => KeyMouse::Key(VirtualKeyCode::Space),
|
|
||||||
GameInput::SwimDown => KeyMouse::Key(VirtualKeyCode::LShift),
|
|
||||||
GameInput::Fly => KeyMouse::Key(VirtualKeyCode::H),
|
|
||||||
GameInput::Sneak => KeyMouse::Key(VirtualKeyCode::LControl),
|
|
||||||
GameInput::ToggleLantern => KeyMouse::Key(VirtualKeyCode::G),
|
|
||||||
GameInput::Mount => KeyMouse::Key(VirtualKeyCode::F),
|
|
||||||
GameInput::Map => KeyMouse::Key(VirtualKeyCode::M),
|
|
||||||
GameInput::Bag => KeyMouse::Key(VirtualKeyCode::B),
|
|
||||||
GameInput::Trade => KeyMouse::Key(VirtualKeyCode::R),
|
|
||||||
GameInput::Social => KeyMouse::Key(VirtualKeyCode::O),
|
|
||||||
GameInput::Crafting => KeyMouse::Key(VirtualKeyCode::C),
|
|
||||||
GameInput::Spellbook => KeyMouse::Key(VirtualKeyCode::P),
|
|
||||||
GameInput::Settings => KeyMouse::Key(VirtualKeyCode::N),
|
|
||||||
GameInput::Help => KeyMouse::Key(VirtualKeyCode::F1),
|
|
||||||
GameInput::ToggleInterface => KeyMouse::Key(VirtualKeyCode::F2),
|
|
||||||
GameInput::ToggleDebug => KeyMouse::Key(VirtualKeyCode::F3),
|
|
||||||
GameInput::Fullscreen => KeyMouse::Key(VirtualKeyCode::F11),
|
|
||||||
GameInput::Screenshot => KeyMouse::Key(VirtualKeyCode::F4),
|
|
||||||
GameInput::ToggleIngameUi => KeyMouse::Key(VirtualKeyCode::F6),
|
|
||||||
GameInput::Roll => MIDDLE_CLICK_KEY,
|
|
||||||
GameInput::Respawn => KeyMouse::Key(VirtualKeyCode::Space),
|
|
||||||
GameInput::Interact => KeyMouse::Key(VirtualKeyCode::E),
|
|
||||||
GameInput::ToggleWield => KeyMouse::Key(VirtualKeyCode::T),
|
|
||||||
GameInput::FreeLook => KeyMouse::Key(VirtualKeyCode::L),
|
|
||||||
GameInput::AutoWalk => KeyMouse::Key(VirtualKeyCode::Period),
|
|
||||||
GameInput::CameraClamp => KeyMouse::Key(VirtualKeyCode::Apostrophe),
|
|
||||||
GameInput::CycleCamera => KeyMouse::Key(VirtualKeyCode::Key0),
|
|
||||||
GameInput::Slot1 => KeyMouse::Key(VirtualKeyCode::Key1),
|
|
||||||
GameInput::Slot2 => KeyMouse::Key(VirtualKeyCode::Key2),
|
|
||||||
GameInput::Slot3 => KeyMouse::Key(VirtualKeyCode::Key3),
|
|
||||||
GameInput::Slot4 => KeyMouse::Key(VirtualKeyCode::Key4),
|
|
||||||
GameInput::Slot5 => KeyMouse::Key(VirtualKeyCode::Key5),
|
|
||||||
GameInput::Slot6 => KeyMouse::Key(VirtualKeyCode::Key6),
|
|
||||||
GameInput::Slot7 => KeyMouse::Key(VirtualKeyCode::Key7),
|
|
||||||
GameInput::Slot8 => KeyMouse::Key(VirtualKeyCode::Key8),
|
|
||||||
GameInput::Slot9 => KeyMouse::Key(VirtualKeyCode::Key9),
|
|
||||||
GameInput::Slot10 => KeyMouse::Key(VirtualKeyCode::Q),
|
|
||||||
GameInput::SwapLoadout => KeyMouse::Key(VirtualKeyCode::Tab),
|
|
||||||
GameInput::Select => KeyMouse::Key(VirtualKeyCode::Y),
|
|
||||||
GameInput::AcceptGroupInvite => KeyMouse::Key(VirtualKeyCode::U),
|
|
||||||
GameInput::DeclineGroupInvite => KeyMouse::Key(VirtualKeyCode::I),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ControlSettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
let mut new_settings = Self {
|
|
||||||
keybindings: HashMap::new(),
|
|
||||||
inverse_keybindings: HashMap::new(),
|
|
||||||
};
|
|
||||||
// Sets the initial keybindings for those GameInputs.
|
|
||||||
for game_input in GameInput::iterator() {
|
|
||||||
new_settings.insert_binding(game_input, ControlSettings::default_binding(game_input));
|
|
||||||
}
|
|
||||||
new_settings
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct GamepadSettings {
|
|
||||||
pub game_buttons: con_settings::GameButtons,
|
|
||||||
pub menu_buttons: con_settings::MenuButtons,
|
|
||||||
pub game_axis: con_settings::GameAxis,
|
|
||||||
pub menu_axis: con_settings::MenuAxis,
|
|
||||||
pub game_analog_buttons: con_settings::GameAnalogButton,
|
|
||||||
pub menu_analog_buttons: con_settings::MenuAnalogButton,
|
|
||||||
pub pan_sensitivity: u32,
|
|
||||||
pub pan_invert_y: bool,
|
|
||||||
pub axis_deadzones: HashMap<crate::controller::Axis, f32>,
|
|
||||||
pub button_deadzones: HashMap<crate::controller::AnalogButton, f32>,
|
|
||||||
pub mouse_emulation_sensitivity: u32,
|
|
||||||
pub inverted_axes: Vec<crate::controller::Axis>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GamepadSettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
game_buttons: con_settings::GameButtons::default(),
|
|
||||||
menu_buttons: con_settings::MenuButtons::default(),
|
|
||||||
game_axis: con_settings::GameAxis::default(),
|
|
||||||
menu_axis: con_settings::MenuAxis::default(),
|
|
||||||
game_analog_buttons: con_settings::GameAnalogButton::default(),
|
|
||||||
menu_analog_buttons: con_settings::MenuAnalogButton::default(),
|
|
||||||
pan_sensitivity: 10,
|
|
||||||
pan_invert_y: false,
|
|
||||||
axis_deadzones: HashMap::new(),
|
|
||||||
button_deadzones: HashMap::new(),
|
|
||||||
mouse_emulation_sensitivity: 12,
|
|
||||||
inverted_axes: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod con_settings {
|
|
||||||
use crate::controller::*;
|
|
||||||
use gilrs::{Axis as GilAxis, Button as GilButton};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct GameButtons {
|
|
||||||
pub primary: Button,
|
|
||||||
pub secondary: Button,
|
|
||||||
pub toggle_cursor: Button,
|
|
||||||
pub escape: Button,
|
|
||||||
pub enter: Button,
|
|
||||||
pub command: Button,
|
|
||||||
pub move_forward: Button,
|
|
||||||
pub move_left: Button,
|
|
||||||
pub move_back: Button,
|
|
||||||
pub move_right: Button,
|
|
||||||
pub jump: Button,
|
|
||||||
pub sit: Button,
|
|
||||||
pub dance: Button,
|
|
||||||
pub glide: Button,
|
|
||||||
pub climb: Button,
|
|
||||||
pub climb_down: Button,
|
|
||||||
pub swimup: Button,
|
|
||||||
pub swimdown: Button,
|
|
||||||
pub sneak: Button,
|
|
||||||
pub toggle_lantern: Button,
|
|
||||||
pub mount: Button,
|
|
||||||
pub map: Button,
|
|
||||||
pub bag: Button,
|
|
||||||
pub quest_log: Button,
|
|
||||||
pub character_window: Button,
|
|
||||||
pub social: Button,
|
|
||||||
pub crafting: Button,
|
|
||||||
pub spellbook: Button,
|
|
||||||
pub settings: Button,
|
|
||||||
pub help: Button,
|
|
||||||
pub toggle_interface: Button,
|
|
||||||
pub toggle_debug: Button,
|
|
||||||
pub fullscreen: Button,
|
|
||||||
pub screenshot: Button,
|
|
||||||
pub toggle_ingame_ui: Button,
|
|
||||||
pub roll: Button,
|
|
||||||
pub respawn: Button,
|
|
||||||
pub interact: Button,
|
|
||||||
pub toggle_wield: Button,
|
|
||||||
pub swap_loadout: Button,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct MenuButtons {
|
|
||||||
pub up: Button,
|
|
||||||
pub down: Button,
|
|
||||||
pub left: Button,
|
|
||||||
pub right: Button,
|
|
||||||
pub scroll_up: Button,
|
|
||||||
pub scroll_down: Button,
|
|
||||||
pub scroll_left: Button,
|
|
||||||
pub scroll_right: Button,
|
|
||||||
pub home: Button,
|
|
||||||
pub end: Button,
|
|
||||||
pub apply: Button,
|
|
||||||
pub back: Button,
|
|
||||||
pub exit: Button,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct GameAxis {
|
|
||||||
pub movement_x: Axis,
|
|
||||||
pub movement_y: Axis,
|
|
||||||
pub camera_x: Axis,
|
|
||||||
pub camera_y: Axis,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct MenuAxis {
|
|
||||||
pub move_x: Axis,
|
|
||||||
pub move_y: Axis,
|
|
||||||
pub scroll_x: Axis,
|
|
||||||
pub scroll_y: Axis,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct GameAnalogButton {}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct MenuAnalogButton {}
|
|
||||||
|
|
||||||
impl Default for GameButtons {
|
|
||||||
fn default() -> Self {
|
|
||||||
// binding to unknown = getting skipped from processing
|
|
||||||
Self {
|
|
||||||
primary: Button::Simple(GilButton::RightTrigger2),
|
|
||||||
secondary: Button::Simple(GilButton::LeftTrigger2),
|
|
||||||
toggle_cursor: Button::Simple(GilButton::Unknown),
|
|
||||||
escape: Button::Simple(GilButton::Start),
|
|
||||||
enter: Button::Simple(GilButton::Unknown),
|
|
||||||
command: Button::Simple(GilButton::Unknown),
|
|
||||||
move_forward: Button::Simple(GilButton::Unknown),
|
|
||||||
move_left: Button::Simple(GilButton::Unknown),
|
|
||||||
move_back: Button::Simple(GilButton::Unknown),
|
|
||||||
move_right: Button::Simple(GilButton::Unknown),
|
|
||||||
jump: Button::Simple(GilButton::South),
|
|
||||||
sit: Button::Simple(GilButton::Unknown),
|
|
||||||
dance: Button::Simple(GilButton::Unknown),
|
|
||||||
glide: Button::Simple(GilButton::LeftTrigger),
|
|
||||||
climb: Button::Simple(GilButton::South),
|
|
||||||
climb_down: Button::Simple(GilButton::East),
|
|
||||||
swimup: Button::Simple(GilButton::South),
|
|
||||||
swimdown: Button::Simple(GilButton::East),
|
|
||||||
sneak: Button::Simple(GilButton::East),
|
|
||||||
toggle_lantern: Button::Simple(GilButton::DPadLeft),
|
|
||||||
mount: Button::Simple(GilButton::North),
|
|
||||||
map: Button::Simple(GilButton::Select),
|
|
||||||
bag: Button::Simple(GilButton::DPadRight),
|
|
||||||
quest_log: Button::Simple(GilButton::Unknown),
|
|
||||||
character_window: Button::Simple(GilButton::Unknown),
|
|
||||||
social: Button::Simple(GilButton::Unknown),
|
|
||||||
crafting: Button::Simple(GilButton::DPadDown),
|
|
||||||
spellbook: Button::Simple(GilButton::Unknown),
|
|
||||||
settings: Button::Simple(GilButton::Unknown),
|
|
||||||
help: Button::Simple(GilButton::Unknown),
|
|
||||||
toggle_interface: Button::Simple(GilButton::Unknown),
|
|
||||||
toggle_debug: Button::Simple(GilButton::Unknown),
|
|
||||||
fullscreen: Button::Simple(GilButton::Unknown),
|
|
||||||
screenshot: Button::Simple(GilButton::Unknown),
|
|
||||||
toggle_ingame_ui: Button::Simple(GilButton::Unknown),
|
|
||||||
roll: Button::Simple(GilButton::RightTrigger),
|
|
||||||
respawn: Button::Simple(GilButton::South),
|
|
||||||
interact: Button::Simple(GilButton::North),
|
|
||||||
toggle_wield: Button::Simple(GilButton::West),
|
|
||||||
swap_loadout: Button::Simple(GilButton::LeftThumb),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MenuButtons {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
up: Button::Simple(GilButton::Unknown),
|
|
||||||
down: Button::Simple(GilButton::Unknown),
|
|
||||||
left: Button::Simple(GilButton::Unknown),
|
|
||||||
right: Button::Simple(GilButton::Unknown),
|
|
||||||
scroll_up: Button::Simple(GilButton::Unknown),
|
|
||||||
scroll_down: Button::Simple(GilButton::Unknown),
|
|
||||||
scroll_left: Button::Simple(GilButton::Unknown),
|
|
||||||
scroll_right: Button::Simple(GilButton::Unknown),
|
|
||||||
home: Button::Simple(GilButton::DPadUp),
|
|
||||||
end: Button::Simple(GilButton::DPadDown),
|
|
||||||
apply: Button::Simple(GilButton::South),
|
|
||||||
back: Button::Simple(GilButton::East),
|
|
||||||
exit: Button::Simple(GilButton::Mode),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GameAxis {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
movement_x: Axis::Simple(GilAxis::LeftStickX),
|
|
||||||
movement_y: Axis::Simple(GilAxis::LeftStickY),
|
|
||||||
camera_x: Axis::Simple(GilAxis::RightStickX),
|
|
||||||
camera_y: Axis::Simple(GilAxis::RightStickY),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MenuAxis {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
move_x: Axis::Simple(GilAxis::RightStickX),
|
|
||||||
move_y: Axis::Simple(GilAxis::RightStickY),
|
|
||||||
scroll_x: Axis::Simple(GilAxis::LeftStickX),
|
|
||||||
scroll_y: Axis::Simple(GilAxis::LeftStickY),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GameAnalogButton {
|
|
||||||
fn default() -> Self { Self {} }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MenuAnalogButton {
|
|
||||||
fn default() -> Self { Self {} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `InterfaceSettings` contains UI, HUD and Map options.
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct InterfaceSettings {
|
|
||||||
pub toggle_debug: bool,
|
|
||||||
pub sct: bool,
|
|
||||||
pub sct_player_batch: bool,
|
|
||||||
pub sct_damage_batch: bool,
|
|
||||||
pub speech_bubble_dark_mode: bool,
|
|
||||||
pub speech_bubble_icon: bool,
|
|
||||||
pub crosshair_transp: f32,
|
|
||||||
pub chat_transp: f32,
|
|
||||||
pub chat_character_name: bool,
|
|
||||||
pub crosshair_type: CrosshairType,
|
|
||||||
pub intro_show: Intro,
|
|
||||||
pub xp_bar: XpBar,
|
|
||||||
pub shortcut_numbers: ShortcutNumbers,
|
|
||||||
pub buff_position: BuffPosition,
|
|
||||||
pub bar_numbers: BarNumbers,
|
|
||||||
pub ui_scale: ScaleMode,
|
|
||||||
pub map_zoom: f64,
|
|
||||||
pub map_drag: Vec2<f64>,
|
|
||||||
pub map_show_topo_map: bool,
|
|
||||||
pub map_show_difficulty: bool,
|
|
||||||
pub map_show_towns: bool,
|
|
||||||
pub map_show_dungeons: bool,
|
|
||||||
pub map_show_castles: bool,
|
|
||||||
pub loading_tips: bool,
|
|
||||||
pub map_show_caves: bool,
|
|
||||||
pub map_show_trees: bool,
|
|
||||||
pub minimap_show: bool,
|
|
||||||
pub minimap_face_north: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for InterfaceSettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
toggle_debug: false,
|
|
||||||
sct: true,
|
|
||||||
sct_player_batch: false,
|
|
||||||
sct_damage_batch: false,
|
|
||||||
speech_bubble_dark_mode: false,
|
|
||||||
speech_bubble_icon: true,
|
|
||||||
crosshair_transp: 0.6,
|
|
||||||
chat_transp: 0.4,
|
|
||||||
chat_character_name: true,
|
|
||||||
crosshair_type: CrosshairType::Round,
|
|
||||||
intro_show: Intro::Show,
|
|
||||||
xp_bar: XpBar::Always,
|
|
||||||
shortcut_numbers: ShortcutNumbers::On,
|
|
||||||
buff_position: BuffPosition::Bar,
|
|
||||||
bar_numbers: BarNumbers::Values,
|
|
||||||
ui_scale: ScaleMode::RelativeToWindow([1920.0, 1080.0].into()),
|
|
||||||
map_zoom: 10.0,
|
|
||||||
map_drag: Vec2 { x: 0.0, y: 0.0 },
|
|
||||||
map_show_topo_map: false,
|
|
||||||
map_show_difficulty: true,
|
|
||||||
map_show_towns: true,
|
|
||||||
map_show_dungeons: true,
|
|
||||||
map_show_castles: true,
|
|
||||||
loading_tips: true,
|
|
||||||
map_show_caves: true,
|
|
||||||
map_show_trees: true,
|
|
||||||
minimap_show: true,
|
|
||||||
minimap_face_north: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `GameplaySettings` contains sensitivity and gameplay options.
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct GameplaySettings {
|
|
||||||
pub pan_sensitivity: u32,
|
|
||||||
pub zoom_sensitivity: u32,
|
|
||||||
pub camera_clamp_angle: u32,
|
|
||||||
pub zoom_inversion: bool,
|
|
||||||
pub mouse_y_inversion: bool,
|
|
||||||
pub smooth_pan_enable: bool,
|
|
||||||
pub free_look_behavior: PressBehavior,
|
|
||||||
pub auto_walk_behavior: PressBehavior,
|
|
||||||
pub camera_clamp_behavior: PressBehavior,
|
|
||||||
pub stop_auto_walk_on_input: bool,
|
|
||||||
pub auto_camera: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GameplaySettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
pan_sensitivity: 100,
|
|
||||||
zoom_sensitivity: 100,
|
|
||||||
camera_clamp_angle: 45,
|
|
||||||
zoom_inversion: false,
|
|
||||||
mouse_y_inversion: false,
|
|
||||||
smooth_pan_enable: false,
|
|
||||||
free_look_behavior: PressBehavior::Toggle,
|
|
||||||
auto_walk_behavior: PressBehavior::Toggle,
|
|
||||||
camera_clamp_behavior: PressBehavior::Toggle,
|
|
||||||
stop_auto_walk_on_input: true,
|
|
||||||
auto_camera: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `NetworkingSettings` stores server and networking settings.
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct NetworkingSettings {
|
|
||||||
pub username: String,
|
|
||||||
pub servers: Vec<String>,
|
|
||||||
pub default_server: String,
|
|
||||||
pub trusted_auth_servers: HashSet<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for NetworkingSettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
username: "".to_string(),
|
|
||||||
servers: vec!["server.veloren.net".to_string()],
|
|
||||||
default_server: "server.veloren.net".to_string(),
|
|
||||||
trusted_auth_servers: ["https://auth.veloren.net"]
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.to_string())
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `Log` stores whether we should create a log file
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct Log {
|
|
||||||
// Whether to create a log file or not.
|
|
||||||
// Default is to create one.
|
|
||||||
pub log_to_file: bool,
|
|
||||||
// The path on which the logs will be stored
|
|
||||||
pub logs_path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Log {
|
|
||||||
fn default() -> Self {
|
|
||||||
// Chooses a path to store the logs by the following order:
|
|
||||||
// - The VOXYGEN_LOGS environment variable
|
|
||||||
// - The ProjectsDirs data local directory
|
|
||||||
// This function is only called if there isn't already an entry in the settings
|
|
||||||
// file. However, the VOXYGEN_LOGS environment variable always overrides
|
|
||||||
// the log file path if set.
|
|
||||||
let logs_path = std::env::var_os("VOXYGEN_LOGS")
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
let mut path = voxygen_data_dir();
|
|
||||||
path.push("logs");
|
|
||||||
path
|
|
||||||
});
|
|
||||||
|
|
||||||
Self {
|
|
||||||
log_to_file: true,
|
|
||||||
logs_path,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq)]
|
|
||||||
pub enum Fps {
|
|
||||||
Max(u32),
|
|
||||||
Unlimited,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_fps(max_fps: Fps) -> u32 {
|
|
||||||
match max_fps {
|
|
||||||
Fps::Max(x) => x,
|
|
||||||
Fps::Unlimited => u32::MAX,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Fps {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Fps::Max(x) => write!(f, "{}", x),
|
|
||||||
Fps::Unlimited => write!(f, "Unlimited"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `GraphicsSettings` contains settings related to framerate and in-game
|
|
||||||
/// visuals.
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct GraphicsSettings {
|
|
||||||
pub view_distance: u32,
|
|
||||||
pub sprite_render_distance: u32,
|
|
||||||
pub particles_enabled: bool,
|
|
||||||
pub figure_lod_render_distance: u32,
|
|
||||||
pub max_fps: Fps,
|
|
||||||
pub fov: u16,
|
|
||||||
pub gamma: f32,
|
|
||||||
pub exposure: f32,
|
|
||||||
pub ambiance: f32,
|
|
||||||
pub render_mode: RenderMode,
|
|
||||||
pub window_size: [u16; 2],
|
|
||||||
pub fullscreen: FullScreenSettings,
|
|
||||||
pub lod_detail: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GraphicsSettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
view_distance: 10,
|
|
||||||
sprite_render_distance: 100,
|
|
||||||
particles_enabled: true,
|
|
||||||
figure_lod_render_distance: 300,
|
|
||||||
max_fps: Fps::Max(60),
|
|
||||||
fov: 70,
|
|
||||||
gamma: 1.0,
|
|
||||||
exposure: 1.0,
|
|
||||||
ambiance: 10.0,
|
|
||||||
render_mode: RenderMode::default(),
|
|
||||||
window_size: [1280, 720],
|
|
||||||
fullscreen: FullScreenSettings::default(),
|
|
||||||
lod_detail: 250,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum AudioOutput {
|
|
||||||
/// Veloren's audio system wont work on some systems,
|
|
||||||
/// so you can use this to disable it, and allow the
|
|
||||||
/// game to function
|
|
||||||
// If this option is disabled, functions in the rodio
|
|
||||||
// library MUST NOT be called.
|
|
||||||
Off,
|
|
||||||
#[serde(other)]
|
|
||||||
Automatic,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AudioOutput {
|
|
||||||
pub fn is_enabled(&self) -> bool { !matches!(self, Self::Off) }
|
|
||||||
}
|
|
||||||
/// `AudioSettings` controls the volume of different audio subsystems and which
|
|
||||||
/// device is used.
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct AudioSettings {
|
|
||||||
pub master_volume: f32,
|
|
||||||
pub music_volume: f32,
|
|
||||||
pub sfx_volume: f32,
|
|
||||||
pub max_sfx_channels: usize,
|
|
||||||
|
|
||||||
/// Audio Device that Voxygen will use to play audio.
|
|
||||||
pub output: AudioOutput,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for AudioSettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
master_volume: 1.0,
|
|
||||||
music_volume: 0.4,
|
|
||||||
sfx_volume: 0.6,
|
|
||||||
max_sfx_channels: 30,
|
|
||||||
output: AudioOutput::Automatic,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct LanguageSettings {
|
|
||||||
pub selected_language: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for LanguageSettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
selected_language: i18n::REFERENCE_LANG.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `Settings` contains everything that can be configured in the settings.ron
|
|
||||||
/// file.
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct Settings {
|
|
||||||
pub controls: ControlSettings,
|
|
||||||
pub interface: InterfaceSettings,
|
|
||||||
pub gameplay: GameplaySettings,
|
|
||||||
pub networking: NetworkingSettings,
|
|
||||||
pub log: Log,
|
|
||||||
pub graphics: GraphicsSettings,
|
|
||||||
pub audio: AudioSettings,
|
|
||||||
pub show_disclaimer: bool,
|
|
||||||
pub send_logon_commands: bool,
|
|
||||||
// TODO: Remove at a later date, for dev testing
|
|
||||||
pub logon_commands: Vec<String>,
|
|
||||||
pub language: LanguageSettings,
|
|
||||||
pub screenshots_path: PathBuf,
|
|
||||||
pub controller: GamepadSettings,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Settings {
|
|
||||||
fn default() -> Self {
|
|
||||||
let user_dirs = UserDirs::new().expect("System's $HOME directory path not found!");
|
|
||||||
|
|
||||||
// Chooses a path to store the screenshots by the following order:
|
|
||||||
// - The VOXYGEN_SCREENSHOT environment variable
|
|
||||||
// - The user's picture directory
|
|
||||||
// - The executable's directory
|
|
||||||
// This only selects if there isn't already an entry in the settings file
|
|
||||||
let screenshots_path = std::env::var_os("VOXYGEN_SCREENSHOT")
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.or_else(|| user_dirs.picture_dir().map(|dir| dir.join("veloren")))
|
|
||||||
.or_else(|| {
|
|
||||||
std::env::current_exe()
|
|
||||||
.ok()
|
|
||||||
.and_then(|dir| dir.parent().map(PathBuf::from))
|
|
||||||
})
|
|
||||||
.expect("Couldn't choose a place to store the screenshots");
|
|
||||||
|
|
||||||
Settings {
|
|
||||||
controls: ControlSettings::default(),
|
|
||||||
interface: InterfaceSettings::default(),
|
|
||||||
gameplay: GameplaySettings::default(),
|
|
||||||
networking: NetworkingSettings::default(),
|
|
||||||
log: Log::default(),
|
|
||||||
graphics: GraphicsSettings::default(),
|
|
||||||
audio: AudioSettings::default(),
|
|
||||||
show_disclaimer: true,
|
|
||||||
send_logon_commands: false,
|
|
||||||
logon_commands: Vec::new(),
|
|
||||||
language: LanguageSettings::default(),
|
|
||||||
screenshots_path,
|
|
||||||
controller: GamepadSettings::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Settings {
|
|
||||||
pub fn load() -> Self {
|
|
||||||
let path = Self::get_settings_path();
|
|
||||||
|
|
||||||
if let Ok(file) = fs::File::open(&path) {
|
|
||||||
match ron::de::from_reader::<_, Self>(file) {
|
|
||||||
Ok(mut s) => {
|
|
||||||
// Override the logs path if it is explicitly set using the VOXYGEN_LOGS
|
|
||||||
// environment variable. This is needed to support package managers that enforce
|
|
||||||
// strict application confinement (e.g. snap). In fact, the veloren snap package
|
|
||||||
// relies on this environment variable to be respected in
|
|
||||||
// order to communicate a path where the snap package is
|
|
||||||
// allowed to write to.
|
|
||||||
if let Some(logs_path_override) =
|
|
||||||
std::env::var_os("VOXYGEN_LOGS").map(PathBuf::from)
|
|
||||||
{
|
|
||||||
s.log.logs_path = logs_path_override;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
warn!(?e, "Failed to parse setting file! Fallback to default.");
|
|
||||||
// Rename the corrupted settings file
|
|
||||||
let mut new_path = path.to_owned();
|
|
||||||
new_path.pop();
|
|
||||||
new_path.push("settings.invalid.ron");
|
|
||||||
if let Err(e) = std::fs::rename(&path, &new_path) {
|
|
||||||
warn!(?e, ?path, ?new_path, "Failed to rename settings file.");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This is reached if either:
|
|
||||||
// - The file can't be opened (presumably it doesn't exist)
|
|
||||||
// - Or there was an error parsing the file
|
|
||||||
let default_settings = Self::default();
|
|
||||||
default_settings.save_to_file_warn();
|
|
||||||
default_settings
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save_to_file_warn(&self) {
|
|
||||||
if let Err(e) = self.save_to_file() {
|
|
||||||
warn!(?e, "Failed to save settings");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save_to_file(&self) -> std::io::Result<()> {
|
|
||||||
let path = Self::get_settings_path();
|
|
||||||
if let Some(dir) = path.parent() {
|
|
||||||
fs::create_dir_all(dir)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ron = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
|
|
||||||
fs::write(path, ron.as_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_settings_path() -> PathBuf {
|
|
||||||
if let Some(path) = std::env::var_os("VOXYGEN_CONFIG") {
|
|
||||||
let settings = PathBuf::from(&path).join("settings.ron");
|
|
||||||
if settings.exists() || settings.parent().map(|x| x.exists()).unwrap_or(false) {
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut path = voxygen_data_dir();
|
|
||||||
path.push("settings.ron");
|
|
||||||
path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn voxygen_data_dir() -> PathBuf {
|
|
||||||
// Note: since voxygen is technically a lib we made need to lift this up to
|
|
||||||
// run.rs
|
|
||||||
let mut path = common_base::userdata_dir_workspace!();
|
|
||||||
path.push("voxygen");
|
|
||||||
path
|
|
||||||
}
|
|
42
voxygen/src/settings/audio.rs
Normal file
42
voxygen/src/settings/audio.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum AudioOutput {
|
||||||
|
/// Veloren's audio system wont work on some systems,
|
||||||
|
/// so you can use this to disable it, and allow the
|
||||||
|
/// game to function
|
||||||
|
// If this option is disabled, functions in the rodio
|
||||||
|
// library MUST NOT be called.
|
||||||
|
Off,
|
||||||
|
#[serde(other)]
|
||||||
|
Automatic,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AudioOutput {
|
||||||
|
pub fn is_enabled(&self) -> bool { !matches!(self, Self::Off) }
|
||||||
|
}
|
||||||
|
/// `AudioSettings` controls the volume of different audio subsystems and which
|
||||||
|
/// device is used.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct AudioSettings {
|
||||||
|
pub master_volume: f32,
|
||||||
|
pub music_volume: f32,
|
||||||
|
pub sfx_volume: f32,
|
||||||
|
pub max_sfx_channels: usize,
|
||||||
|
|
||||||
|
/// Audio Device that Voxygen will use to play audio.
|
||||||
|
pub output: AudioOutput,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AudioSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
master_volume: 1.0,
|
||||||
|
music_volume: 0.4,
|
||||||
|
sfx_volume: 0.6,
|
||||||
|
max_sfx_channels: 30,
|
||||||
|
output: AudioOutput::Automatic,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
185
voxygen/src/settings/control.rs
Normal file
185
voxygen/src/settings/control.rs
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
use crate::window::{GameInput, KeyMouse};
|
||||||
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use winit::event::{MouseButton, VirtualKeyCode};
|
||||||
|
|
||||||
|
// ControlSetting-like struct used by Serde, to handle not serializing/building
|
||||||
|
// post-deserializing the inverse_keybindings hashmap
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct ControlSettingsSerde {
|
||||||
|
keybindings: HashMap<GameInput, KeyMouse>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ControlSettings> for ControlSettingsSerde {
|
||||||
|
fn from(control_settings: ControlSettings) -> Self {
|
||||||
|
let mut user_bindings: HashMap<GameInput, KeyMouse> = HashMap::new();
|
||||||
|
// Do a delta between default() ControlSettings and the argument, and let
|
||||||
|
// keybindings be only the custom keybindings chosen by the user.
|
||||||
|
for (k, v) in control_settings.keybindings {
|
||||||
|
if ControlSettings::default_binding(k) != v {
|
||||||
|
// Keybinding chosen by the user
|
||||||
|
user_bindings.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlSettingsSerde {
|
||||||
|
keybindings: user_bindings,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `ControlSettings` contains keybindings.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(from = "ControlSettingsSerde", into = "ControlSettingsSerde")]
|
||||||
|
pub struct ControlSettings {
|
||||||
|
pub keybindings: HashMap<GameInput, KeyMouse>,
|
||||||
|
pub inverse_keybindings: HashMap<KeyMouse, HashSet<GameInput>>, // used in event loop
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ControlSettingsSerde> for ControlSettings {
|
||||||
|
fn from(control_serde: ControlSettingsSerde) -> Self {
|
||||||
|
let user_keybindings = control_serde.keybindings;
|
||||||
|
let mut control_settings = ControlSettings::default();
|
||||||
|
for (k, v) in user_keybindings {
|
||||||
|
control_settings.modify_binding(k, v);
|
||||||
|
}
|
||||||
|
control_settings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Since Macbook trackpads lack middle click, on OS X we default to LShift
|
||||||
|
/// instead It is an imperfect heuristic, but hopefully it will be a slightly
|
||||||
|
/// better default, and the two places we default to middle click currently
|
||||||
|
/// (roll and wall jump) are both situations where you cannot glide (the other
|
||||||
|
/// default mapping for LShift).
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Key(VirtualKeyCode::LShift);
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Mouse(MouseButton::Middle);
|
||||||
|
|
||||||
|
impl ControlSettings {
|
||||||
|
pub fn get_binding(&self, game_input: GameInput) -> Option<KeyMouse> {
|
||||||
|
self.keybindings.get(&game_input).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_associated_game_inputs(&self, key_mouse: &KeyMouse) -> Option<&HashSet<GameInput>> {
|
||||||
|
self.inverse_keybindings.get(key_mouse)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
||||||
|
self.keybindings.insert(game_input, key_mouse);
|
||||||
|
self.inverse_keybindings
|
||||||
|
.entry(key_mouse)
|
||||||
|
.or_default()
|
||||||
|
.insert(game_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn modify_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
||||||
|
// For the KeyMouse->GameInput hashmap, we first need to remove the GameInput
|
||||||
|
// from the old binding
|
||||||
|
if let Some(old_binding) = self.get_binding(game_input) {
|
||||||
|
self.inverse_keybindings
|
||||||
|
.entry(old_binding)
|
||||||
|
.or_default()
|
||||||
|
.remove(&game_input);
|
||||||
|
}
|
||||||
|
// then we add the GameInput to the proper key
|
||||||
|
self.inverse_keybindings
|
||||||
|
.entry(key_mouse)
|
||||||
|
.or_default()
|
||||||
|
.insert(game_input);
|
||||||
|
// For the GameInput->KeyMouse hashmap, just overwrite the value
|
||||||
|
self.keybindings.insert(game_input, key_mouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true if this key is used for multiple GameInputs that aren't
|
||||||
|
/// expected to be safe to have bound to the same key at the same time
|
||||||
|
pub fn has_conflicting_bindings(&self, key_mouse: KeyMouse) -> bool {
|
||||||
|
if let Some(game_inputs) = self.inverse_keybindings.get(&key_mouse) {
|
||||||
|
for a in game_inputs.iter() {
|
||||||
|
for b in game_inputs.iter() {
|
||||||
|
if !GameInput::can_share_bindings(*a, *b) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_binding(game_input: GameInput) -> KeyMouse {
|
||||||
|
// If a new GameInput is added, be sure to update GameInput::iterator() too!
|
||||||
|
match game_input {
|
||||||
|
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
||||||
|
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
||||||
|
GameInput::ToggleCursor => KeyMouse::Key(VirtualKeyCode::Comma),
|
||||||
|
GameInput::Escape => KeyMouse::Key(VirtualKeyCode::Escape),
|
||||||
|
GameInput::Chat => KeyMouse::Key(VirtualKeyCode::Return),
|
||||||
|
GameInput::Command => KeyMouse::Key(VirtualKeyCode::Slash),
|
||||||
|
GameInput::MoveForward => KeyMouse::Key(VirtualKeyCode::W),
|
||||||
|
GameInput::MoveLeft => KeyMouse::Key(VirtualKeyCode::A),
|
||||||
|
GameInput::MoveBack => KeyMouse::Key(VirtualKeyCode::S),
|
||||||
|
GameInput::MoveRight => KeyMouse::Key(VirtualKeyCode::D),
|
||||||
|
GameInput::Jump => KeyMouse::Key(VirtualKeyCode::Space),
|
||||||
|
GameInput::Sit => KeyMouse::Key(VirtualKeyCode::K),
|
||||||
|
GameInput::Dance => KeyMouse::Key(VirtualKeyCode::J),
|
||||||
|
GameInput::Glide => KeyMouse::Key(VirtualKeyCode::LShift),
|
||||||
|
GameInput::Climb => KeyMouse::Key(VirtualKeyCode::Space),
|
||||||
|
GameInput::ClimbDown => KeyMouse::Key(VirtualKeyCode::LControl),
|
||||||
|
GameInput::SwimUp => KeyMouse::Key(VirtualKeyCode::Space),
|
||||||
|
GameInput::SwimDown => KeyMouse::Key(VirtualKeyCode::LShift),
|
||||||
|
GameInput::Fly => KeyMouse::Key(VirtualKeyCode::H),
|
||||||
|
GameInput::Sneak => KeyMouse::Key(VirtualKeyCode::LControl),
|
||||||
|
GameInput::ToggleLantern => KeyMouse::Key(VirtualKeyCode::G),
|
||||||
|
GameInput::Mount => KeyMouse::Key(VirtualKeyCode::F),
|
||||||
|
GameInput::Map => KeyMouse::Key(VirtualKeyCode::M),
|
||||||
|
GameInput::Bag => KeyMouse::Key(VirtualKeyCode::B),
|
||||||
|
GameInput::Trade => KeyMouse::Key(VirtualKeyCode::R),
|
||||||
|
GameInput::Social => KeyMouse::Key(VirtualKeyCode::O),
|
||||||
|
GameInput::Crafting => KeyMouse::Key(VirtualKeyCode::C),
|
||||||
|
GameInput::Spellbook => KeyMouse::Key(VirtualKeyCode::P),
|
||||||
|
GameInput::Settings => KeyMouse::Key(VirtualKeyCode::N),
|
||||||
|
GameInput::Help => KeyMouse::Key(VirtualKeyCode::F1),
|
||||||
|
GameInput::ToggleInterface => KeyMouse::Key(VirtualKeyCode::F2),
|
||||||
|
GameInput::ToggleDebug => KeyMouse::Key(VirtualKeyCode::F3),
|
||||||
|
GameInput::Fullscreen => KeyMouse::Key(VirtualKeyCode::F11),
|
||||||
|
GameInput::Screenshot => KeyMouse::Key(VirtualKeyCode::F4),
|
||||||
|
GameInput::ToggleIngameUi => KeyMouse::Key(VirtualKeyCode::F6),
|
||||||
|
GameInput::Roll => MIDDLE_CLICK_KEY,
|
||||||
|
GameInput::Respawn => KeyMouse::Key(VirtualKeyCode::Space),
|
||||||
|
GameInput::Interact => KeyMouse::Key(VirtualKeyCode::E),
|
||||||
|
GameInput::ToggleWield => KeyMouse::Key(VirtualKeyCode::T),
|
||||||
|
GameInput::FreeLook => KeyMouse::Key(VirtualKeyCode::L),
|
||||||
|
GameInput::AutoWalk => KeyMouse::Key(VirtualKeyCode::Period),
|
||||||
|
GameInput::CameraClamp => KeyMouse::Key(VirtualKeyCode::Apostrophe),
|
||||||
|
GameInput::CycleCamera => KeyMouse::Key(VirtualKeyCode::Key0),
|
||||||
|
GameInput::Slot1 => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||||
|
GameInput::Slot2 => KeyMouse::Key(VirtualKeyCode::Key2),
|
||||||
|
GameInput::Slot3 => KeyMouse::Key(VirtualKeyCode::Key3),
|
||||||
|
GameInput::Slot4 => KeyMouse::Key(VirtualKeyCode::Key4),
|
||||||
|
GameInput::Slot5 => KeyMouse::Key(VirtualKeyCode::Key5),
|
||||||
|
GameInput::Slot6 => KeyMouse::Key(VirtualKeyCode::Key6),
|
||||||
|
GameInput::Slot7 => KeyMouse::Key(VirtualKeyCode::Key7),
|
||||||
|
GameInput::Slot8 => KeyMouse::Key(VirtualKeyCode::Key8),
|
||||||
|
GameInput::Slot9 => KeyMouse::Key(VirtualKeyCode::Key9),
|
||||||
|
GameInput::Slot10 => KeyMouse::Key(VirtualKeyCode::Q),
|
||||||
|
GameInput::SwapLoadout => KeyMouse::Key(VirtualKeyCode::Tab),
|
||||||
|
GameInput::Select => KeyMouse::Key(VirtualKeyCode::Y),
|
||||||
|
GameInput::AcceptGroupInvite => KeyMouse::Key(VirtualKeyCode::U),
|
||||||
|
GameInput::DeclineGroupInvite => KeyMouse::Key(VirtualKeyCode::I),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ControlSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut new_settings = Self {
|
||||||
|
keybindings: HashMap::new(),
|
||||||
|
inverse_keybindings: HashMap::new(),
|
||||||
|
};
|
||||||
|
// Sets the initial keybindings for those GameInputs.
|
||||||
|
for game_input in GameInput::iterator() {
|
||||||
|
new_settings.insert_binding(game_input, ControlSettings::default_binding(game_input));
|
||||||
|
}
|
||||||
|
new_settings
|
||||||
|
}
|
||||||
|
}
|
231
voxygen/src/settings/gamepad.rs
Normal file
231
voxygen/src/settings/gamepad.rs
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
use hashbrown::HashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct GamepadSettings {
|
||||||
|
pub game_buttons: con_settings::GameButtons,
|
||||||
|
pub menu_buttons: con_settings::MenuButtons,
|
||||||
|
pub game_axis: con_settings::GameAxis,
|
||||||
|
pub menu_axis: con_settings::MenuAxis,
|
||||||
|
pub game_analog_buttons: con_settings::GameAnalogButton,
|
||||||
|
pub menu_analog_buttons: con_settings::MenuAnalogButton,
|
||||||
|
pub pan_sensitivity: u32,
|
||||||
|
pub pan_invert_y: bool,
|
||||||
|
pub axis_deadzones: HashMap<crate::controller::Axis, f32>,
|
||||||
|
pub button_deadzones: HashMap<crate::controller::AnalogButton, f32>,
|
||||||
|
pub mouse_emulation_sensitivity: u32,
|
||||||
|
pub inverted_axes: Vec<crate::controller::Axis>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GamepadSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
game_buttons: con_settings::GameButtons::default(),
|
||||||
|
menu_buttons: con_settings::MenuButtons::default(),
|
||||||
|
game_axis: con_settings::GameAxis::default(),
|
||||||
|
menu_axis: con_settings::MenuAxis::default(),
|
||||||
|
game_analog_buttons: con_settings::GameAnalogButton::default(),
|
||||||
|
menu_analog_buttons: con_settings::MenuAnalogButton::default(),
|
||||||
|
pan_sensitivity: 10,
|
||||||
|
pan_invert_y: false,
|
||||||
|
axis_deadzones: HashMap::new(),
|
||||||
|
button_deadzones: HashMap::new(),
|
||||||
|
mouse_emulation_sensitivity: 12,
|
||||||
|
inverted_axes: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod con_settings {
|
||||||
|
use crate::controller::*;
|
||||||
|
use gilrs::{Axis as GilAxis, Button as GilButton};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct GameButtons {
|
||||||
|
pub primary: Button,
|
||||||
|
pub secondary: Button,
|
||||||
|
pub toggle_cursor: Button,
|
||||||
|
pub escape: Button,
|
||||||
|
pub enter: Button,
|
||||||
|
pub command: Button,
|
||||||
|
pub move_forward: Button,
|
||||||
|
pub move_left: Button,
|
||||||
|
pub move_back: Button,
|
||||||
|
pub move_right: Button,
|
||||||
|
pub jump: Button,
|
||||||
|
pub sit: Button,
|
||||||
|
pub dance: Button,
|
||||||
|
pub glide: Button,
|
||||||
|
pub climb: Button,
|
||||||
|
pub climb_down: Button,
|
||||||
|
pub swimup: Button,
|
||||||
|
pub swimdown: Button,
|
||||||
|
pub sneak: Button,
|
||||||
|
pub toggle_lantern: Button,
|
||||||
|
pub mount: Button,
|
||||||
|
pub map: Button,
|
||||||
|
pub bag: Button,
|
||||||
|
pub quest_log: Button,
|
||||||
|
pub character_window: Button,
|
||||||
|
pub social: Button,
|
||||||
|
pub crafting: Button,
|
||||||
|
pub spellbook: Button,
|
||||||
|
pub settings: Button,
|
||||||
|
pub help: Button,
|
||||||
|
pub toggle_interface: Button,
|
||||||
|
pub toggle_debug: Button,
|
||||||
|
pub fullscreen: Button,
|
||||||
|
pub screenshot: Button,
|
||||||
|
pub toggle_ingame_ui: Button,
|
||||||
|
pub roll: Button,
|
||||||
|
pub respawn: Button,
|
||||||
|
pub interact: Button,
|
||||||
|
pub toggle_wield: Button,
|
||||||
|
pub swap_loadout: Button,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct MenuButtons {
|
||||||
|
pub up: Button,
|
||||||
|
pub down: Button,
|
||||||
|
pub left: Button,
|
||||||
|
pub right: Button,
|
||||||
|
pub scroll_up: Button,
|
||||||
|
pub scroll_down: Button,
|
||||||
|
pub scroll_left: Button,
|
||||||
|
pub scroll_right: Button,
|
||||||
|
pub home: Button,
|
||||||
|
pub end: Button,
|
||||||
|
pub apply: Button,
|
||||||
|
pub back: Button,
|
||||||
|
pub exit: Button,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct GameAxis {
|
||||||
|
pub movement_x: Axis,
|
||||||
|
pub movement_y: Axis,
|
||||||
|
pub camera_x: Axis,
|
||||||
|
pub camera_y: Axis,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct MenuAxis {
|
||||||
|
pub move_x: Axis,
|
||||||
|
pub move_y: Axis,
|
||||||
|
pub scroll_x: Axis,
|
||||||
|
pub scroll_y: Axis,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct GameAnalogButton {}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct MenuAnalogButton {}
|
||||||
|
|
||||||
|
impl Default for GameButtons {
|
||||||
|
fn default() -> Self {
|
||||||
|
// binding to unknown = getting skipped from processing
|
||||||
|
Self {
|
||||||
|
primary: Button::Simple(GilButton::RightTrigger2),
|
||||||
|
secondary: Button::Simple(GilButton::LeftTrigger2),
|
||||||
|
toggle_cursor: Button::Simple(GilButton::Unknown),
|
||||||
|
escape: Button::Simple(GilButton::Start),
|
||||||
|
enter: Button::Simple(GilButton::Unknown),
|
||||||
|
command: Button::Simple(GilButton::Unknown),
|
||||||
|
move_forward: Button::Simple(GilButton::Unknown),
|
||||||
|
move_left: Button::Simple(GilButton::Unknown),
|
||||||
|
move_back: Button::Simple(GilButton::Unknown),
|
||||||
|
move_right: Button::Simple(GilButton::Unknown),
|
||||||
|
jump: Button::Simple(GilButton::South),
|
||||||
|
sit: Button::Simple(GilButton::Unknown),
|
||||||
|
dance: Button::Simple(GilButton::Unknown),
|
||||||
|
glide: Button::Simple(GilButton::LeftTrigger),
|
||||||
|
climb: Button::Simple(GilButton::South),
|
||||||
|
climb_down: Button::Simple(GilButton::East),
|
||||||
|
swimup: Button::Simple(GilButton::South),
|
||||||
|
swimdown: Button::Simple(GilButton::East),
|
||||||
|
sneak: Button::Simple(GilButton::East),
|
||||||
|
toggle_lantern: Button::Simple(GilButton::DPadLeft),
|
||||||
|
mount: Button::Simple(GilButton::North),
|
||||||
|
map: Button::Simple(GilButton::Select),
|
||||||
|
bag: Button::Simple(GilButton::DPadRight),
|
||||||
|
quest_log: Button::Simple(GilButton::Unknown),
|
||||||
|
character_window: Button::Simple(GilButton::Unknown),
|
||||||
|
social: Button::Simple(GilButton::Unknown),
|
||||||
|
crafting: Button::Simple(GilButton::DPadDown),
|
||||||
|
spellbook: Button::Simple(GilButton::Unknown),
|
||||||
|
settings: Button::Simple(GilButton::Unknown),
|
||||||
|
help: Button::Simple(GilButton::Unknown),
|
||||||
|
toggle_interface: Button::Simple(GilButton::Unknown),
|
||||||
|
toggle_debug: Button::Simple(GilButton::Unknown),
|
||||||
|
fullscreen: Button::Simple(GilButton::Unknown),
|
||||||
|
screenshot: Button::Simple(GilButton::Unknown),
|
||||||
|
toggle_ingame_ui: Button::Simple(GilButton::Unknown),
|
||||||
|
roll: Button::Simple(GilButton::RightTrigger),
|
||||||
|
respawn: Button::Simple(GilButton::South),
|
||||||
|
interact: Button::Simple(GilButton::North),
|
||||||
|
toggle_wield: Button::Simple(GilButton::West),
|
||||||
|
swap_loadout: Button::Simple(GilButton::LeftThumb),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MenuButtons {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
up: Button::Simple(GilButton::Unknown),
|
||||||
|
down: Button::Simple(GilButton::Unknown),
|
||||||
|
left: Button::Simple(GilButton::Unknown),
|
||||||
|
right: Button::Simple(GilButton::Unknown),
|
||||||
|
scroll_up: Button::Simple(GilButton::Unknown),
|
||||||
|
scroll_down: Button::Simple(GilButton::Unknown),
|
||||||
|
scroll_left: Button::Simple(GilButton::Unknown),
|
||||||
|
scroll_right: Button::Simple(GilButton::Unknown),
|
||||||
|
home: Button::Simple(GilButton::DPadUp),
|
||||||
|
end: Button::Simple(GilButton::DPadDown),
|
||||||
|
apply: Button::Simple(GilButton::South),
|
||||||
|
back: Button::Simple(GilButton::East),
|
||||||
|
exit: Button::Simple(GilButton::Mode),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GameAxis {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
movement_x: Axis::Simple(GilAxis::LeftStickX),
|
||||||
|
movement_y: Axis::Simple(GilAxis::LeftStickY),
|
||||||
|
camera_x: Axis::Simple(GilAxis::RightStickX),
|
||||||
|
camera_y: Axis::Simple(GilAxis::RightStickY),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MenuAxis {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
move_x: Axis::Simple(GilAxis::RightStickX),
|
||||||
|
move_y: Axis::Simple(GilAxis::RightStickY),
|
||||||
|
scroll_x: Axis::Simple(GilAxis::LeftStickX),
|
||||||
|
scroll_y: Axis::Simple(GilAxis::LeftStickY),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GameAnalogButton {
|
||||||
|
fn default() -> Self { Self {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MenuAnalogButton {
|
||||||
|
fn default() -> Self { Self {} }
|
||||||
|
}
|
||||||
|
}
|
37
voxygen/src/settings/gameplay.rs
Normal file
37
voxygen/src/settings/gameplay.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use crate::hud::PressBehavior;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// `GameplaySettings` contains sensitivity and gameplay options.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct GameplaySettings {
|
||||||
|
pub pan_sensitivity: u32,
|
||||||
|
pub zoom_sensitivity: u32,
|
||||||
|
pub camera_clamp_angle: u32,
|
||||||
|
pub zoom_inversion: bool,
|
||||||
|
pub mouse_y_inversion: bool,
|
||||||
|
pub smooth_pan_enable: bool,
|
||||||
|
pub free_look_behavior: PressBehavior,
|
||||||
|
pub auto_walk_behavior: PressBehavior,
|
||||||
|
pub camera_clamp_behavior: PressBehavior,
|
||||||
|
pub stop_auto_walk_on_input: bool,
|
||||||
|
pub auto_camera: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GameplaySettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
pan_sensitivity: 100,
|
||||||
|
zoom_sensitivity: 100,
|
||||||
|
camera_clamp_angle: 45,
|
||||||
|
zoom_inversion: false,
|
||||||
|
mouse_y_inversion: false,
|
||||||
|
smooth_pan_enable: false,
|
||||||
|
free_look_behavior: PressBehavior::Toggle,
|
||||||
|
auto_walk_behavior: PressBehavior::Toggle,
|
||||||
|
camera_clamp_behavior: PressBehavior::Toggle,
|
||||||
|
stop_auto_walk_on_input: true,
|
||||||
|
auto_camera: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
voxygen/src/settings/graphics.rs
Normal file
65
voxygen/src/settings/graphics.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use crate::{render::RenderMode, window::FullScreenSettings};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
pub enum Fps {
|
||||||
|
Max(u32),
|
||||||
|
Unlimited,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fps(max_fps: Fps) -> u32 {
|
||||||
|
match max_fps {
|
||||||
|
Fps::Max(x) => x,
|
||||||
|
Fps::Unlimited => u32::MAX,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Fps {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Fps::Max(x) => write!(f, "{}", x),
|
||||||
|
Fps::Unlimited => write!(f, "Unlimited"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `GraphicsSettings` contains settings related to framerate and in-game
|
||||||
|
/// visuals.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct GraphicsSettings {
|
||||||
|
pub view_distance: u32,
|
||||||
|
pub sprite_render_distance: u32,
|
||||||
|
pub particles_enabled: bool,
|
||||||
|
pub figure_lod_render_distance: u32,
|
||||||
|
pub max_fps: Fps,
|
||||||
|
pub fov: u16,
|
||||||
|
pub gamma: f32,
|
||||||
|
pub exposure: f32,
|
||||||
|
pub ambiance: f32,
|
||||||
|
pub render_mode: RenderMode,
|
||||||
|
pub window_size: [u16; 2],
|
||||||
|
pub fullscreen: FullScreenSettings,
|
||||||
|
pub lod_detail: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GraphicsSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
view_distance: 10,
|
||||||
|
sprite_render_distance: 100,
|
||||||
|
particles_enabled: true,
|
||||||
|
figure_lod_render_distance: 300,
|
||||||
|
max_fps: Fps::Max(60),
|
||||||
|
fov: 70,
|
||||||
|
gamma: 1.0,
|
||||||
|
exposure: 1.0,
|
||||||
|
ambiance: 10.0,
|
||||||
|
render_mode: RenderMode::default(),
|
||||||
|
window_size: [1280, 720],
|
||||||
|
fullscreen: FullScreenSettings::default(),
|
||||||
|
lod_detail: 250,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
voxygen/src/settings/interface.rs
Normal file
75
voxygen/src/settings/interface.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use crate::{
|
||||||
|
hud::{BarNumbers, BuffPosition, CrosshairType, Intro, ShortcutNumbers, XpBar},
|
||||||
|
ui::ScaleMode,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
/// `InterfaceSettings` contains UI, HUD and Map options.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct InterfaceSettings {
|
||||||
|
pub toggle_debug: bool,
|
||||||
|
pub sct: bool,
|
||||||
|
pub sct_player_batch: bool,
|
||||||
|
pub sct_damage_batch: bool,
|
||||||
|
pub speech_bubble_dark_mode: bool,
|
||||||
|
pub speech_bubble_icon: bool,
|
||||||
|
pub crosshair_transp: f32,
|
||||||
|
pub chat_transp: f32,
|
||||||
|
pub chat_character_name: bool,
|
||||||
|
pub crosshair_type: CrosshairType,
|
||||||
|
pub intro_show: Intro,
|
||||||
|
pub xp_bar: XpBar,
|
||||||
|
pub shortcut_numbers: ShortcutNumbers,
|
||||||
|
pub buff_position: BuffPosition,
|
||||||
|
pub bar_numbers: BarNumbers,
|
||||||
|
pub ui_scale: ScaleMode,
|
||||||
|
pub map_zoom: f64,
|
||||||
|
pub map_drag: Vec2<f64>,
|
||||||
|
pub map_show_topo_map: bool,
|
||||||
|
pub map_show_difficulty: bool,
|
||||||
|
pub map_show_towns: bool,
|
||||||
|
pub map_show_dungeons: bool,
|
||||||
|
pub map_show_castles: bool,
|
||||||
|
pub loading_tips: bool,
|
||||||
|
pub map_show_caves: bool,
|
||||||
|
pub map_show_trees: bool,
|
||||||
|
pub minimap_show: bool,
|
||||||
|
pub minimap_face_north: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InterfaceSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
toggle_debug: false,
|
||||||
|
sct: true,
|
||||||
|
sct_player_batch: false,
|
||||||
|
sct_damage_batch: false,
|
||||||
|
speech_bubble_dark_mode: false,
|
||||||
|
speech_bubble_icon: true,
|
||||||
|
crosshair_transp: 0.6,
|
||||||
|
chat_transp: 0.4,
|
||||||
|
chat_character_name: true,
|
||||||
|
crosshair_type: CrosshairType::Round,
|
||||||
|
intro_show: Intro::Show,
|
||||||
|
xp_bar: XpBar::Always,
|
||||||
|
shortcut_numbers: ShortcutNumbers::On,
|
||||||
|
buff_position: BuffPosition::Bar,
|
||||||
|
bar_numbers: BarNumbers::Values,
|
||||||
|
ui_scale: ScaleMode::RelativeToWindow([1920.0, 1080.0].into()),
|
||||||
|
map_zoom: 10.0,
|
||||||
|
map_drag: Vec2 { x: 0.0, y: 0.0 },
|
||||||
|
map_show_topo_map: false,
|
||||||
|
map_show_difficulty: true,
|
||||||
|
map_show_towns: true,
|
||||||
|
map_show_dungeons: true,
|
||||||
|
map_show_castles: true,
|
||||||
|
loading_tips: true,
|
||||||
|
map_show_caves: true,
|
||||||
|
map_show_trees: true,
|
||||||
|
minimap_show: true,
|
||||||
|
minimap_face_north: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
voxygen/src/settings/language.rs
Normal file
16
voxygen/src/settings/language.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use crate::i18n;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct LanguageSettings {
|
||||||
|
pub selected_language: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LanguageSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
selected_language: i18n::REFERENCE_LANG.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
193
voxygen/src/settings/mod.rs
Normal file
193
voxygen/src/settings/mod.rs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
use directories_next::UserDirs;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{fs, path::PathBuf};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
mod audio;
|
||||||
|
mod control;
|
||||||
|
mod gamepad;
|
||||||
|
mod gameplay;
|
||||||
|
mod graphics;
|
||||||
|
mod interface;
|
||||||
|
mod language;
|
||||||
|
mod networking;
|
||||||
|
|
||||||
|
pub use audio::{AudioOutput, AudioSettings};
|
||||||
|
pub use control::ControlSettings;
|
||||||
|
pub use gamepad::GamepadSettings;
|
||||||
|
pub use gameplay::GameplaySettings;
|
||||||
|
pub use graphics::{get_fps, Fps, GraphicsSettings};
|
||||||
|
pub use interface::InterfaceSettings;
|
||||||
|
pub use language::LanguageSettings;
|
||||||
|
pub use networking::NetworkingSettings;
|
||||||
|
|
||||||
|
/// `Log` stores whether we should create a log file
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Log {
|
||||||
|
// Whether to create a log file or not.
|
||||||
|
// Default is to create one.
|
||||||
|
pub log_to_file: bool,
|
||||||
|
// The path on which the logs will be stored
|
||||||
|
pub logs_path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Log {
|
||||||
|
fn default() -> Self {
|
||||||
|
// Chooses a path to store the logs by the following order:
|
||||||
|
// - The VOXYGEN_LOGS environment variable
|
||||||
|
// - The ProjectsDirs data local directory
|
||||||
|
// This function is only called if there isn't already an entry in the settings
|
||||||
|
// file. However, the VOXYGEN_LOGS environment variable always overrides
|
||||||
|
// the log file path if set.
|
||||||
|
let logs_path = std::env::var_os("VOXYGEN_LOGS")
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let mut path = voxygen_data_dir();
|
||||||
|
path.push("logs");
|
||||||
|
path
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
log_to_file: true,
|
||||||
|
logs_path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Settings` contains everything that can be configured in the settings.ron
|
||||||
|
/// file.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Settings {
|
||||||
|
pub controls: ControlSettings,
|
||||||
|
pub interface: InterfaceSettings,
|
||||||
|
pub gameplay: GameplaySettings,
|
||||||
|
pub networking: NetworkingSettings,
|
||||||
|
pub log: Log,
|
||||||
|
pub graphics: GraphicsSettings,
|
||||||
|
pub audio: AudioSettings,
|
||||||
|
pub show_disclaimer: bool,
|
||||||
|
pub send_logon_commands: bool,
|
||||||
|
// TODO: Remove at a later date, for dev testing
|
||||||
|
pub logon_commands: Vec<String>,
|
||||||
|
pub language: LanguageSettings,
|
||||||
|
pub screenshots_path: PathBuf,
|
||||||
|
pub controller: GamepadSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Settings {
|
||||||
|
fn default() -> Self {
|
||||||
|
let user_dirs = UserDirs::new().expect("System's $HOME directory path not found!");
|
||||||
|
|
||||||
|
// Chooses a path to store the screenshots by the following order:
|
||||||
|
// - The VOXYGEN_SCREENSHOT environment variable
|
||||||
|
// - The user's picture directory
|
||||||
|
// - The executable's directory
|
||||||
|
// This only selects if there isn't already an entry in the settings file
|
||||||
|
let screenshots_path = std::env::var_os("VOXYGEN_SCREENSHOT")
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.or_else(|| user_dirs.picture_dir().map(|dir| dir.join("veloren")))
|
||||||
|
.or_else(|| {
|
||||||
|
std::env::current_exe()
|
||||||
|
.ok()
|
||||||
|
.and_then(|dir| dir.parent().map(PathBuf::from))
|
||||||
|
})
|
||||||
|
.expect("Couldn't choose a place to store the screenshots");
|
||||||
|
|
||||||
|
Settings {
|
||||||
|
controls: ControlSettings::default(),
|
||||||
|
interface: InterfaceSettings::default(),
|
||||||
|
gameplay: GameplaySettings::default(),
|
||||||
|
networking: NetworkingSettings::default(),
|
||||||
|
log: Log::default(),
|
||||||
|
graphics: GraphicsSettings::default(),
|
||||||
|
audio: AudioSettings::default(),
|
||||||
|
show_disclaimer: true,
|
||||||
|
send_logon_commands: false,
|
||||||
|
logon_commands: Vec::new(),
|
||||||
|
language: LanguageSettings::default(),
|
||||||
|
screenshots_path,
|
||||||
|
controller: GamepadSettings::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Settings {
|
||||||
|
pub fn load() -> Self {
|
||||||
|
let path = Self::get_settings_path();
|
||||||
|
|
||||||
|
if let Ok(file) = fs::File::open(&path) {
|
||||||
|
match ron::de::from_reader::<_, Self>(file) {
|
||||||
|
Ok(mut s) => {
|
||||||
|
// Override the logs path if it is explicitly set using the VOXYGEN_LOGS
|
||||||
|
// environment variable. This is needed to support package managers that enforce
|
||||||
|
// strict application confinement (e.g. snap). In fact, the veloren snap package
|
||||||
|
// relies on this environment variable to be respected in
|
||||||
|
// order to communicate a path where the snap package is
|
||||||
|
// allowed to write to.
|
||||||
|
if let Some(logs_path_override) =
|
||||||
|
std::env::var_os("VOXYGEN_LOGS").map(PathBuf::from)
|
||||||
|
{
|
||||||
|
s.log.logs_path = logs_path_override;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
warn!(?e, "Failed to parse setting file! Fallback to default.");
|
||||||
|
// Rename the corrupted settings file
|
||||||
|
let mut new_path = path.to_owned();
|
||||||
|
new_path.pop();
|
||||||
|
new_path.push("settings.invalid.ron");
|
||||||
|
if let Err(e) = std::fs::rename(&path, &new_path) {
|
||||||
|
warn!(?e, ?path, ?new_path, "Failed to rename settings file.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This is reached if either:
|
||||||
|
// - The file can't be opened (presumably it doesn't exist)
|
||||||
|
// - Or there was an error parsing the file
|
||||||
|
let default_settings = Self::default();
|
||||||
|
default_settings.save_to_file_warn();
|
||||||
|
default_settings
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_to_file_warn(&self) {
|
||||||
|
if let Err(e) = self.save_to_file() {
|
||||||
|
warn!(?e, "Failed to save settings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_to_file(&self) -> std::io::Result<()> {
|
||||||
|
let path = Self::get_settings_path();
|
||||||
|
if let Some(dir) = path.parent() {
|
||||||
|
fs::create_dir_all(dir)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ron = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
|
||||||
|
fs::write(path, ron.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_settings_path() -> PathBuf {
|
||||||
|
if let Some(path) = std::env::var_os("VOXYGEN_CONFIG") {
|
||||||
|
let settings = PathBuf::from(&path).join("settings.ron");
|
||||||
|
if settings.exists() || settings.parent().map(|x| x.exists()).unwrap_or(false) {
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut path = voxygen_data_dir();
|
||||||
|
path.push("settings.ron");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn voxygen_data_dir() -> PathBuf {
|
||||||
|
// Note: since voxygen is technically a lib we made need to lift this up to
|
||||||
|
// run.rs
|
||||||
|
let mut path = common_base::userdata_dir_workspace!();
|
||||||
|
path.push("voxygen");
|
||||||
|
path
|
||||||
|
}
|
26
voxygen/src/settings/networking.rs
Normal file
26
voxygen/src/settings/networking.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use hashbrown::HashSet;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// `NetworkingSettings` stores server and networking settings.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct NetworkingSettings {
|
||||||
|
pub username: String,
|
||||||
|
pub servers: Vec<String>,
|
||||||
|
pub default_server: String,
|
||||||
|
pub trusted_auth_servers: HashSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for NetworkingSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
username: "".to_string(),
|
||||||
|
servers: vec!["server.veloren.net".to_string()],
|
||||||
|
default_server: "server.veloren.net".to_string(),
|
||||||
|
trusted_auth_servers: ["https://auth.veloren.net"]
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user