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:
Marcel 2021-04-15 09:06:10 +00:00
commit a386a27411
22 changed files with 1529 additions and 1630 deletions

View File

@ -5,6 +5,7 @@ use super::{
};
use crate::{
i18n::Localization,
session::settings_change::{Interface as InterfaceChange, Interface::*},
ui::{fonts::Fonts, img_ids, ImageFrame, Tooltip, TooltipManager, Tooltipable},
GlobalState,
};
@ -117,15 +118,7 @@ pub struct State {
}
pub enum Event {
MapZoom(f64),
MapDrag(Vec2<f64>),
ShowDifficulties(bool),
ShowTowns(bool),
ShowCastles(bool),
ShowDungeons(bool),
ShowCaves(bool),
ShowTrees(bool),
ShowTopoMap(bool),
SettingsChange(InterfaceChange),
Close,
RequestSiteInfo(SiteId),
}
@ -315,7 +308,7 @@ impl<'a> Widget for Map<'a> {
.sum();
// Drag represents offset of view from the player_pos in chunk coords
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(
[
@ -366,7 +359,7 @@ impl<'a> Widget for Map<'a> {
let new_zoom_lvl = (self.global_state.settings.interface.map_zoom
* (scrolled * 0.05 * -1.0).exp2())
.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
// Alignment
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)
.was_clicked()
{
events.push(Event::ShowDifficulties(!show_difficulty));
events.push(Event::SettingsChange(MapShowDifficulty(!show_difficulty)));
}
Text::new(i18n.get("hud.map.difficulty"))
.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)
.was_clicked()
{
events.push(Event::ShowTowns(!show_towns));
events.push(Event::SettingsChange(MapShowTowns(!show_towns)));
}
Text::new(i18n.get("hud.map.towns"))
.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)
.was_clicked()
{
events.push(Event::ShowCastles(!show_castles));
events.push(Event::SettingsChange(MapShowCastles(!show_castles)));
}
Text::new(i18n.get("hud.map.castles"))
.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)
.was_clicked()
{
events.push(Event::ShowDungeons(!show_dungeons));
events.push(Event::SettingsChange(MapShowDungeons(!show_dungeons)));
}
Text::new(i18n.get("hud.map.dungeons"))
.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)
.was_clicked()
{
events.push(Event::ShowCaves(!show_caves));
events.push(Event::SettingsChange(MapShowCaves(!show_caves)));
}
Text::new(i18n.get("hud.map.caves"))
.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)
.was_clicked()
{
events.push(Event::ShowTrees(!show_trees));
events.push(Event::SettingsChange(MapShowTrees(!show_trees)));
}
Text::new(i18n.get("hud.map.trees"))
.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)
.was_clicked()
{
events.push(Event::MapDrag(Vec2::zero()));
events.push(Event::SettingsChange(MapDrag(Vec2::zero())));
};
Image::new(self.imgs.m_move_ico)
@ -942,7 +935,7 @@ impl<'a> Widget for Map<'a> {
.set(state.ids.map_mode_btn, ui)
.was_clicked()
{
events.push(Event::ShowTopoMap(!show_topo_map));
events.push(Event::SettingsChange(MapShowTopoMap(!show_topo_map)));
};
Button::image(self.imgs.map_mode_overlay)
.w_h(92.0, icon_size.y)

View File

@ -4,6 +4,7 @@ use super::{
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
};
use crate::{
session::settings_change::{Interface as InterfaceChange, Interface::*},
ui::{fonts::Fonts, img_ids},
GlobalState,
};
@ -85,8 +86,7 @@ pub struct State {
}
pub enum Event {
Show(bool),
FaceNorth(bool),
SettingsChange(InterfaceChange),
}
impl<'a> Widget for MiniMap<'a> {
@ -227,7 +227,7 @@ impl<'a> Widget for MiniMap<'a> {
.set(state.ids.mmap_north_button, ui)
.was_clicked()
{
return Some(Event::FaceNorth(!is_facing_north));
return Some(Event::SettingsChange(MinimapFaceNorth(!is_facing_north)));
}
// Reload zoom in case it changed.
@ -502,7 +502,7 @@ impl<'a> Widget for MiniMap<'a> {
.set(state.ids.mmap_button, ui)
.was_clicked()
{
return Some(Event::Show(!show_minimap));
return Some(Event::SettingsChange(MinimapShow(!show_minimap)));
}
// TODO: Subregion name display

View File

@ -50,15 +50,17 @@ use trade::Trade;
use crate::{
ecs::{comp as vcomp, comp::HpFloaterList},
hud::{img_ids::ImgsRot, prompt_dialog::DialogOutcomeEvent},
i18n::{LanguageMetadata, Localization},
render::{Consts, Globals, RenderMode, Renderer},
i18n::Localization,
render::{Consts, Globals, Renderer},
scene::camera::{self, Camera},
session::Interactable,
settings::Fps,
session::{
settings_change::{Interface as InterfaceChange, SettingsChange},
Interactable,
},
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,
};
use client::Client;
@ -351,55 +353,8 @@ pub struct HudInfo {
#[derive(Clone)]
pub enum Event {
ToggleTips(bool),
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,
UseSlot {
slot: comp::slot::Slot,
@ -423,19 +378,7 @@ pub enum Event {
Ability4(bool),
Logout,
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),
InviteMember(Uid),
AcceptInvite,
@ -445,9 +388,9 @@ pub enum Event {
AssignLeader(Uid),
RemoveBuff(BuffKind),
UnlockSkill(Skill),
MinimapShow(bool),
MinimapFaceNorth(bool),
RequestSiteInfo(SiteId),
SettingsChange(SettingsChange),
}
// TODO: Are these the possible layouts we want?
@ -1878,7 +1821,9 @@ impl Hud {
.was_clicked()
{
self.show.intro = false;
events.push(Event::Intro(Intro::Never));
events.push(Event::SettingsChange(
InterfaceChange::Intro(Intro::Never).into(),
));
self.show.want_grab = true;
}
if !self.show.crafting && !self.show.bag {
@ -2247,11 +2192,8 @@ impl Hud {
)
.set(self.ids.minimap, ui_widgets)
{
Some(minimap::Event::Show(show)) => {
events.push(Event::MinimapShow(show));
},
Some(minimap::Event::FaceNorth(should_face_north)) => {
events.push(Event::MinimapFaceNorth(should_face_north))
Some(minimap::Event::SettingsChange(interface_change)) => {
events.push(Event::SettingsChange(interface_change.into()));
},
None => {},
}
@ -2556,29 +2498,6 @@ impl Hud {
.set(self.ids.settings_window, ui_widgets)
{
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::Close => {
// Unpause the game if we are on singleplayer so that we can logout
@ -2589,136 +2508,24 @@ impl Hud {
self.show.settings(false)
},
settings_window::Event::AdjustMousePan(sensitivity) => {
events.push(Event::AdjustMousePan(sensitivity));
},
settings_window::Event::AdjustMouseZoom(sensitivity) => {
events.push(Event::AdjustMouseZoom(sensitivity));
},
settings_window::Event::AdjustCameraClamp(sensitivity) => {
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.debug = false;
events.push(Event::ResetInterfaceSettings);
},
settings_window::Event::ResetGameplaySettings => {
events.push(Event::ResetGameplaySettings);
},
settings_window::Event::ResetKeyBindings => {
events.push(Event::ResetKeyBindings);
},
settings_window::Event::ResetGraphicsSettings => {
events.push(Event::ResetGraphicsSettings);
},
settings_window::Event::ResetAudioSettings => {
events.push(Event::ResetAudioSettings);
settings_window::Event::SettingsChange(settings_change) => {
match &settings_change {
SettingsChange::Interface(interface_change) => match interface_change {
InterfaceChange::ToggleHelp(toggle_help) => {
self.show.help = *toggle_help;
},
InterfaceChange::ToggleDebug(toggle_debug) => {
self.show.debug = *toggle_debug;
},
InterfaceChange::ResetInterfaceSettings => {
self.show.help = false;
self.show.debug = false;
},
_ => {},
},
_ => {},
}
events.push(Event::SettingsChange(settings_change));
},
}
}
@ -2818,32 +2625,8 @@ impl Hud {
self.show.want_grab = true;
self.force_ungrab = false;
},
map::Event::ShowTopoMap(map_show_topo_map) => {
events.push(Event::MapShowTopoMap(map_show_topo_map));
},
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::SettingsChange(settings_change) => {
events.push(Event::SettingsChange(settings_change.into()));
},
map::Event::RequestSiteInfo(id) => {
events.push(Event::RequestSiteInfo(id));
@ -2854,7 +2637,9 @@ impl Hud {
// Reset the map position when it's not showing
let drag = &global_state.settings.interface.map_drag;
if drag.x != 0.0 || drag.y != 0.0 {
events.push(Event::MapDrag(Vec2::zero()))
events.push(Event::SettingsChange(
InterfaceChange::MapDrag(Vec2::zero()).into(),
))
}
}

View File

@ -1,8 +1,9 @@
use super::{Event, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
use crate::{
hud::{img_ids::Imgs, ERROR_COLOR, TEXT_BIND_CONFLICT_COLOR, TEXT_COLOR},
i18n::Localization,
session::settings_change::{Control as ControlChange, Control::*},
ui::fonts::Fonts,
window::GameInput,
GlobalState,
@ -57,7 +58,7 @@ pub struct State {
}
impl<'a> Widget for Controls<'a> {
type Event = Vec<Event>;
type Event = Vec<ControlChange>;
type State = State;
type Style = ();
@ -167,7 +168,7 @@ impl<'a> Widget for Controls<'a> {
.set(button_id, ui)
.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
previous_element_id = Some(text_id);
@ -188,7 +189,7 @@ impl<'a> Widget for Controls<'a> {
.set(state.ids.reset_controls_button, ui)
.was_clicked()
{
events.push(Event::ResetKeyBindings);
events.push(ResetKeyBindings);
}
previous_element_id = Some(state.ids.reset_controls_button)
}

View File

@ -1,8 +1,9 @@
use super::{Event, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
use crate::{
hud::{img_ids::Imgs, PressBehavior, MENU_BG, TEXT_COLOR},
i18n::Localization,
session::settings_change::{Gameplay as GameplayChange, Gameplay::*},
ui::{fonts::Fonts, ImageSlider, ToggleButton},
GlobalState,
};
@ -81,7 +82,7 @@ pub struct State {
}
impl<'a> Widget for Gameplay<'a> {
type Event = Vec<Event>;
type Event = Vec<GameplayChange>;
type State = State;
type Style = ();
@ -140,7 +141,7 @@ impl<'a> Widget for Gameplay<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.mouse_pan_slider, ui)
{
events.push(Event::AdjustMousePan(new_val));
events.push(AdjustMousePan(new_val));
}
Text::new(&format!("{}", display_pan))
@ -172,7 +173,7 @@ impl<'a> Widget for Gameplay<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.mouse_zoom_slider, ui)
{
events.push(Event::AdjustMouseZoom(new_val));
events.push(AdjustMouseZoom(new_val));
}
Text::new(&format!("{}", display_zoom))
@ -208,7 +209,7 @@ impl<'a> Widget for Gameplay<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.camera_clamp_slider, ui)
{
events.push(Event::AdjustCameraClamp(new_val));
events.push(AdjustCameraClamp(new_val));
}
Text::new(&format!("{}", display_clamp))
@ -231,7 +232,7 @@ impl<'a> Widget for Gameplay<'a> {
.set(state.ids.mouse_zoom_invert_button, ui);
if self.global_state.settings.gameplay.zoom_inversion != zoom_inverted {
events.push(Event::ToggleZoomInvert(
events.push(ToggleZoomInvert(
!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);
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,
));
}
@ -291,7 +292,7 @@ impl<'a> Widget for Gameplay<'a> {
.set(state.ids.controller_y_invert_button, ui);
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,
));
}
@ -321,7 +322,7 @@ impl<'a> Widget for Gameplay<'a> {
.set(state.ids.smooth_pan_toggle_button, ui);
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,
));
}
@ -371,8 +372,8 @@ impl<'a> Widget for Gameplay<'a> {
.set(state.ids.free_look_behavior_list, ui)
{
match clicked {
0 => events.push(Event::ChangeFreeLookBehavior(PressBehavior::Toggle)),
1 => events.push(Event::ChangeFreeLookBehavior(PressBehavior::Hold)),
0 => events.push(ChangeFreeLookBehavior(PressBehavior::Toggle)),
1 => events.push(ChangeFreeLookBehavior(PressBehavior::Hold)),
_ => unreachable!(),
}
}
@ -401,8 +402,8 @@ impl<'a> Widget for Gameplay<'a> {
.set(state.ids.auto_walk_behavior_list, ui)
{
match clicked {
0 => events.push(Event::ChangeAutoWalkBehavior(PressBehavior::Toggle)),
1 => events.push(Event::ChangeAutoWalkBehavior(PressBehavior::Hold)),
0 => events.push(ChangeAutoWalkBehavior(PressBehavior::Toggle)),
1 => events.push(ChangeAutoWalkBehavior(PressBehavior::Hold)),
_ => unreachable!(),
}
}
@ -431,8 +432,8 @@ impl<'a> Widget for Gameplay<'a> {
.set(state.ids.camera_clamp_behavior_list, ui)
{
match clicked {
0 => events.push(Event::ChangeCameraClampBehavior(PressBehavior::Toggle)),
1 => events.push(Event::ChangeCameraClampBehavior(PressBehavior::Hold)),
0 => events.push(ChangeCameraClampBehavior(PressBehavior::Toggle)),
1 => events.push(ChangeCameraClampBehavior(PressBehavior::Hold)),
_ => unreachable!(),
}
}
@ -452,7 +453,7 @@ impl<'a> Widget for Gameplay<'a> {
if self.global_state.settings.gameplay.stop_auto_walk_on_input
!= stop_auto_walk_on_input_toggle
{
events.push(Event::ChangeStopAutoWalkOnInput(
events.push(ChangeStopAutoWalkOnInput(
!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);
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,
));
}
@ -509,7 +510,7 @@ impl<'a> Widget for Gameplay<'a> {
.set(state.ids.reset_gameplay_button, ui)
.was_clicked()
{
events.push(Event::ResetGameplaySettings);
events.push(ResetGameplaySettings);
}
events

View File

@ -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::{
hud::{
img_ids::Imgs, BarNumbers, BuffPosition, CrosshairType, ShortcutNumbers, Show, TEXT_COLOR,
},
i18n::Localization,
session::settings_change::{Interface as InterfaceChange, Interface::*},
ui::{fonts::Fonts, ImageSlider, ScaleMode, ToggleButton},
GlobalState,
};
@ -126,7 +127,7 @@ pub struct State {
}
impl<'a> Widget for Interface<'a> {
type Event = Vec<Event>;
type Event = Vec<InterfaceChange>;
type State = State;
type Style = ();
@ -185,7 +186,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.button_help, ui);
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"))
@ -209,7 +210,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.load_tips_button, ui);
if self.global_state.settings.interface.loading_tips != show_tips {
events.push(Event::ToggleTips(
events.push(ToggleTips(
!self.global_state.settings.interface.loading_tips,
));
}
@ -234,7 +235,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.debug_button, ui);
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"))
@ -277,7 +278,7 @@ impl<'a> Widget for Interface<'a> {
.was_clicked()
&& !relative_selected
{
events.push(Event::UiScale(ScaleChange::ToRelative));
events.push(UiScale(ScaleChange::ToRelative));
}
Text::new(self.localized_strings.get("hud.settings.relative_scaling"))
@ -312,7 +313,7 @@ impl<'a> Widget for Interface<'a> {
.was_clicked()
&& !absolute_selected
{
events.push(Event::UiScale(ScaleChange::ToAbsolute));
events.push(UiScale(ScaleChange::ToAbsolute));
}
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))
.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
Text::new(&format!("{:.2}", scale))
@ -384,7 +385,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.ch_1_bg, ui)
.was_clicked()
{
events.push(Event::CrosshairType(CrosshairType::Round));
events.push(CrosshairType(CrosshairType::Round));
}
// Crosshair
@ -427,7 +428,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.ch_2_bg, ui)
.was_clicked()
{
events.push(Event::CrosshairType(CrosshairType::RoundEdges));
events.push(CrosshairType(CrosshairType::RoundEdges));
}
// Crosshair
@ -470,7 +471,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.ch_3_bg, ui)
.was_clicked()
{
events.push(Event::CrosshairType(CrosshairType::Edges));
events.push(CrosshairType(CrosshairType::Edges));
}
// Crosshair
@ -519,7 +520,7 @@ impl<'a> Widget for Interface<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.ch_transp_slider, ui)
{
events.push(Event::CrosshairTransp(new_val));
events.push(CrosshairTransp(new_val));
}
Text::new(&format!("{:.2}", crosshair_transp,))
@ -562,12 +563,8 @@ impl<'a> Widget for Interface<'a> {
.was_clicked()
{
match self.global_state.settings.interface.shortcut_numbers {
ShortcutNumbers::On => {
events.push(Event::ToggleShortcutNumbers(ShortcutNumbers::Off))
},
ShortcutNumbers::Off => {
events.push(Event::ToggleShortcutNumbers(ShortcutNumbers::On))
},
ShortcutNumbers::On => events.push(ToggleShortcutNumbers(ShortcutNumbers::Off)),
ShortcutNumbers::Off => events.push(ToggleShortcutNumbers(ShortcutNumbers::On)),
}
}
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)
.was_clicked()
{
events.push(Event::BuffPosition(BuffPosition::Bar))
events.push(BuffPosition(BuffPosition::Bar))
}
Text::new(&self.localized_strings.get("hud.settings.buffs_skillbar"))
.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)
.was_clicked()
{
events.push(Event::BuffPosition(BuffPosition::Map))
events.push(BuffPosition(BuffPosition::Map))
}
Text::new(&self.localized_strings.get("hud.settings.buffs_mmap"))
.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);
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(
&self
@ -719,7 +716,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.sct_show_batch_radio, ui);
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,
))
}
@ -762,7 +759,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.sct_batch_inc_radio, ui);
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,
))
}
@ -806,7 +803,7 @@ impl<'a> Widget for Interface<'a> {
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.speech_bubble_dark_mode_button, ui);
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(
&self
@ -830,7 +827,7 @@ impl<'a> Widget for Interface<'a> {
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.speech_bubble_icon_button, ui);
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(
&self
@ -873,7 +870,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.show_bar_numbers_none_button, ui)
.was_clicked()
{
events.push(Event::ToggleBarNumbers(BarNumbers::Off))
events.push(ToggleBarNumbers(BarNumbers::Off))
}
Text::new(&self.localized_strings.get("hud.settings.none"))
.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)
.was_clicked()
{
events.push(Event::ToggleBarNumbers(BarNumbers::Values))
events.push(ToggleBarNumbers(BarNumbers::Values))
}
Text::new(&self.localized_strings.get("hud.settings.values"))
.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)
.was_clicked()
{
events.push(Event::ToggleBarNumbers(BarNumbers::Percent))
events.push(ToggleBarNumbers(BarNumbers::Percent))
}
Text::new(&self.localized_strings.get("hud.settings.percentages"))
.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))
.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
@ -992,7 +989,7 @@ impl<'a> Widget for Interface<'a> {
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.chat_char_name_button, ui);
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,
));
}
@ -1023,7 +1020,7 @@ impl<'a> Widget for Interface<'a> {
.set(state.ids.reset_interface_button, ui)
.was_clicked()
{
events.push(Event::ResetInterfaceSettings);
events.push(ResetInterfaceSettings);
}
events

View File

@ -1,8 +1,7 @@
use super::Event;
use crate::{
hud::{img_ids::Imgs, TEXT_COLOR},
i18n::list_localizations,
session::settings_change::{Language as LanguageChange, Language::*},
ui::fonts::Fonts,
GlobalState,
};
@ -45,7 +44,7 @@ pub struct State {
}
impl<'a> Widget for Language<'a> {
type Event = Vec<Event>;
type Event = Vec<LanguageChange>;
type State = State;
type Style = ();
@ -114,7 +113,7 @@ impl<'a> Widget for Language<'a> {
.set(state.ids.language_list[i], ui)
.was_clicked()
{
events.push(Event::ChangeLanguage(Box::new(language.to_owned())));
events.push(ChangeLanguage(Box::new(language.to_owned())));
}
}

View File

@ -6,15 +6,10 @@ mod sound;
mod video;
use crate::{
hud::{
img_ids::Imgs, BarNumbers, BuffPosition, CrosshairType, PressBehavior, ShortcutNumbers,
Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
},
i18n::{LanguageMetadata, Localization},
render::RenderMode,
settings::Fps,
hud::{img_ids::Imgs, Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN},
i18n::Localization,
session::settings_change::SettingsChange,
ui::fonts::Fonts,
window::{FullScreenSettings, GameInput},
GlobalState,
};
use conrod_core::{
@ -120,59 +115,9 @@ pub struct State {
}
pub enum Event {
ToggleHelp,
ToggleDebug,
ToggleTips(bool),
ToggleBarNumbers(BarNumbers),
ToggleShortcutNumbers(ShortcutNumbers),
BuffPosition(BuffPosition),
ChangeTab(SettingsTab),
Close,
AdjustMousePan(u32),
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),
SettingsChange(SettingsChange),
}
#[derive(Clone)]
@ -294,41 +239,63 @@ impl<'a> Widget for SettingsWindow<'a> {
let imgs = self.imgs;
let fonts = self.fonts;
let localized_strings = self.localized_strings;
for event in match self.show.settings_tab {
match self.show.settings_tab {
SettingsTab::Interface => {
interface::Interface::new(global_state, show, imgs, fonts, localized_strings)
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
.wh_of(state.ids.settings_content_align)
.set(state.ids.interface, ui)
for change in
interface::Interface::new(global_state, show, imgs, fonts, localized_strings)
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
.wh_of(state.ids.settings_content_align)
.set(state.ids.interface, ui)
{
events.push(Event::SettingsChange(change.into()));
}
},
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)
.wh_of(state.ids.settings_content_align)
.set(state.ids.gameplay, ui)
{
events.push(Event::SettingsChange(change.into()));
}
},
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)
.wh_of(state.ids.settings_content_align)
.set(state.ids.controls, ui)
{
events.push(Event::SettingsChange(change.into()));
}
},
SettingsTab::Video => {
video::Video::new(global_state, imgs, fonts, localized_strings, self.fps)
for change in
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)
.wh_of(state.ids.settings_content_align)
.set(state.ids.video, ui)
{
events.push(Event::SettingsChange(change.into()));
}
},
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)
.wh_of(state.ids.settings_content_align)
.set(state.ids.video, ui)
.set(state.ids.sound, ui)
{
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)
.wh_of(state.ids.settings_content_align)
.set(state.ids.language, ui)
{
events.push(Event::SettingsChange(change.into()));
}
},
SettingsTab::Sound => sound::Sound::new(global_state, imgs, fonts, localized_strings)
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
.wh_of(state.ids.settings_content_align)
.set(state.ids.sound, ui),
SettingsTab::Lang => language::Language::new(global_state, imgs, fonts)
.top_left_with_margins_on(state.ids.settings_content_align, 0.0, 0.0)
.wh_of(state.ids.settings_content_align)
.set(state.ids.language, ui),
} {
events.push(event);
}
events

View File

@ -1,8 +1,9 @@
use super::{Event, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
use crate::{
hud::{img_ids::Imgs, TEXT_COLOR},
i18n::Localization,
session::settings_change::{Audio as AudioChange, Audio::*},
ui::{fonts::Fonts, ImageSlider},
GlobalState,
};
@ -59,7 +60,7 @@ pub struct State {
}
impl<'a> Widget for Sound<'a> {
type Event = Vec<Event>;
type Event = Vec<AudioChange>;
type State = State;
type Style = ();
@ -114,7 +115,7 @@ impl<'a> Widget for Sound<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.audio_volume_slider, ui)
{
events.push(Event::AdjustMusicVolume(new_val));
events.push(AdjustMusicVolume(new_val));
}
// SFX Volume -------------------------------------------------------
@ -143,7 +144,7 @@ impl<'a> Widget for Sound<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.sfx_volume_slider, ui)
{
events.push(Event::AdjustSfxVolume(new_val));
events.push(AdjustSfxVolume(new_val));
}
// Audio Device Selector
@ -170,7 +171,7 @@ impl<'a> Widget for Sound<'a> {
// .set(state.ids.audio_device_list, ui)
//{
// 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
@ -187,7 +188,7 @@ impl<'a> Widget for Sound<'a> {
.set(state.ids.reset_sound_button, ui)
.was_clicked()
{
events.push(Event::ResetAudioSettings);
events.push(ResetAudioSettings);
}
events

View File

@ -1,4 +1,4 @@
use super::{Event, RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
use crate::{
hud::{
@ -10,6 +10,7 @@ use crate::{
AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode,
UpscaleMode,
},
session::settings_change::{Graphics as GraphicsChange, Graphics::*},
settings::Fps,
ui::{fonts::Fonts, ImageSlider, ToggleButton},
window::{FullScreenSettings, FullscreenMode},
@ -145,7 +146,7 @@ const FPS_CHOICES: [Fps; 12] = [
];
impl<'a> Widget for Video<'a> {
type Event = Vec<Event>;
type Event = Vec<GraphicsChange>;
type State = State;
type Style = ();
@ -226,7 +227,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.vd_slider, ui)
{
events.push(Event::AdjustViewDistance(new_val));
events.push(AdjustViewDistance(new_val));
}
Text::new(&format!(
@ -264,7 +265,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.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())
@ -296,7 +297,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.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))
@ -329,7 +330,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.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,
));
}
@ -366,7 +367,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.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))
@ -391,7 +392,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.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"))
@ -429,7 +430,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.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"))
.up_from(state.ids.ambiance_slider, 8.0)
@ -465,7 +466,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.sprite_dist_slider, ui)
{
events.push(Event::AdjustSpriteRenderDistance(new_val));
events.push(AdjustSpriteRenderDistance(new_val));
}
Text::new(
&self
@ -505,7 +506,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.set(state.ids.figure_dist_slider, ui)
{
events.push(Event::AdjustFigureLoDRenderDistance(new_val));
events.push(AdjustFigureLoDRenderDistance(new_val));
}
Text::new(
&self
@ -569,7 +570,7 @@ impl<'a> Widget for Video<'a> {
.down_from(state.ids.aa_mode_text, 8.0)
.set(state.ids.aa_mode_list, ui)
{
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
events.push(ChangeRenderMode(Box::new(RenderMode {
aa: mode_list[clicked],
..render_mode.clone()
})));
@ -609,7 +610,7 @@ impl<'a> Widget for Video<'a> {
.down_from(state.ids.upscale_factor_text, 8.0)
.set(state.ids.upscale_factor_list, ui)
{
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
events.push(ChangeRenderMode(Box::new(RenderMode {
upscale_mode: UpscaleMode {
factor: upscale_factors[clicked],
},
@ -667,7 +668,7 @@ impl<'a> Widget for Video<'a> {
.down_from(state.ids.cloud_mode_text, 8.0)
.set(state.ids.cloud_mode_list, ui)
{
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
events.push(ChangeRenderMode(Box::new(RenderMode {
cloud: mode_list[clicked],
..render_mode.clone()
})));
@ -706,7 +707,7 @@ impl<'a> Widget for Video<'a> {
.down_from(state.ids.fluid_mode_text, 8.0)
.set(state.ids.fluid_mode_list, ui)
{
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
events.push(ChangeRenderMode(Box::new(RenderMode {
fluid: mode_list[clicked],
..render_mode.clone()
})));
@ -752,7 +753,7 @@ impl<'a> Widget for Video<'a> {
.down_from(state.ids.lighting_mode_text, 8.0)
.set(state.ids.lighting_mode_list, ui)
{
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
events.push(ChangeRenderMode(Box::new(RenderMode {
lighting: mode_list[clicked],
..render_mode.clone()
})));
@ -799,7 +800,7 @@ impl<'a> Widget for Video<'a> {
.down_from(state.ids.shadow_mode_text, 8.0)
.set(state.ids.shadow_mode_list, ui)
{
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
events.push(ChangeRenderMode(Box::new(RenderMode {
shadow: mode_list[clicked],
..render_mode.clone()
})));
@ -832,7 +833,7 @@ impl<'a> Widget for Video<'a> {
.pad_track((5.0, 5.0))
.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 {
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);
if self.global_state.settings.graphics.particles_enabled != particles_enabled {
events.push(Event::ToggleParticlesEnabled(particles_enabled));
events.push(ToggleParticlesEnabled(particles_enabled));
}
// Resolution
@ -907,7 +908,7 @@ impl<'a> Widget for Video<'a> {
.down_from(state.ids.resolution_label, 10.0)
.set(state.ids.resolution, ui)
{
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
events.push(ChangeFullscreenMode(FullScreenSettings {
resolution: resolutions[clicked],
..self.global_state.settings.graphics.fullscreen
}));
@ -971,7 +972,7 @@ impl<'a> Widget for Video<'a> {
.right_from(state.ids.resolution, 8.0)
.set(state.ids.bit_depth, ui)
{
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
events.push(ChangeFullscreenMode(FullScreenSettings {
bit_depth: if clicked == 0 {
None
} else {
@ -1025,7 +1026,7 @@ impl<'a> Widget for Video<'a> {
.right_from(state.ids.bit_depth, 8.0)
.set(state.ids.refresh_rate, ui)
{
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
events.push(ChangeFullscreenMode(FullScreenSettings {
refresh_rate: if clicked == 0 {
None
} else {
@ -1055,7 +1056,7 @@ impl<'a> Widget for Video<'a> {
.set(state.ids.fullscreen_button, ui);
if self.global_state.settings.graphics.fullscreen.enabled != enabled {
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
events.push(ChangeFullscreenMode(FullScreenSettings {
enabled,
..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)
.set(state.ids.fullscreen_mode_list, ui)
{
events.push(Event::ChangeFullscreenMode(FullScreenSettings {
events.push(ChangeFullscreenMode(FullScreenSettings {
mode: mode_list[clicked],
..self.global_state.settings.graphics.fullscreen
}));
@ -1112,7 +1113,7 @@ impl<'a> Widget for Video<'a> {
.set(state.ids.save_window_size_button, ui)
.was_clicked()
{
events.push(Event::AdjustWindowSize(
events.push(AdjustWindowSize(
self.global_state
.window
.logical_size()
@ -1136,7 +1137,7 @@ impl<'a> Widget for Video<'a> {
.set(state.ids.reset_graphics_button, ui)
.was_clicked()
{
events.push(Event::ResetGraphicsSettings);
events.push(ResetGraphicsSettings);
}
events

View File

@ -1,3 +1,5 @@
pub mod settings_change;
use std::{cell::RefCell, collections::HashSet, rc::Rc, time::Duration};
use ordered_float::OrderedFloat;
@ -7,7 +9,6 @@ use vek::*;
use client::{self, Client};
use common::{
assets::AssetExt,
comp,
comp::{
inventory::slot::{EquipSlot, Slot},
@ -33,20 +34,16 @@ use common_net::{
use crate::{
audio::sfx::SfxEvent,
controller::ControllerSettings,
hud::{DebugInfo, Event as HudEvent, Hud, HudInfo, PromptDialogSettings},
i18n::{i18n_asset_key, Localization},
key_state::KeyState,
menu::char_selection::CharSelectionState,
render::Renderer,
scene::{camera, CameraMode, Scene, SceneData},
settings::{
AudioSettings, ControlSettings, GamepadSettings, GameplaySettings, GraphicsSettings,
InterfaceSettings, Settings,
},
settings::Settings,
window::{AnalogGameInput, Event, GameInput},
Direction, Error, GlobalState, PlayState, PlayStateResult,
};
use settings_change::Language::ChangeLanguage;
/// The action to perform after a tick
enum TickAction {
@ -903,9 +900,9 @@ impl PlayState for SessionState {
// Look for changes in the localization files
if global_state.i18n.reloaded() {
hud_events.push(HudEvent::ChangeLanguage(Box::new(
global_state.i18n.read().metadata.clone(),
)));
hud_events.push(HudEvent::SettingsChange(
ChangeLanguage(Box::new(global_state.i18n.read().metadata.clone())).into(),
));
}
// Maintain the UI.
@ -925,153 +922,7 @@ impl PlayState for SessionState {
HudEvent::Quit => {
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) => {
let mut client = self.client.borrow_mut();
client.remove_buff(buff_id);
@ -1317,124 +1168,12 @@ impl PlayState for SessionState {
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) => {
let mut client = self.client.borrow_mut();
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) => {
self.client.borrow_mut().craft_recipe(&r);
},
@ -1456,83 +1195,8 @@ impl PlayState for SessionState {
HudEvent::AssignLeader(uid) => {
self.client.borrow_mut().assign_group_leader(uid);
},
HudEvent::MinimapShow(state) => {
global_state.settings.interface.minimap_show = state;
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);
HudEvent::SettingsChange(settings_change) => {
settings_change.process(global_state, self);
},
}
}

View 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 {},
}
}
}

View File

@ -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
}

View 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,
}
}
}

View 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
}
}

View 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 {} }
}
}

View 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,
}
}
}

View 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,
}
}
}

View 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,
}
}
}

View 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
View 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
}

View 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(),
}
}
}