mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'hqurve/settings-cleanup' into 'master'
Settings changes from the ui are now wrapped into a single enum and handling was moved to session/settings_change.rs, also settings.rs was split up See merge request veloren/veloren!2130
This commit is contained in:
commit
a386a27411
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
},
|
||||
}
|
||||
}
|
459
voxygen/src/session/settings_change.rs
Normal file
459
voxygen/src/session/settings_change.rs
Normal file
@ -0,0 +1,459 @@
|
||||
use super::SessionState;
|
||||
use crate::{
|
||||
controller::ControllerSettings,
|
||||
hud::{
|
||||
BarNumbers, BuffPosition, CrosshairType, Intro, PressBehavior, ScaleChange,
|
||||
ShortcutNumbers, XpBar,
|
||||
},
|
||||
i18n::{i18n_asset_key, LanguageMetadata, Localization},
|
||||
render::RenderMode,
|
||||
settings::{
|
||||
AudioSettings, ControlSettings, Fps, GamepadSettings, GameplaySettings, GraphicsSettings,
|
||||
InterfaceSettings,
|
||||
},
|
||||
window::{FullScreenSettings, GameInput},
|
||||
GlobalState,
|
||||
};
|
||||
use common::assets::AssetExt;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Audio {
|
||||
AdjustMusicVolume(f32),
|
||||
AdjustSfxVolume(f32),
|
||||
//ChangeAudioDevice(String),
|
||||
ResetAudioSettings,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub enum Control {
|
||||
ChangeBinding(GameInput),
|
||||
ResetKeyBindings,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub enum Gamepad {}
|
||||
#[derive(Clone)]
|
||||
pub enum Gameplay {
|
||||
AdjustMousePan(u32),
|
||||
AdjustMouseZoom(u32),
|
||||
AdjustCameraClamp(u32),
|
||||
|
||||
ToggleControllerYInvert(bool),
|
||||
ToggleMouseYInvert(bool),
|
||||
ToggleZoomInvert(bool),
|
||||
|
||||
ToggleSmoothPan(bool),
|
||||
|
||||
ChangeFreeLookBehavior(PressBehavior),
|
||||
ChangeAutoWalkBehavior(PressBehavior),
|
||||
ChangeCameraClampBehavior(PressBehavior),
|
||||
ChangeStopAutoWalkOnInput(bool),
|
||||
ChangeAutoCamera(bool),
|
||||
|
||||
ResetGameplaySettings,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub enum Graphics {
|
||||
AdjustViewDistance(u32),
|
||||
AdjustLodDetail(u32),
|
||||
AdjustSpriteRenderDistance(u32),
|
||||
AdjustFigureLoDRenderDistance(u32),
|
||||
|
||||
ChangeMaxFPS(Fps),
|
||||
ChangeFOV(u16),
|
||||
|
||||
ChangeGamma(f32),
|
||||
ChangeExposure(f32),
|
||||
ChangeAmbiance(f32),
|
||||
|
||||
ChangeRenderMode(Box<RenderMode>),
|
||||
|
||||
ChangeFullscreenMode(FullScreenSettings),
|
||||
ToggleParticlesEnabled(bool),
|
||||
AdjustWindowSize([u16; 2]),
|
||||
|
||||
ResetGraphicsSettings,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub enum Interface {
|
||||
Sct(bool),
|
||||
SctPlayerBatch(bool),
|
||||
SctDamageBatch(bool),
|
||||
SpeechBubbleDarkMode(bool),
|
||||
SpeechBubbleIcon(bool),
|
||||
ToggleHelp(bool),
|
||||
ToggleDebug(bool),
|
||||
ToggleTips(bool),
|
||||
|
||||
CrosshairTransp(f32),
|
||||
ChatTransp(f32),
|
||||
ChatCharName(bool),
|
||||
CrosshairType(CrosshairType),
|
||||
Intro(Intro),
|
||||
ToggleXpBar(XpBar),
|
||||
ToggleBarNumbers(BarNumbers),
|
||||
ToggleShortcutNumbers(ShortcutNumbers),
|
||||
BuffPosition(BuffPosition),
|
||||
|
||||
UiScale(ScaleChange),
|
||||
//Minimap
|
||||
MinimapShow(bool),
|
||||
MinimapFaceNorth(bool),
|
||||
//Map settings
|
||||
MapZoom(f64),
|
||||
MapDrag(Vec2<f64>),
|
||||
MapShowTopoMap(bool),
|
||||
MapShowDifficulty(bool),
|
||||
MapShowTowns(bool),
|
||||
MapShowDungeons(bool),
|
||||
MapShowCastles(bool),
|
||||
MapShowCaves(bool),
|
||||
MapShowTrees(bool),
|
||||
|
||||
ResetInterfaceSettings,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub enum Language {
|
||||
ChangeLanguage(Box<LanguageMetadata>),
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub enum Networking {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SettingsChange {
|
||||
Audio(Audio),
|
||||
Control(Control),
|
||||
Gamepad(Gamepad),
|
||||
Gameplay(Gameplay),
|
||||
Graphics(Graphics),
|
||||
Interface(Interface),
|
||||
Language(Language),
|
||||
Networking(Networking),
|
||||
}
|
||||
|
||||
macro_rules! settings_change_from {
|
||||
($i: ident) => {
|
||||
impl From<$i> for SettingsChange {
|
||||
fn from(change: $i) -> Self { SettingsChange::$i(change) }
|
||||
}
|
||||
};
|
||||
}
|
||||
settings_change_from!(Audio);
|
||||
settings_change_from!(Control);
|
||||
settings_change_from!(Gamepad);
|
||||
settings_change_from!(Gameplay);
|
||||
settings_change_from!(Graphics);
|
||||
settings_change_from!(Interface);
|
||||
settings_change_from!(Language);
|
||||
settings_change_from!(Networking);
|
||||
|
||||
impl SettingsChange {
|
||||
pub fn process(self, global_state: &mut GlobalState, session_state: &mut SessionState) {
|
||||
let mut settings = &mut global_state.settings;
|
||||
match self {
|
||||
SettingsChange::Audio(audio_change) => {
|
||||
match audio_change {
|
||||
Audio::AdjustMusicVolume(music_volume) => {
|
||||
global_state.audio.set_music_volume(music_volume);
|
||||
|
||||
settings.audio.music_volume = music_volume;
|
||||
},
|
||||
Audio::AdjustSfxVolume(sfx_volume) => {
|
||||
global_state.audio.set_sfx_volume(sfx_volume);
|
||||
|
||||
settings.audio.sfx_volume = sfx_volume;
|
||||
},
|
||||
//Audio::ChangeAudioDevice(name) => {
|
||||
// global_state.audio.set_device(name.clone());
|
||||
|
||||
// settings.audio.output = AudioOutput::Device(name);
|
||||
//},
|
||||
Audio::ResetAudioSettings => {
|
||||
settings.audio = AudioSettings::default();
|
||||
let audio = &settings.audio;
|
||||
global_state.audio.set_music_volume(audio.music_volume);
|
||||
global_state.audio.set_sfx_volume(audio.sfx_volume);
|
||||
},
|
||||
}
|
||||
settings.save_to_file_warn();
|
||||
},
|
||||
SettingsChange::Control(control_change) => match control_change {
|
||||
Control::ChangeBinding(game_input) => {
|
||||
global_state.window.set_keybinding_mode(game_input);
|
||||
},
|
||||
Control::ResetKeyBindings => {
|
||||
settings.controls = ControlSettings::default();
|
||||
settings.save_to_file_warn();
|
||||
},
|
||||
},
|
||||
SettingsChange::Gamepad(gamepad_change) => match gamepad_change {},
|
||||
SettingsChange::Gameplay(gameplay_change) => {
|
||||
let mut window = &mut global_state.window;
|
||||
match gameplay_change {
|
||||
Gameplay::AdjustMousePan(sensitivity) => {
|
||||
window.pan_sensitivity = sensitivity;
|
||||
settings.gameplay.pan_sensitivity = sensitivity;
|
||||
},
|
||||
Gameplay::AdjustMouseZoom(sensitivity) => {
|
||||
window.zoom_sensitivity = sensitivity;
|
||||
settings.gameplay.zoom_sensitivity = sensitivity;
|
||||
},
|
||||
Gameplay::AdjustCameraClamp(angle) => {
|
||||
settings.gameplay.camera_clamp_angle = angle;
|
||||
},
|
||||
Gameplay::ToggleControllerYInvert(controller_y_inverted) => {
|
||||
window.controller_settings.pan_invert_y = controller_y_inverted;
|
||||
settings.controller.pan_invert_y = controller_y_inverted;
|
||||
},
|
||||
Gameplay::ToggleMouseYInvert(mouse_y_inverted) => {
|
||||
window.mouse_y_inversion = mouse_y_inverted;
|
||||
settings.gameplay.mouse_y_inversion = mouse_y_inverted;
|
||||
},
|
||||
Gameplay::ToggleZoomInvert(zoom_inverted) => {
|
||||
window.zoom_inversion = zoom_inverted;
|
||||
settings.gameplay.zoom_inversion = zoom_inverted;
|
||||
},
|
||||
Gameplay::ToggleSmoothPan(smooth_pan_enabled) => {
|
||||
settings.gameplay.smooth_pan_enable = smooth_pan_enabled;
|
||||
},
|
||||
Gameplay::ChangeFreeLookBehavior(behavior) => {
|
||||
settings.gameplay.free_look_behavior = behavior;
|
||||
},
|
||||
Gameplay::ChangeAutoWalkBehavior(behavior) => {
|
||||
settings.gameplay.auto_walk_behavior = behavior;
|
||||
},
|
||||
Gameplay::ChangeCameraClampBehavior(behavior) => {
|
||||
settings.gameplay.camera_clamp_behavior = behavior;
|
||||
},
|
||||
Gameplay::ChangeStopAutoWalkOnInput(state) => {
|
||||
settings.gameplay.stop_auto_walk_on_input = state;
|
||||
},
|
||||
Gameplay::ChangeAutoCamera(state) => {
|
||||
settings.gameplay.auto_camera = state;
|
||||
},
|
||||
Gameplay::ResetGameplaySettings => {
|
||||
// Reset Gameplay Settings
|
||||
settings.gameplay = GameplaySettings::default();
|
||||
// Reset Gamepad and Controller Settings
|
||||
settings.controller = GamepadSettings::default();
|
||||
window.controller_settings = ControllerSettings::from(&settings.controller);
|
||||
// Pan Sensitivity
|
||||
window.pan_sensitivity = settings.gameplay.pan_sensitivity;
|
||||
// Zoom Sensitivity
|
||||
window.zoom_sensitivity = settings.gameplay.zoom_sensitivity;
|
||||
// Invert Scroll Zoom
|
||||
window.zoom_inversion = settings.gameplay.zoom_inversion;
|
||||
// Invert Mouse Y Axis
|
||||
window.mouse_y_inversion = settings.gameplay.mouse_y_inversion;
|
||||
},
|
||||
}
|
||||
settings.save_to_file_warn();
|
||||
},
|
||||
SettingsChange::Graphics(graphics_change) => {
|
||||
match graphics_change {
|
||||
Graphics::AdjustViewDistance(view_distance) => {
|
||||
session_state
|
||||
.client
|
||||
.borrow_mut()
|
||||
.set_view_distance(view_distance);
|
||||
|
||||
settings.graphics.view_distance = view_distance;
|
||||
},
|
||||
Graphics::AdjustLodDetail(lod_detail) => {
|
||||
session_state.scene.lod.set_detail(lod_detail);
|
||||
|
||||
settings.graphics.lod_detail = lod_detail;
|
||||
},
|
||||
Graphics::AdjustSpriteRenderDistance(sprite_render_distance) => {
|
||||
settings.graphics.sprite_render_distance = sprite_render_distance;
|
||||
},
|
||||
Graphics::AdjustFigureLoDRenderDistance(figure_lod_render_distance) => {
|
||||
settings.graphics.figure_lod_render_distance = figure_lod_render_distance;
|
||||
},
|
||||
Graphics::ChangeMaxFPS(fps) => {
|
||||
settings.graphics.max_fps = fps;
|
||||
},
|
||||
Graphics::ChangeFOV(new_fov) => {
|
||||
settings.graphics.fov = new_fov;
|
||||
session_state.scene.camera_mut().set_fov_deg(new_fov);
|
||||
session_state
|
||||
.scene
|
||||
.camera_mut()
|
||||
.compute_dependents(&*session_state.client.borrow().state().terrain());
|
||||
},
|
||||
Graphics::ChangeGamma(new_gamma) => {
|
||||
settings.graphics.gamma = new_gamma;
|
||||
},
|
||||
Graphics::ChangeExposure(new_exposure) => {
|
||||
settings.graphics.exposure = new_exposure;
|
||||
},
|
||||
Graphics::ChangeAmbiance(new_ambiance) => {
|
||||
settings.graphics.ambiance = new_ambiance;
|
||||
},
|
||||
Graphics::ChangeRenderMode(new_render_mode) => {
|
||||
// Do this first so if it crashes the setting isn't saved :)
|
||||
global_state
|
||||
.window
|
||||
.renderer_mut()
|
||||
.set_render_mode((&*new_render_mode).clone())
|
||||
.unwrap();
|
||||
settings.graphics.render_mode = *new_render_mode;
|
||||
},
|
||||
Graphics::ChangeFullscreenMode(new_fullscreen_settings) => {
|
||||
global_state
|
||||
.window
|
||||
.set_fullscreen_mode(new_fullscreen_settings);
|
||||
settings.graphics.fullscreen = new_fullscreen_settings;
|
||||
},
|
||||
Graphics::ToggleParticlesEnabled(particles_enabled) => {
|
||||
settings.graphics.particles_enabled = particles_enabled;
|
||||
},
|
||||
Graphics::AdjustWindowSize(new_size) => {
|
||||
global_state.window.set_size(new_size.into());
|
||||
settings.graphics.window_size = new_size;
|
||||
},
|
||||
Graphics::ResetGraphicsSettings => {
|
||||
settings.graphics = GraphicsSettings::default();
|
||||
let graphics = &settings.graphics;
|
||||
// View distance
|
||||
session_state
|
||||
.client
|
||||
.borrow_mut()
|
||||
.set_view_distance(graphics.view_distance);
|
||||
// FOV
|
||||
session_state.scene.camera_mut().set_fov_deg(graphics.fov);
|
||||
session_state
|
||||
.scene
|
||||
.camera_mut()
|
||||
.compute_dependents(&*session_state.client.borrow().state().terrain());
|
||||
// LoD
|
||||
session_state.scene.lod.set_detail(graphics.lod_detail);
|
||||
// Render mode
|
||||
global_state
|
||||
.window
|
||||
.renderer_mut()
|
||||
.set_render_mode(graphics.render_mode.clone())
|
||||
.unwrap();
|
||||
// Fullscreen mode
|
||||
global_state.window.set_fullscreen_mode(graphics.fullscreen);
|
||||
// Window size
|
||||
global_state.window.set_size(graphics.window_size.into());
|
||||
},
|
||||
}
|
||||
settings.save_to_file_warn();
|
||||
},
|
||||
SettingsChange::Interface(interface_change) => {
|
||||
match interface_change {
|
||||
Interface::Sct(sct) => {
|
||||
settings.interface.sct = sct;
|
||||
},
|
||||
Interface::SctPlayerBatch(sct_player_batch) => {
|
||||
settings.interface.sct_player_batch = sct_player_batch;
|
||||
},
|
||||
Interface::SctDamageBatch(sct_damage_batch) => {
|
||||
settings.interface.sct_damage_batch = sct_damage_batch;
|
||||
},
|
||||
Interface::SpeechBubbleDarkMode(sbdm) => {
|
||||
settings.interface.speech_bubble_dark_mode = sbdm;
|
||||
},
|
||||
Interface::SpeechBubbleIcon(sbi) => {
|
||||
settings.interface.speech_bubble_icon = sbi;
|
||||
},
|
||||
Interface::ToggleHelp(_) => {
|
||||
// implemented in hud
|
||||
},
|
||||
Interface::ToggleDebug(toggle_debug) => {
|
||||
settings.interface.toggle_debug = toggle_debug;
|
||||
},
|
||||
Interface::ToggleTips(loading_tips) => {
|
||||
settings.interface.loading_tips = loading_tips;
|
||||
},
|
||||
Interface::CrosshairTransp(crosshair_transp) => {
|
||||
settings.interface.crosshair_transp = crosshair_transp;
|
||||
},
|
||||
Interface::ChatTransp(chat_transp) => {
|
||||
settings.interface.chat_transp = chat_transp;
|
||||
},
|
||||
Interface::ChatCharName(chat_char_name) => {
|
||||
settings.interface.chat_character_name = chat_char_name;
|
||||
},
|
||||
Interface::CrosshairType(crosshair_type) => {
|
||||
settings.interface.crosshair_type = crosshair_type;
|
||||
},
|
||||
Interface::Intro(intro_show) => {
|
||||
settings.interface.intro_show = intro_show;
|
||||
},
|
||||
Interface::ToggleXpBar(xp_bar) => {
|
||||
settings.interface.xp_bar = xp_bar;
|
||||
},
|
||||
Interface::ToggleBarNumbers(bar_numbers) => {
|
||||
settings.interface.bar_numbers = bar_numbers;
|
||||
},
|
||||
Interface::ToggleShortcutNumbers(shortcut_numbers) => {
|
||||
settings.interface.shortcut_numbers = shortcut_numbers;
|
||||
},
|
||||
Interface::BuffPosition(buff_position) => {
|
||||
settings.interface.buff_position = buff_position;
|
||||
},
|
||||
Interface::UiScale(scale_change) => {
|
||||
settings.interface.ui_scale = session_state.hud.scale_change(scale_change);
|
||||
},
|
||||
Interface::MinimapShow(state) => {
|
||||
settings.interface.minimap_show = state;
|
||||
},
|
||||
Interface::MinimapFaceNorth(state) => {
|
||||
settings.interface.minimap_face_north = state;
|
||||
},
|
||||
Interface::MapZoom(map_zoom) => {
|
||||
settings.interface.map_zoom = map_zoom;
|
||||
},
|
||||
Interface::MapDrag(map_drag) => {
|
||||
settings.interface.map_drag = map_drag;
|
||||
},
|
||||
Interface::MapShowTopoMap(map_show_topo_map) => {
|
||||
settings.interface.map_show_topo_map = map_show_topo_map;
|
||||
},
|
||||
Interface::MapShowDifficulty(map_show_difficulty) => {
|
||||
settings.interface.map_show_difficulty = map_show_difficulty;
|
||||
},
|
||||
Interface::MapShowTowns(map_show_towns) => {
|
||||
settings.interface.map_show_towns = map_show_towns;
|
||||
},
|
||||
Interface::MapShowDungeons(map_show_dungeons) => {
|
||||
settings.interface.map_show_dungeons = map_show_dungeons;
|
||||
},
|
||||
Interface::MapShowCastles(map_show_castles) => {
|
||||
settings.interface.map_show_castles = map_show_castles;
|
||||
},
|
||||
Interface::MapShowCaves(map_show_caves) => {
|
||||
settings.interface.map_show_caves = map_show_caves;
|
||||
},
|
||||
Interface::MapShowTrees(map_show_trees) => {
|
||||
settings.interface.map_show_trees = map_show_trees;
|
||||
},
|
||||
Interface::ResetInterfaceSettings => {
|
||||
// Reset Interface Settings
|
||||
let tmp = settings.interface.intro_show;
|
||||
settings.interface = InterfaceSettings::default();
|
||||
settings.interface.intro_show = tmp;
|
||||
// Update Current Scaling Mode
|
||||
session_state
|
||||
.hud
|
||||
.set_scaling_mode(settings.interface.ui_scale);
|
||||
},
|
||||
}
|
||||
settings.save_to_file_warn();
|
||||
},
|
||||
SettingsChange::Language(language_change) => match language_change {
|
||||
Language::ChangeLanguage(new_language) => {
|
||||
settings.language.selected_language = new_language.language_identifier;
|
||||
global_state.i18n = Localization::load_expect(&i18n_asset_key(
|
||||
&settings.language.selected_language,
|
||||
));
|
||||
global_state.i18n.read().log_missing_entries();
|
||||
session_state.hud.update_fonts(&global_state.i18n.read());
|
||||
},
|
||||
},
|
||||
SettingsChange::Networking(networking_change) => match networking_change {},
|
||||
}
|
||||
}
|
||||
}
|
@ -1,839 +0,0 @@
|
||||
use crate::{
|
||||
hud::{BarNumbers, BuffPosition, CrosshairType, Intro, PressBehavior, ShortcutNumbers, XpBar},
|
||||
i18n,
|
||||
render::RenderMode,
|
||||
ui::ScaleMode,
|
||||
window::{FullScreenSettings, GameInput, KeyMouse},
|
||||
};
|
||||
use directories_next::UserDirs;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fmt, fs, path::PathBuf};
|
||||
use tracing::warn;
|
||||
use vek::*;
|
||||
use winit::event::{MouseButton, VirtualKeyCode};
|
||||
// ControlSetting-like struct used by Serde, to handle not serializing/building
|
||||
// post-deserializing the inverse_keybindings hashmap
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ControlSettingsSerde {
|
||||
keybindings: HashMap<GameInput, KeyMouse>,
|
||||
}
|
||||
|
||||
impl From<ControlSettings> for ControlSettingsSerde {
|
||||
fn from(control_settings: ControlSettings) -> Self {
|
||||
let mut user_bindings: HashMap<GameInput, KeyMouse> = HashMap::new();
|
||||
// Do a delta between default() ControlSettings and the argument, and let
|
||||
// keybindings be only the custom keybindings chosen by the user.
|
||||
for (k, v) in control_settings.keybindings {
|
||||
if ControlSettings::default_binding(k) != v {
|
||||
// Keybinding chosen by the user
|
||||
user_bindings.insert(k, v);
|
||||
}
|
||||
}
|
||||
ControlSettingsSerde {
|
||||
keybindings: user_bindings,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `ControlSettings` contains keybindings.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(from = "ControlSettingsSerde", into = "ControlSettingsSerde")]
|
||||
pub struct ControlSettings {
|
||||
pub keybindings: HashMap<GameInput, KeyMouse>,
|
||||
pub inverse_keybindings: HashMap<KeyMouse, HashSet<GameInput>>, // used in event loop
|
||||
}
|
||||
|
||||
impl From<ControlSettingsSerde> for ControlSettings {
|
||||
fn from(control_serde: ControlSettingsSerde) -> Self {
|
||||
let user_keybindings = control_serde.keybindings;
|
||||
let mut control_settings = ControlSettings::default();
|
||||
for (k, v) in user_keybindings {
|
||||
control_settings.modify_binding(k, v);
|
||||
}
|
||||
control_settings
|
||||
}
|
||||
}
|
||||
|
||||
/// Since Macbook trackpads lack middle click, on OS X we default to LShift
|
||||
/// instead It is an imperfect heuristic, but hopefully it will be a slightly
|
||||
/// better default, and the two places we default to middle click currently
|
||||
/// (roll and wall jump) are both situations where you cannot glide (the other
|
||||
/// default mapping for LShift).
|
||||
#[cfg(target_os = "macos")]
|
||||
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Key(VirtualKeyCode::LShift);
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Mouse(MouseButton::Middle);
|
||||
|
||||
impl ControlSettings {
|
||||
pub fn get_binding(&self, game_input: GameInput) -> Option<KeyMouse> {
|
||||
self.keybindings.get(&game_input).copied()
|
||||
}
|
||||
|
||||
pub fn get_associated_game_inputs(&self, key_mouse: &KeyMouse) -> Option<&HashSet<GameInput>> {
|
||||
self.inverse_keybindings.get(key_mouse)
|
||||
}
|
||||
|
||||
pub fn insert_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
||||
self.keybindings.insert(game_input, key_mouse);
|
||||
self.inverse_keybindings
|
||||
.entry(key_mouse)
|
||||
.or_default()
|
||||
.insert(game_input);
|
||||
}
|
||||
|
||||
pub fn modify_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
||||
// For the KeyMouse->GameInput hashmap, we first need to remove the GameInput
|
||||
// from the old binding
|
||||
if let Some(old_binding) = self.get_binding(game_input) {
|
||||
self.inverse_keybindings
|
||||
.entry(old_binding)
|
||||
.or_default()
|
||||
.remove(&game_input);
|
||||
}
|
||||
// then we add the GameInput to the proper key
|
||||
self.inverse_keybindings
|
||||
.entry(key_mouse)
|
||||
.or_default()
|
||||
.insert(game_input);
|
||||
// For the GameInput->KeyMouse hashmap, just overwrite the value
|
||||
self.keybindings.insert(game_input, key_mouse);
|
||||
}
|
||||
|
||||
/// Return true if this key is used for multiple GameInputs that aren't
|
||||
/// expected to be safe to have bound to the same key at the same time
|
||||
pub fn has_conflicting_bindings(&self, key_mouse: KeyMouse) -> bool {
|
||||
if let Some(game_inputs) = self.inverse_keybindings.get(&key_mouse) {
|
||||
for a in game_inputs.iter() {
|
||||
for b in game_inputs.iter() {
|
||||
if !GameInput::can_share_bindings(*a, *b) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn default_binding(game_input: GameInput) -> KeyMouse {
|
||||
// If a new GameInput is added, be sure to update GameInput::iterator() too!
|
||||
match game_input {
|
||||
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
||||
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
||||
GameInput::ToggleCursor => KeyMouse::Key(VirtualKeyCode::Comma),
|
||||
GameInput::Escape => KeyMouse::Key(VirtualKeyCode::Escape),
|
||||
GameInput::Chat => KeyMouse::Key(VirtualKeyCode::Return),
|
||||
GameInput::Command => KeyMouse::Key(VirtualKeyCode::Slash),
|
||||
GameInput::MoveForward => KeyMouse::Key(VirtualKeyCode::W),
|
||||
GameInput::MoveLeft => KeyMouse::Key(VirtualKeyCode::A),
|
||||
GameInput::MoveBack => KeyMouse::Key(VirtualKeyCode::S),
|
||||
GameInput::MoveRight => KeyMouse::Key(VirtualKeyCode::D),
|
||||
GameInput::Jump => KeyMouse::Key(VirtualKeyCode::Space),
|
||||
GameInput::Sit => KeyMouse::Key(VirtualKeyCode::K),
|
||||
GameInput::Dance => KeyMouse::Key(VirtualKeyCode::J),
|
||||
GameInput::Glide => KeyMouse::Key(VirtualKeyCode::LShift),
|
||||
GameInput::Climb => KeyMouse::Key(VirtualKeyCode::Space),
|
||||
GameInput::ClimbDown => KeyMouse::Key(VirtualKeyCode::LControl),
|
||||
GameInput::SwimUp => KeyMouse::Key(VirtualKeyCode::Space),
|
||||
GameInput::SwimDown => KeyMouse::Key(VirtualKeyCode::LShift),
|
||||
GameInput::Fly => KeyMouse::Key(VirtualKeyCode::H),
|
||||
GameInput::Sneak => KeyMouse::Key(VirtualKeyCode::LControl),
|
||||
GameInput::ToggleLantern => KeyMouse::Key(VirtualKeyCode::G),
|
||||
GameInput::Mount => KeyMouse::Key(VirtualKeyCode::F),
|
||||
GameInput::Map => KeyMouse::Key(VirtualKeyCode::M),
|
||||
GameInput::Bag => KeyMouse::Key(VirtualKeyCode::B),
|
||||
GameInput::Trade => KeyMouse::Key(VirtualKeyCode::R),
|
||||
GameInput::Social => KeyMouse::Key(VirtualKeyCode::O),
|
||||
GameInput::Crafting => KeyMouse::Key(VirtualKeyCode::C),
|
||||
GameInput::Spellbook => KeyMouse::Key(VirtualKeyCode::P),
|
||||
GameInput::Settings => KeyMouse::Key(VirtualKeyCode::N),
|
||||
GameInput::Help => KeyMouse::Key(VirtualKeyCode::F1),
|
||||
GameInput::ToggleInterface => KeyMouse::Key(VirtualKeyCode::F2),
|
||||
GameInput::ToggleDebug => KeyMouse::Key(VirtualKeyCode::F3),
|
||||
GameInput::Fullscreen => KeyMouse::Key(VirtualKeyCode::F11),
|
||||
GameInput::Screenshot => KeyMouse::Key(VirtualKeyCode::F4),
|
||||
GameInput::ToggleIngameUi => KeyMouse::Key(VirtualKeyCode::F6),
|
||||
GameInput::Roll => MIDDLE_CLICK_KEY,
|
||||
GameInput::Respawn => KeyMouse::Key(VirtualKeyCode::Space),
|
||||
GameInput::Interact => KeyMouse::Key(VirtualKeyCode::E),
|
||||
GameInput::ToggleWield => KeyMouse::Key(VirtualKeyCode::T),
|
||||
GameInput::FreeLook => KeyMouse::Key(VirtualKeyCode::L),
|
||||
GameInput::AutoWalk => KeyMouse::Key(VirtualKeyCode::Period),
|
||||
GameInput::CameraClamp => KeyMouse::Key(VirtualKeyCode::Apostrophe),
|
||||
GameInput::CycleCamera => KeyMouse::Key(VirtualKeyCode::Key0),
|
||||
GameInput::Slot1 => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||
GameInput::Slot2 => KeyMouse::Key(VirtualKeyCode::Key2),
|
||||
GameInput::Slot3 => KeyMouse::Key(VirtualKeyCode::Key3),
|
||||
GameInput::Slot4 => KeyMouse::Key(VirtualKeyCode::Key4),
|
||||
GameInput::Slot5 => KeyMouse::Key(VirtualKeyCode::Key5),
|
||||
GameInput::Slot6 => KeyMouse::Key(VirtualKeyCode::Key6),
|
||||
GameInput::Slot7 => KeyMouse::Key(VirtualKeyCode::Key7),
|
||||
GameInput::Slot8 => KeyMouse::Key(VirtualKeyCode::Key8),
|
||||
GameInput::Slot9 => KeyMouse::Key(VirtualKeyCode::Key9),
|
||||
GameInput::Slot10 => KeyMouse::Key(VirtualKeyCode::Q),
|
||||
GameInput::SwapLoadout => KeyMouse::Key(VirtualKeyCode::Tab),
|
||||
GameInput::Select => KeyMouse::Key(VirtualKeyCode::Y),
|
||||
GameInput::AcceptGroupInvite => KeyMouse::Key(VirtualKeyCode::U),
|
||||
GameInput::DeclineGroupInvite => KeyMouse::Key(VirtualKeyCode::I),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ControlSettings {
|
||||
fn default() -> Self {
|
||||
let mut new_settings = Self {
|
||||
keybindings: HashMap::new(),
|
||||
inverse_keybindings: HashMap::new(),
|
||||
};
|
||||
// Sets the initial keybindings for those GameInputs.
|
||||
for game_input in GameInput::iterator() {
|
||||
new_settings.insert_binding(game_input, ControlSettings::default_binding(game_input));
|
||||
}
|
||||
new_settings
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GamepadSettings {
|
||||
pub game_buttons: con_settings::GameButtons,
|
||||
pub menu_buttons: con_settings::MenuButtons,
|
||||
pub game_axis: con_settings::GameAxis,
|
||||
pub menu_axis: con_settings::MenuAxis,
|
||||
pub game_analog_buttons: con_settings::GameAnalogButton,
|
||||
pub menu_analog_buttons: con_settings::MenuAnalogButton,
|
||||
pub pan_sensitivity: u32,
|
||||
pub pan_invert_y: bool,
|
||||
pub axis_deadzones: HashMap<crate::controller::Axis, f32>,
|
||||
pub button_deadzones: HashMap<crate::controller::AnalogButton, f32>,
|
||||
pub mouse_emulation_sensitivity: u32,
|
||||
pub inverted_axes: Vec<crate::controller::Axis>,
|
||||
}
|
||||
|
||||
impl Default for GamepadSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
game_buttons: con_settings::GameButtons::default(),
|
||||
menu_buttons: con_settings::MenuButtons::default(),
|
||||
game_axis: con_settings::GameAxis::default(),
|
||||
menu_axis: con_settings::MenuAxis::default(),
|
||||
game_analog_buttons: con_settings::GameAnalogButton::default(),
|
||||
menu_analog_buttons: con_settings::MenuAnalogButton::default(),
|
||||
pan_sensitivity: 10,
|
||||
pan_invert_y: false,
|
||||
axis_deadzones: HashMap::new(),
|
||||
button_deadzones: HashMap::new(),
|
||||
mouse_emulation_sensitivity: 12,
|
||||
inverted_axes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod con_settings {
|
||||
use crate::controller::*;
|
||||
use gilrs::{Axis as GilAxis, Button as GilButton};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameButtons {
|
||||
pub primary: Button,
|
||||
pub secondary: Button,
|
||||
pub toggle_cursor: Button,
|
||||
pub escape: Button,
|
||||
pub enter: Button,
|
||||
pub command: Button,
|
||||
pub move_forward: Button,
|
||||
pub move_left: Button,
|
||||
pub move_back: Button,
|
||||
pub move_right: Button,
|
||||
pub jump: Button,
|
||||
pub sit: Button,
|
||||
pub dance: Button,
|
||||
pub glide: Button,
|
||||
pub climb: Button,
|
||||
pub climb_down: Button,
|
||||
pub swimup: Button,
|
||||
pub swimdown: Button,
|
||||
pub sneak: Button,
|
||||
pub toggle_lantern: Button,
|
||||
pub mount: Button,
|
||||
pub map: Button,
|
||||
pub bag: Button,
|
||||
pub quest_log: Button,
|
||||
pub character_window: Button,
|
||||
pub social: Button,
|
||||
pub crafting: Button,
|
||||
pub spellbook: Button,
|
||||
pub settings: Button,
|
||||
pub help: Button,
|
||||
pub toggle_interface: Button,
|
||||
pub toggle_debug: Button,
|
||||
pub fullscreen: Button,
|
||||
pub screenshot: Button,
|
||||
pub toggle_ingame_ui: Button,
|
||||
pub roll: Button,
|
||||
pub respawn: Button,
|
||||
pub interact: Button,
|
||||
pub toggle_wield: Button,
|
||||
pub swap_loadout: Button,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuButtons {
|
||||
pub up: Button,
|
||||
pub down: Button,
|
||||
pub left: Button,
|
||||
pub right: Button,
|
||||
pub scroll_up: Button,
|
||||
pub scroll_down: Button,
|
||||
pub scroll_left: Button,
|
||||
pub scroll_right: Button,
|
||||
pub home: Button,
|
||||
pub end: Button,
|
||||
pub apply: Button,
|
||||
pub back: Button,
|
||||
pub exit: Button,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameAxis {
|
||||
pub movement_x: Axis,
|
||||
pub movement_y: Axis,
|
||||
pub camera_x: Axis,
|
||||
pub camera_y: Axis,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuAxis {
|
||||
pub move_x: Axis,
|
||||
pub move_y: Axis,
|
||||
pub scroll_x: Axis,
|
||||
pub scroll_y: Axis,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameAnalogButton {}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuAnalogButton {}
|
||||
|
||||
impl Default for GameButtons {
|
||||
fn default() -> Self {
|
||||
// binding to unknown = getting skipped from processing
|
||||
Self {
|
||||
primary: Button::Simple(GilButton::RightTrigger2),
|
||||
secondary: Button::Simple(GilButton::LeftTrigger2),
|
||||
toggle_cursor: Button::Simple(GilButton::Unknown),
|
||||
escape: Button::Simple(GilButton::Start),
|
||||
enter: Button::Simple(GilButton::Unknown),
|
||||
command: Button::Simple(GilButton::Unknown),
|
||||
move_forward: Button::Simple(GilButton::Unknown),
|
||||
move_left: Button::Simple(GilButton::Unknown),
|
||||
move_back: Button::Simple(GilButton::Unknown),
|
||||
move_right: Button::Simple(GilButton::Unknown),
|
||||
jump: Button::Simple(GilButton::South),
|
||||
sit: Button::Simple(GilButton::Unknown),
|
||||
dance: Button::Simple(GilButton::Unknown),
|
||||
glide: Button::Simple(GilButton::LeftTrigger),
|
||||
climb: Button::Simple(GilButton::South),
|
||||
climb_down: Button::Simple(GilButton::East),
|
||||
swimup: Button::Simple(GilButton::South),
|
||||
swimdown: Button::Simple(GilButton::East),
|
||||
sneak: Button::Simple(GilButton::East),
|
||||
toggle_lantern: Button::Simple(GilButton::DPadLeft),
|
||||
mount: Button::Simple(GilButton::North),
|
||||
map: Button::Simple(GilButton::Select),
|
||||
bag: Button::Simple(GilButton::DPadRight),
|
||||
quest_log: Button::Simple(GilButton::Unknown),
|
||||
character_window: Button::Simple(GilButton::Unknown),
|
||||
social: Button::Simple(GilButton::Unknown),
|
||||
crafting: Button::Simple(GilButton::DPadDown),
|
||||
spellbook: Button::Simple(GilButton::Unknown),
|
||||
settings: Button::Simple(GilButton::Unknown),
|
||||
help: Button::Simple(GilButton::Unknown),
|
||||
toggle_interface: Button::Simple(GilButton::Unknown),
|
||||
toggle_debug: Button::Simple(GilButton::Unknown),
|
||||
fullscreen: Button::Simple(GilButton::Unknown),
|
||||
screenshot: Button::Simple(GilButton::Unknown),
|
||||
toggle_ingame_ui: Button::Simple(GilButton::Unknown),
|
||||
roll: Button::Simple(GilButton::RightTrigger),
|
||||
respawn: Button::Simple(GilButton::South),
|
||||
interact: Button::Simple(GilButton::North),
|
||||
toggle_wield: Button::Simple(GilButton::West),
|
||||
swap_loadout: Button::Simple(GilButton::LeftThumb),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MenuButtons {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
up: Button::Simple(GilButton::Unknown),
|
||||
down: Button::Simple(GilButton::Unknown),
|
||||
left: Button::Simple(GilButton::Unknown),
|
||||
right: Button::Simple(GilButton::Unknown),
|
||||
scroll_up: Button::Simple(GilButton::Unknown),
|
||||
scroll_down: Button::Simple(GilButton::Unknown),
|
||||
scroll_left: Button::Simple(GilButton::Unknown),
|
||||
scroll_right: Button::Simple(GilButton::Unknown),
|
||||
home: Button::Simple(GilButton::DPadUp),
|
||||
end: Button::Simple(GilButton::DPadDown),
|
||||
apply: Button::Simple(GilButton::South),
|
||||
back: Button::Simple(GilButton::East),
|
||||
exit: Button::Simple(GilButton::Mode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GameAxis {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
movement_x: Axis::Simple(GilAxis::LeftStickX),
|
||||
movement_y: Axis::Simple(GilAxis::LeftStickY),
|
||||
camera_x: Axis::Simple(GilAxis::RightStickX),
|
||||
camera_y: Axis::Simple(GilAxis::RightStickY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MenuAxis {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
move_x: Axis::Simple(GilAxis::RightStickX),
|
||||
move_y: Axis::Simple(GilAxis::RightStickY),
|
||||
scroll_x: Axis::Simple(GilAxis::LeftStickX),
|
||||
scroll_y: Axis::Simple(GilAxis::LeftStickY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GameAnalogButton {
|
||||
fn default() -> Self { Self {} }
|
||||
}
|
||||
|
||||
impl Default for MenuAnalogButton {
|
||||
fn default() -> Self { Self {} }
|
||||
}
|
||||
}
|
||||
|
||||
/// `InterfaceSettings` contains UI, HUD and Map options.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct InterfaceSettings {
|
||||
pub toggle_debug: bool,
|
||||
pub sct: bool,
|
||||
pub sct_player_batch: bool,
|
||||
pub sct_damage_batch: bool,
|
||||
pub speech_bubble_dark_mode: bool,
|
||||
pub speech_bubble_icon: bool,
|
||||
pub crosshair_transp: f32,
|
||||
pub chat_transp: f32,
|
||||
pub chat_character_name: bool,
|
||||
pub crosshair_type: CrosshairType,
|
||||
pub intro_show: Intro,
|
||||
pub xp_bar: XpBar,
|
||||
pub shortcut_numbers: ShortcutNumbers,
|
||||
pub buff_position: BuffPosition,
|
||||
pub bar_numbers: BarNumbers,
|
||||
pub ui_scale: ScaleMode,
|
||||
pub map_zoom: f64,
|
||||
pub map_drag: Vec2<f64>,
|
||||
pub map_show_topo_map: bool,
|
||||
pub map_show_difficulty: bool,
|
||||
pub map_show_towns: bool,
|
||||
pub map_show_dungeons: bool,
|
||||
pub map_show_castles: bool,
|
||||
pub loading_tips: bool,
|
||||
pub map_show_caves: bool,
|
||||
pub map_show_trees: bool,
|
||||
pub minimap_show: bool,
|
||||
pub minimap_face_north: bool,
|
||||
}
|
||||
|
||||
impl Default for InterfaceSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
toggle_debug: false,
|
||||
sct: true,
|
||||
sct_player_batch: false,
|
||||
sct_damage_batch: false,
|
||||
speech_bubble_dark_mode: false,
|
||||
speech_bubble_icon: true,
|
||||
crosshair_transp: 0.6,
|
||||
chat_transp: 0.4,
|
||||
chat_character_name: true,
|
||||
crosshair_type: CrosshairType::Round,
|
||||
intro_show: Intro::Show,
|
||||
xp_bar: XpBar::Always,
|
||||
shortcut_numbers: ShortcutNumbers::On,
|
||||
buff_position: BuffPosition::Bar,
|
||||
bar_numbers: BarNumbers::Values,
|
||||
ui_scale: ScaleMode::RelativeToWindow([1920.0, 1080.0].into()),
|
||||
map_zoom: 10.0,
|
||||
map_drag: Vec2 { x: 0.0, y: 0.0 },
|
||||
map_show_topo_map: false,
|
||||
map_show_difficulty: true,
|
||||
map_show_towns: true,
|
||||
map_show_dungeons: true,
|
||||
map_show_castles: true,
|
||||
loading_tips: true,
|
||||
map_show_caves: true,
|
||||
map_show_trees: true,
|
||||
minimap_show: true,
|
||||
minimap_face_north: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `GameplaySettings` contains sensitivity and gameplay options.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameplaySettings {
|
||||
pub pan_sensitivity: u32,
|
||||
pub zoom_sensitivity: u32,
|
||||
pub camera_clamp_angle: u32,
|
||||
pub zoom_inversion: bool,
|
||||
pub mouse_y_inversion: bool,
|
||||
pub smooth_pan_enable: bool,
|
||||
pub free_look_behavior: PressBehavior,
|
||||
pub auto_walk_behavior: PressBehavior,
|
||||
pub camera_clamp_behavior: PressBehavior,
|
||||
pub stop_auto_walk_on_input: bool,
|
||||
pub auto_camera: bool,
|
||||
}
|
||||
|
||||
impl Default for GameplaySettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pan_sensitivity: 100,
|
||||
zoom_sensitivity: 100,
|
||||
camera_clamp_angle: 45,
|
||||
zoom_inversion: false,
|
||||
mouse_y_inversion: false,
|
||||
smooth_pan_enable: false,
|
||||
free_look_behavior: PressBehavior::Toggle,
|
||||
auto_walk_behavior: PressBehavior::Toggle,
|
||||
camera_clamp_behavior: PressBehavior::Toggle,
|
||||
stop_auto_walk_on_input: true,
|
||||
auto_camera: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `NetworkingSettings` stores server and networking settings.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct NetworkingSettings {
|
||||
pub username: String,
|
||||
pub servers: Vec<String>,
|
||||
pub default_server: String,
|
||||
pub trusted_auth_servers: HashSet<String>,
|
||||
}
|
||||
|
||||
impl Default for NetworkingSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
username: "".to_string(),
|
||||
servers: vec!["server.veloren.net".to_string()],
|
||||
default_server: "server.veloren.net".to_string(),
|
||||
trusted_auth_servers: ["https://auth.veloren.net"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `Log` stores whether we should create a log file
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct Log {
|
||||
// Whether to create a log file or not.
|
||||
// Default is to create one.
|
||||
pub log_to_file: bool,
|
||||
// The path on which the logs will be stored
|
||||
pub logs_path: PathBuf,
|
||||
}
|
||||
|
||||
impl Default for Log {
|
||||
fn default() -> Self {
|
||||
// Chooses a path to store the logs by the following order:
|
||||
// - The VOXYGEN_LOGS environment variable
|
||||
// - The ProjectsDirs data local directory
|
||||
// This function is only called if there isn't already an entry in the settings
|
||||
// file. However, the VOXYGEN_LOGS environment variable always overrides
|
||||
// the log file path if set.
|
||||
let logs_path = std::env::var_os("VOXYGEN_LOGS")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| {
|
||||
let mut path = voxygen_data_dir();
|
||||
path.push("logs");
|
||||
path
|
||||
});
|
||||
|
||||
Self {
|
||||
log_to_file: true,
|
||||
logs_path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub enum Fps {
|
||||
Max(u32),
|
||||
Unlimited,
|
||||
}
|
||||
|
||||
pub fn get_fps(max_fps: Fps) -> u32 {
|
||||
match max_fps {
|
||||
Fps::Max(x) => x,
|
||||
Fps::Unlimited => u32::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Fps {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Fps::Max(x) => write!(f, "{}", x),
|
||||
Fps::Unlimited => write!(f, "Unlimited"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `GraphicsSettings` contains settings related to framerate and in-game
|
||||
/// visuals.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GraphicsSettings {
|
||||
pub view_distance: u32,
|
||||
pub sprite_render_distance: u32,
|
||||
pub particles_enabled: bool,
|
||||
pub figure_lod_render_distance: u32,
|
||||
pub max_fps: Fps,
|
||||
pub fov: u16,
|
||||
pub gamma: f32,
|
||||
pub exposure: f32,
|
||||
pub ambiance: f32,
|
||||
pub render_mode: RenderMode,
|
||||
pub window_size: [u16; 2],
|
||||
pub fullscreen: FullScreenSettings,
|
||||
pub lod_detail: u32,
|
||||
}
|
||||
|
||||
impl Default for GraphicsSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
view_distance: 10,
|
||||
sprite_render_distance: 100,
|
||||
particles_enabled: true,
|
||||
figure_lod_render_distance: 300,
|
||||
max_fps: Fps::Max(60),
|
||||
fov: 70,
|
||||
gamma: 1.0,
|
||||
exposure: 1.0,
|
||||
ambiance: 10.0,
|
||||
render_mode: RenderMode::default(),
|
||||
window_size: [1280, 720],
|
||||
fullscreen: FullScreenSettings::default(),
|
||||
lod_detail: 250,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum AudioOutput {
|
||||
/// Veloren's audio system wont work on some systems,
|
||||
/// so you can use this to disable it, and allow the
|
||||
/// game to function
|
||||
// If this option is disabled, functions in the rodio
|
||||
// library MUST NOT be called.
|
||||
Off,
|
||||
#[serde(other)]
|
||||
Automatic,
|
||||
}
|
||||
|
||||
impl AudioOutput {
|
||||
pub fn is_enabled(&self) -> bool { !matches!(self, Self::Off) }
|
||||
}
|
||||
/// `AudioSettings` controls the volume of different audio subsystems and which
|
||||
/// device is used.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct AudioSettings {
|
||||
pub master_volume: f32,
|
||||
pub music_volume: f32,
|
||||
pub sfx_volume: f32,
|
||||
pub max_sfx_channels: usize,
|
||||
|
||||
/// Audio Device that Voxygen will use to play audio.
|
||||
pub output: AudioOutput,
|
||||
}
|
||||
|
||||
impl Default for AudioSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
master_volume: 1.0,
|
||||
music_volume: 0.4,
|
||||
sfx_volume: 0.6,
|
||||
max_sfx_channels: 30,
|
||||
output: AudioOutput::Automatic,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct LanguageSettings {
|
||||
pub selected_language: String,
|
||||
}
|
||||
|
||||
impl Default for LanguageSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
selected_language: i18n::REFERENCE_LANG.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `Settings` contains everything that can be configured in the settings.ron
|
||||
/// file.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct Settings {
|
||||
pub controls: ControlSettings,
|
||||
pub interface: InterfaceSettings,
|
||||
pub gameplay: GameplaySettings,
|
||||
pub networking: NetworkingSettings,
|
||||
pub log: Log,
|
||||
pub graphics: GraphicsSettings,
|
||||
pub audio: AudioSettings,
|
||||
pub show_disclaimer: bool,
|
||||
pub send_logon_commands: bool,
|
||||
// TODO: Remove at a later date, for dev testing
|
||||
pub logon_commands: Vec<String>,
|
||||
pub language: LanguageSettings,
|
||||
pub screenshots_path: PathBuf,
|
||||
pub controller: GamepadSettings,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
let user_dirs = UserDirs::new().expect("System's $HOME directory path not found!");
|
||||
|
||||
// Chooses a path to store the screenshots by the following order:
|
||||
// - The VOXYGEN_SCREENSHOT environment variable
|
||||
// - The user's picture directory
|
||||
// - The executable's directory
|
||||
// This only selects if there isn't already an entry in the settings file
|
||||
let screenshots_path = std::env::var_os("VOXYGEN_SCREENSHOT")
|
||||
.map(PathBuf::from)
|
||||
.or_else(|| user_dirs.picture_dir().map(|dir| dir.join("veloren")))
|
||||
.or_else(|| {
|
||||
std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|dir| dir.parent().map(PathBuf::from))
|
||||
})
|
||||
.expect("Couldn't choose a place to store the screenshots");
|
||||
|
||||
Settings {
|
||||
controls: ControlSettings::default(),
|
||||
interface: InterfaceSettings::default(),
|
||||
gameplay: GameplaySettings::default(),
|
||||
networking: NetworkingSettings::default(),
|
||||
log: Log::default(),
|
||||
graphics: GraphicsSettings::default(),
|
||||
audio: AudioSettings::default(),
|
||||
show_disclaimer: true,
|
||||
send_logon_commands: false,
|
||||
logon_commands: Vec::new(),
|
||||
language: LanguageSettings::default(),
|
||||
screenshots_path,
|
||||
controller: GamepadSettings::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn load() -> Self {
|
||||
let path = Self::get_settings_path();
|
||||
|
||||
if let Ok(file) = fs::File::open(&path) {
|
||||
match ron::de::from_reader::<_, Self>(file) {
|
||||
Ok(mut s) => {
|
||||
// Override the logs path if it is explicitly set using the VOXYGEN_LOGS
|
||||
// environment variable. This is needed to support package managers that enforce
|
||||
// strict application confinement (e.g. snap). In fact, the veloren snap package
|
||||
// relies on this environment variable to be respected in
|
||||
// order to communicate a path where the snap package is
|
||||
// allowed to write to.
|
||||
if let Some(logs_path_override) =
|
||||
std::env::var_os("VOXYGEN_LOGS").map(PathBuf::from)
|
||||
{
|
||||
s.log.logs_path = logs_path_override;
|
||||
}
|
||||
return s;
|
||||
},
|
||||
Err(e) => {
|
||||
warn!(?e, "Failed to parse setting file! Fallback to default.");
|
||||
// Rename the corrupted settings file
|
||||
let mut new_path = path.to_owned();
|
||||
new_path.pop();
|
||||
new_path.push("settings.invalid.ron");
|
||||
if let Err(e) = std::fs::rename(&path, &new_path) {
|
||||
warn!(?e, ?path, ?new_path, "Failed to rename settings file.");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
// This is reached if either:
|
||||
// - The file can't be opened (presumably it doesn't exist)
|
||||
// - Or there was an error parsing the file
|
||||
let default_settings = Self::default();
|
||||
default_settings.save_to_file_warn();
|
||||
default_settings
|
||||
}
|
||||
|
||||
pub fn save_to_file_warn(&self) {
|
||||
if let Err(e) = self.save_to_file() {
|
||||
warn!(?e, "Failed to save settings");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save_to_file(&self) -> std::io::Result<()> {
|
||||
let path = Self::get_settings_path();
|
||||
if let Some(dir) = path.parent() {
|
||||
fs::create_dir_all(dir)?;
|
||||
}
|
||||
|
||||
let ron = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
|
||||
fs::write(path, ron.as_bytes())
|
||||
}
|
||||
|
||||
pub fn get_settings_path() -> PathBuf {
|
||||
if let Some(path) = std::env::var_os("VOXYGEN_CONFIG") {
|
||||
let settings = PathBuf::from(&path).join("settings.ron");
|
||||
if settings.exists() || settings.parent().map(|x| x.exists()).unwrap_or(false) {
|
||||
return settings;
|
||||
}
|
||||
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
|
||||
}
|
||||
|
||||
let mut path = voxygen_data_dir();
|
||||
path.push("settings.ron");
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
pub fn voxygen_data_dir() -> PathBuf {
|
||||
// Note: since voxygen is technically a lib we made need to lift this up to
|
||||
// run.rs
|
||||
let mut path = common_base::userdata_dir_workspace!();
|
||||
path.push("voxygen");
|
||||
path
|
||||
}
|
42
voxygen/src/settings/audio.rs
Normal file
42
voxygen/src/settings/audio.rs
Normal file
@ -0,0 +1,42 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum AudioOutput {
|
||||
/// Veloren's audio system wont work on some systems,
|
||||
/// so you can use this to disable it, and allow the
|
||||
/// game to function
|
||||
// If this option is disabled, functions in the rodio
|
||||
// library MUST NOT be called.
|
||||
Off,
|
||||
#[serde(other)]
|
||||
Automatic,
|
||||
}
|
||||
|
||||
impl AudioOutput {
|
||||
pub fn is_enabled(&self) -> bool { !matches!(self, Self::Off) }
|
||||
}
|
||||
/// `AudioSettings` controls the volume of different audio subsystems and which
|
||||
/// device is used.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct AudioSettings {
|
||||
pub master_volume: f32,
|
||||
pub music_volume: f32,
|
||||
pub sfx_volume: f32,
|
||||
pub max_sfx_channels: usize,
|
||||
|
||||
/// Audio Device that Voxygen will use to play audio.
|
||||
pub output: AudioOutput,
|
||||
}
|
||||
|
||||
impl Default for AudioSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
master_volume: 1.0,
|
||||
music_volume: 0.4,
|
||||
sfx_volume: 0.6,
|
||||
max_sfx_channels: 30,
|
||||
output: AudioOutput::Automatic,
|
||||
}
|
||||
}
|
||||
}
|
185
voxygen/src/settings/control.rs
Normal file
185
voxygen/src/settings/control.rs
Normal file
@ -0,0 +1,185 @@
|
||||
use crate::window::{GameInput, KeyMouse};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use winit::event::{MouseButton, VirtualKeyCode};
|
||||
|
||||
// ControlSetting-like struct used by Serde, to handle not serializing/building
|
||||
// post-deserializing the inverse_keybindings hashmap
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ControlSettingsSerde {
|
||||
keybindings: HashMap<GameInput, KeyMouse>,
|
||||
}
|
||||
|
||||
impl From<ControlSettings> for ControlSettingsSerde {
|
||||
fn from(control_settings: ControlSettings) -> Self {
|
||||
let mut user_bindings: HashMap<GameInput, KeyMouse> = HashMap::new();
|
||||
// Do a delta between default() ControlSettings and the argument, and let
|
||||
// keybindings be only the custom keybindings chosen by the user.
|
||||
for (k, v) in control_settings.keybindings {
|
||||
if ControlSettings::default_binding(k) != v {
|
||||
// Keybinding chosen by the user
|
||||
user_bindings.insert(k, v);
|
||||
}
|
||||
}
|
||||
ControlSettingsSerde {
|
||||
keybindings: user_bindings,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `ControlSettings` contains keybindings.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(from = "ControlSettingsSerde", into = "ControlSettingsSerde")]
|
||||
pub struct ControlSettings {
|
||||
pub keybindings: HashMap<GameInput, KeyMouse>,
|
||||
pub inverse_keybindings: HashMap<KeyMouse, HashSet<GameInput>>, // used in event loop
|
||||
}
|
||||
|
||||
impl From<ControlSettingsSerde> for ControlSettings {
|
||||
fn from(control_serde: ControlSettingsSerde) -> Self {
|
||||
let user_keybindings = control_serde.keybindings;
|
||||
let mut control_settings = ControlSettings::default();
|
||||
for (k, v) in user_keybindings {
|
||||
control_settings.modify_binding(k, v);
|
||||
}
|
||||
control_settings
|
||||
}
|
||||
}
|
||||
|
||||
/// Since Macbook trackpads lack middle click, on OS X we default to LShift
|
||||
/// instead It is an imperfect heuristic, but hopefully it will be a slightly
|
||||
/// better default, and the two places we default to middle click currently
|
||||
/// (roll and wall jump) are both situations where you cannot glide (the other
|
||||
/// default mapping for LShift).
|
||||
#[cfg(target_os = "macos")]
|
||||
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Key(VirtualKeyCode::LShift);
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Mouse(MouseButton::Middle);
|
||||
|
||||
impl ControlSettings {
|
||||
pub fn get_binding(&self, game_input: GameInput) -> Option<KeyMouse> {
|
||||
self.keybindings.get(&game_input).copied()
|
||||
}
|
||||
|
||||
pub fn get_associated_game_inputs(&self, key_mouse: &KeyMouse) -> Option<&HashSet<GameInput>> {
|
||||
self.inverse_keybindings.get(key_mouse)
|
||||
}
|
||||
|
||||
pub fn insert_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
||||
self.keybindings.insert(game_input, key_mouse);
|
||||
self.inverse_keybindings
|
||||
.entry(key_mouse)
|
||||
.or_default()
|
||||
.insert(game_input);
|
||||
}
|
||||
|
||||
pub fn modify_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
||||
// For the KeyMouse->GameInput hashmap, we first need to remove the GameInput
|
||||
// from the old binding
|
||||
if let Some(old_binding) = self.get_binding(game_input) {
|
||||
self.inverse_keybindings
|
||||
.entry(old_binding)
|
||||
.or_default()
|
||||
.remove(&game_input);
|
||||
}
|
||||
// then we add the GameInput to the proper key
|
||||
self.inverse_keybindings
|
||||
.entry(key_mouse)
|
||||
.or_default()
|
||||
.insert(game_input);
|
||||
// For the GameInput->KeyMouse hashmap, just overwrite the value
|
||||
self.keybindings.insert(game_input, key_mouse);
|
||||
}
|
||||
|
||||
/// Return true if this key is used for multiple GameInputs that aren't
|
||||
/// expected to be safe to have bound to the same key at the same time
|
||||
pub fn has_conflicting_bindings(&self, key_mouse: KeyMouse) -> bool {
|
||||
if let Some(game_inputs) = self.inverse_keybindings.get(&key_mouse) {
|
||||
for a in game_inputs.iter() {
|
||||
for b in game_inputs.iter() {
|
||||
if !GameInput::can_share_bindings(*a, *b) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn default_binding(game_input: GameInput) -> KeyMouse {
|
||||
// If a new GameInput is added, be sure to update GameInput::iterator() too!
|
||||
match game_input {
|
||||
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
||||
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
||||
GameInput::ToggleCursor => KeyMouse::Key(VirtualKeyCode::Comma),
|
||||
GameInput::Escape => KeyMouse::Key(VirtualKeyCode::Escape),
|
||||
GameInput::Chat => KeyMouse::Key(VirtualKeyCode::Return),
|
||||
GameInput::Command => KeyMouse::Key(VirtualKeyCode::Slash),
|
||||
GameInput::MoveForward => KeyMouse::Key(VirtualKeyCode::W),
|
||||
GameInput::MoveLeft => KeyMouse::Key(VirtualKeyCode::A),
|
||||
GameInput::MoveBack => KeyMouse::Key(VirtualKeyCode::S),
|
||||
GameInput::MoveRight => KeyMouse::Key(VirtualKeyCode::D),
|
||||
GameInput::Jump => KeyMouse::Key(VirtualKeyCode::Space),
|
||||
GameInput::Sit => KeyMouse::Key(VirtualKeyCode::K),
|
||||
GameInput::Dance => KeyMouse::Key(VirtualKeyCode::J),
|
||||
GameInput::Glide => KeyMouse::Key(VirtualKeyCode::LShift),
|
||||
GameInput::Climb => KeyMouse::Key(VirtualKeyCode::Space),
|
||||
GameInput::ClimbDown => KeyMouse::Key(VirtualKeyCode::LControl),
|
||||
GameInput::SwimUp => KeyMouse::Key(VirtualKeyCode::Space),
|
||||
GameInput::SwimDown => KeyMouse::Key(VirtualKeyCode::LShift),
|
||||
GameInput::Fly => KeyMouse::Key(VirtualKeyCode::H),
|
||||
GameInput::Sneak => KeyMouse::Key(VirtualKeyCode::LControl),
|
||||
GameInput::ToggleLantern => KeyMouse::Key(VirtualKeyCode::G),
|
||||
GameInput::Mount => KeyMouse::Key(VirtualKeyCode::F),
|
||||
GameInput::Map => KeyMouse::Key(VirtualKeyCode::M),
|
||||
GameInput::Bag => KeyMouse::Key(VirtualKeyCode::B),
|
||||
GameInput::Trade => KeyMouse::Key(VirtualKeyCode::R),
|
||||
GameInput::Social => KeyMouse::Key(VirtualKeyCode::O),
|
||||
GameInput::Crafting => KeyMouse::Key(VirtualKeyCode::C),
|
||||
GameInput::Spellbook => KeyMouse::Key(VirtualKeyCode::P),
|
||||
GameInput::Settings => KeyMouse::Key(VirtualKeyCode::N),
|
||||
GameInput::Help => KeyMouse::Key(VirtualKeyCode::F1),
|
||||
GameInput::ToggleInterface => KeyMouse::Key(VirtualKeyCode::F2),
|
||||
GameInput::ToggleDebug => KeyMouse::Key(VirtualKeyCode::F3),
|
||||
GameInput::Fullscreen => KeyMouse::Key(VirtualKeyCode::F11),
|
||||
GameInput::Screenshot => KeyMouse::Key(VirtualKeyCode::F4),
|
||||
GameInput::ToggleIngameUi => KeyMouse::Key(VirtualKeyCode::F6),
|
||||
GameInput::Roll => MIDDLE_CLICK_KEY,
|
||||
GameInput::Respawn => KeyMouse::Key(VirtualKeyCode::Space),
|
||||
GameInput::Interact => KeyMouse::Key(VirtualKeyCode::E),
|
||||
GameInput::ToggleWield => KeyMouse::Key(VirtualKeyCode::T),
|
||||
GameInput::FreeLook => KeyMouse::Key(VirtualKeyCode::L),
|
||||
GameInput::AutoWalk => KeyMouse::Key(VirtualKeyCode::Period),
|
||||
GameInput::CameraClamp => KeyMouse::Key(VirtualKeyCode::Apostrophe),
|
||||
GameInput::CycleCamera => KeyMouse::Key(VirtualKeyCode::Key0),
|
||||
GameInput::Slot1 => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||
GameInput::Slot2 => KeyMouse::Key(VirtualKeyCode::Key2),
|
||||
GameInput::Slot3 => KeyMouse::Key(VirtualKeyCode::Key3),
|
||||
GameInput::Slot4 => KeyMouse::Key(VirtualKeyCode::Key4),
|
||||
GameInput::Slot5 => KeyMouse::Key(VirtualKeyCode::Key5),
|
||||
GameInput::Slot6 => KeyMouse::Key(VirtualKeyCode::Key6),
|
||||
GameInput::Slot7 => KeyMouse::Key(VirtualKeyCode::Key7),
|
||||
GameInput::Slot8 => KeyMouse::Key(VirtualKeyCode::Key8),
|
||||
GameInput::Slot9 => KeyMouse::Key(VirtualKeyCode::Key9),
|
||||
GameInput::Slot10 => KeyMouse::Key(VirtualKeyCode::Q),
|
||||
GameInput::SwapLoadout => KeyMouse::Key(VirtualKeyCode::Tab),
|
||||
GameInput::Select => KeyMouse::Key(VirtualKeyCode::Y),
|
||||
GameInput::AcceptGroupInvite => KeyMouse::Key(VirtualKeyCode::U),
|
||||
GameInput::DeclineGroupInvite => KeyMouse::Key(VirtualKeyCode::I),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ControlSettings {
|
||||
fn default() -> Self {
|
||||
let mut new_settings = Self {
|
||||
keybindings: HashMap::new(),
|
||||
inverse_keybindings: HashMap::new(),
|
||||
};
|
||||
// Sets the initial keybindings for those GameInputs.
|
||||
for game_input in GameInput::iterator() {
|
||||
new_settings.insert_binding(game_input, ControlSettings::default_binding(game_input));
|
||||
}
|
||||
new_settings
|
||||
}
|
||||
}
|
231
voxygen/src/settings/gamepad.rs
Normal file
231
voxygen/src/settings/gamepad.rs
Normal file
@ -0,0 +1,231 @@
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GamepadSettings {
|
||||
pub game_buttons: con_settings::GameButtons,
|
||||
pub menu_buttons: con_settings::MenuButtons,
|
||||
pub game_axis: con_settings::GameAxis,
|
||||
pub menu_axis: con_settings::MenuAxis,
|
||||
pub game_analog_buttons: con_settings::GameAnalogButton,
|
||||
pub menu_analog_buttons: con_settings::MenuAnalogButton,
|
||||
pub pan_sensitivity: u32,
|
||||
pub pan_invert_y: bool,
|
||||
pub axis_deadzones: HashMap<crate::controller::Axis, f32>,
|
||||
pub button_deadzones: HashMap<crate::controller::AnalogButton, f32>,
|
||||
pub mouse_emulation_sensitivity: u32,
|
||||
pub inverted_axes: Vec<crate::controller::Axis>,
|
||||
}
|
||||
|
||||
impl Default for GamepadSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
game_buttons: con_settings::GameButtons::default(),
|
||||
menu_buttons: con_settings::MenuButtons::default(),
|
||||
game_axis: con_settings::GameAxis::default(),
|
||||
menu_axis: con_settings::MenuAxis::default(),
|
||||
game_analog_buttons: con_settings::GameAnalogButton::default(),
|
||||
menu_analog_buttons: con_settings::MenuAnalogButton::default(),
|
||||
pan_sensitivity: 10,
|
||||
pan_invert_y: false,
|
||||
axis_deadzones: HashMap::new(),
|
||||
button_deadzones: HashMap::new(),
|
||||
mouse_emulation_sensitivity: 12,
|
||||
inverted_axes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod con_settings {
|
||||
use crate::controller::*;
|
||||
use gilrs::{Axis as GilAxis, Button as GilButton};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameButtons {
|
||||
pub primary: Button,
|
||||
pub secondary: Button,
|
||||
pub toggle_cursor: Button,
|
||||
pub escape: Button,
|
||||
pub enter: Button,
|
||||
pub command: Button,
|
||||
pub move_forward: Button,
|
||||
pub move_left: Button,
|
||||
pub move_back: Button,
|
||||
pub move_right: Button,
|
||||
pub jump: Button,
|
||||
pub sit: Button,
|
||||
pub dance: Button,
|
||||
pub glide: Button,
|
||||
pub climb: Button,
|
||||
pub climb_down: Button,
|
||||
pub swimup: Button,
|
||||
pub swimdown: Button,
|
||||
pub sneak: Button,
|
||||
pub toggle_lantern: Button,
|
||||
pub mount: Button,
|
||||
pub map: Button,
|
||||
pub bag: Button,
|
||||
pub quest_log: Button,
|
||||
pub character_window: Button,
|
||||
pub social: Button,
|
||||
pub crafting: Button,
|
||||
pub spellbook: Button,
|
||||
pub settings: Button,
|
||||
pub help: Button,
|
||||
pub toggle_interface: Button,
|
||||
pub toggle_debug: Button,
|
||||
pub fullscreen: Button,
|
||||
pub screenshot: Button,
|
||||
pub toggle_ingame_ui: Button,
|
||||
pub roll: Button,
|
||||
pub respawn: Button,
|
||||
pub interact: Button,
|
||||
pub toggle_wield: Button,
|
||||
pub swap_loadout: Button,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuButtons {
|
||||
pub up: Button,
|
||||
pub down: Button,
|
||||
pub left: Button,
|
||||
pub right: Button,
|
||||
pub scroll_up: Button,
|
||||
pub scroll_down: Button,
|
||||
pub scroll_left: Button,
|
||||
pub scroll_right: Button,
|
||||
pub home: Button,
|
||||
pub end: Button,
|
||||
pub apply: Button,
|
||||
pub back: Button,
|
||||
pub exit: Button,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameAxis {
|
||||
pub movement_x: Axis,
|
||||
pub movement_y: Axis,
|
||||
pub camera_x: Axis,
|
||||
pub camera_y: Axis,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuAxis {
|
||||
pub move_x: Axis,
|
||||
pub move_y: Axis,
|
||||
pub scroll_x: Axis,
|
||||
pub scroll_y: Axis,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameAnalogButton {}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuAnalogButton {}
|
||||
|
||||
impl Default for GameButtons {
|
||||
fn default() -> Self {
|
||||
// binding to unknown = getting skipped from processing
|
||||
Self {
|
||||
primary: Button::Simple(GilButton::RightTrigger2),
|
||||
secondary: Button::Simple(GilButton::LeftTrigger2),
|
||||
toggle_cursor: Button::Simple(GilButton::Unknown),
|
||||
escape: Button::Simple(GilButton::Start),
|
||||
enter: Button::Simple(GilButton::Unknown),
|
||||
command: Button::Simple(GilButton::Unknown),
|
||||
move_forward: Button::Simple(GilButton::Unknown),
|
||||
move_left: Button::Simple(GilButton::Unknown),
|
||||
move_back: Button::Simple(GilButton::Unknown),
|
||||
move_right: Button::Simple(GilButton::Unknown),
|
||||
jump: Button::Simple(GilButton::South),
|
||||
sit: Button::Simple(GilButton::Unknown),
|
||||
dance: Button::Simple(GilButton::Unknown),
|
||||
glide: Button::Simple(GilButton::LeftTrigger),
|
||||
climb: Button::Simple(GilButton::South),
|
||||
climb_down: Button::Simple(GilButton::East),
|
||||
swimup: Button::Simple(GilButton::South),
|
||||
swimdown: Button::Simple(GilButton::East),
|
||||
sneak: Button::Simple(GilButton::East),
|
||||
toggle_lantern: Button::Simple(GilButton::DPadLeft),
|
||||
mount: Button::Simple(GilButton::North),
|
||||
map: Button::Simple(GilButton::Select),
|
||||
bag: Button::Simple(GilButton::DPadRight),
|
||||
quest_log: Button::Simple(GilButton::Unknown),
|
||||
character_window: Button::Simple(GilButton::Unknown),
|
||||
social: Button::Simple(GilButton::Unknown),
|
||||
crafting: Button::Simple(GilButton::DPadDown),
|
||||
spellbook: Button::Simple(GilButton::Unknown),
|
||||
settings: Button::Simple(GilButton::Unknown),
|
||||
help: Button::Simple(GilButton::Unknown),
|
||||
toggle_interface: Button::Simple(GilButton::Unknown),
|
||||
toggle_debug: Button::Simple(GilButton::Unknown),
|
||||
fullscreen: Button::Simple(GilButton::Unknown),
|
||||
screenshot: Button::Simple(GilButton::Unknown),
|
||||
toggle_ingame_ui: Button::Simple(GilButton::Unknown),
|
||||
roll: Button::Simple(GilButton::RightTrigger),
|
||||
respawn: Button::Simple(GilButton::South),
|
||||
interact: Button::Simple(GilButton::North),
|
||||
toggle_wield: Button::Simple(GilButton::West),
|
||||
swap_loadout: Button::Simple(GilButton::LeftThumb),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MenuButtons {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
up: Button::Simple(GilButton::Unknown),
|
||||
down: Button::Simple(GilButton::Unknown),
|
||||
left: Button::Simple(GilButton::Unknown),
|
||||
right: Button::Simple(GilButton::Unknown),
|
||||
scroll_up: Button::Simple(GilButton::Unknown),
|
||||
scroll_down: Button::Simple(GilButton::Unknown),
|
||||
scroll_left: Button::Simple(GilButton::Unknown),
|
||||
scroll_right: Button::Simple(GilButton::Unknown),
|
||||
home: Button::Simple(GilButton::DPadUp),
|
||||
end: Button::Simple(GilButton::DPadDown),
|
||||
apply: Button::Simple(GilButton::South),
|
||||
back: Button::Simple(GilButton::East),
|
||||
exit: Button::Simple(GilButton::Mode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GameAxis {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
movement_x: Axis::Simple(GilAxis::LeftStickX),
|
||||
movement_y: Axis::Simple(GilAxis::LeftStickY),
|
||||
camera_x: Axis::Simple(GilAxis::RightStickX),
|
||||
camera_y: Axis::Simple(GilAxis::RightStickY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MenuAxis {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
move_x: Axis::Simple(GilAxis::RightStickX),
|
||||
move_y: Axis::Simple(GilAxis::RightStickY),
|
||||
scroll_x: Axis::Simple(GilAxis::LeftStickX),
|
||||
scroll_y: Axis::Simple(GilAxis::LeftStickY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GameAnalogButton {
|
||||
fn default() -> Self { Self {} }
|
||||
}
|
||||
|
||||
impl Default for MenuAnalogButton {
|
||||
fn default() -> Self { Self {} }
|
||||
}
|
||||
}
|
37
voxygen/src/settings/gameplay.rs
Normal file
37
voxygen/src/settings/gameplay.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use crate::hud::PressBehavior;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// `GameplaySettings` contains sensitivity and gameplay options.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameplaySettings {
|
||||
pub pan_sensitivity: u32,
|
||||
pub zoom_sensitivity: u32,
|
||||
pub camera_clamp_angle: u32,
|
||||
pub zoom_inversion: bool,
|
||||
pub mouse_y_inversion: bool,
|
||||
pub smooth_pan_enable: bool,
|
||||
pub free_look_behavior: PressBehavior,
|
||||
pub auto_walk_behavior: PressBehavior,
|
||||
pub camera_clamp_behavior: PressBehavior,
|
||||
pub stop_auto_walk_on_input: bool,
|
||||
pub auto_camera: bool,
|
||||
}
|
||||
|
||||
impl Default for GameplaySettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pan_sensitivity: 100,
|
||||
zoom_sensitivity: 100,
|
||||
camera_clamp_angle: 45,
|
||||
zoom_inversion: false,
|
||||
mouse_y_inversion: false,
|
||||
smooth_pan_enable: false,
|
||||
free_look_behavior: PressBehavior::Toggle,
|
||||
auto_walk_behavior: PressBehavior::Toggle,
|
||||
camera_clamp_behavior: PressBehavior::Toggle,
|
||||
stop_auto_walk_on_input: true,
|
||||
auto_camera: false,
|
||||
}
|
||||
}
|
||||
}
|
65
voxygen/src/settings/graphics.rs
Normal file
65
voxygen/src/settings/graphics.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use crate::{render::RenderMode, window::FullScreenSettings};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub enum Fps {
|
||||
Max(u32),
|
||||
Unlimited,
|
||||
}
|
||||
|
||||
pub fn get_fps(max_fps: Fps) -> u32 {
|
||||
match max_fps {
|
||||
Fps::Max(x) => x,
|
||||
Fps::Unlimited => u32::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Fps {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Fps::Max(x) => write!(f, "{}", x),
|
||||
Fps::Unlimited => write!(f, "Unlimited"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `GraphicsSettings` contains settings related to framerate and in-game
|
||||
/// visuals.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GraphicsSettings {
|
||||
pub view_distance: u32,
|
||||
pub sprite_render_distance: u32,
|
||||
pub particles_enabled: bool,
|
||||
pub figure_lod_render_distance: u32,
|
||||
pub max_fps: Fps,
|
||||
pub fov: u16,
|
||||
pub gamma: f32,
|
||||
pub exposure: f32,
|
||||
pub ambiance: f32,
|
||||
pub render_mode: RenderMode,
|
||||
pub window_size: [u16; 2],
|
||||
pub fullscreen: FullScreenSettings,
|
||||
pub lod_detail: u32,
|
||||
}
|
||||
|
||||
impl Default for GraphicsSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
view_distance: 10,
|
||||
sprite_render_distance: 100,
|
||||
particles_enabled: true,
|
||||
figure_lod_render_distance: 300,
|
||||
max_fps: Fps::Max(60),
|
||||
fov: 70,
|
||||
gamma: 1.0,
|
||||
exposure: 1.0,
|
||||
ambiance: 10.0,
|
||||
render_mode: RenderMode::default(),
|
||||
window_size: [1280, 720],
|
||||
fullscreen: FullScreenSettings::default(),
|
||||
lod_detail: 250,
|
||||
}
|
||||
}
|
||||
}
|
75
voxygen/src/settings/interface.rs
Normal file
75
voxygen/src/settings/interface.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use crate::{
|
||||
hud::{BarNumbers, BuffPosition, CrosshairType, Intro, ShortcutNumbers, XpBar},
|
||||
ui::ScaleMode,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
/// `InterfaceSettings` contains UI, HUD and Map options.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct InterfaceSettings {
|
||||
pub toggle_debug: bool,
|
||||
pub sct: bool,
|
||||
pub sct_player_batch: bool,
|
||||
pub sct_damage_batch: bool,
|
||||
pub speech_bubble_dark_mode: bool,
|
||||
pub speech_bubble_icon: bool,
|
||||
pub crosshair_transp: f32,
|
||||
pub chat_transp: f32,
|
||||
pub chat_character_name: bool,
|
||||
pub crosshair_type: CrosshairType,
|
||||
pub intro_show: Intro,
|
||||
pub xp_bar: XpBar,
|
||||
pub shortcut_numbers: ShortcutNumbers,
|
||||
pub buff_position: BuffPosition,
|
||||
pub bar_numbers: BarNumbers,
|
||||
pub ui_scale: ScaleMode,
|
||||
pub map_zoom: f64,
|
||||
pub map_drag: Vec2<f64>,
|
||||
pub map_show_topo_map: bool,
|
||||
pub map_show_difficulty: bool,
|
||||
pub map_show_towns: bool,
|
||||
pub map_show_dungeons: bool,
|
||||
pub map_show_castles: bool,
|
||||
pub loading_tips: bool,
|
||||
pub map_show_caves: bool,
|
||||
pub map_show_trees: bool,
|
||||
pub minimap_show: bool,
|
||||
pub minimap_face_north: bool,
|
||||
}
|
||||
|
||||
impl Default for InterfaceSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
toggle_debug: false,
|
||||
sct: true,
|
||||
sct_player_batch: false,
|
||||
sct_damage_batch: false,
|
||||
speech_bubble_dark_mode: false,
|
||||
speech_bubble_icon: true,
|
||||
crosshair_transp: 0.6,
|
||||
chat_transp: 0.4,
|
||||
chat_character_name: true,
|
||||
crosshair_type: CrosshairType::Round,
|
||||
intro_show: Intro::Show,
|
||||
xp_bar: XpBar::Always,
|
||||
shortcut_numbers: ShortcutNumbers::On,
|
||||
buff_position: BuffPosition::Bar,
|
||||
bar_numbers: BarNumbers::Values,
|
||||
ui_scale: ScaleMode::RelativeToWindow([1920.0, 1080.0].into()),
|
||||
map_zoom: 10.0,
|
||||
map_drag: Vec2 { x: 0.0, y: 0.0 },
|
||||
map_show_topo_map: false,
|
||||
map_show_difficulty: true,
|
||||
map_show_towns: true,
|
||||
map_show_dungeons: true,
|
||||
map_show_castles: true,
|
||||
loading_tips: true,
|
||||
map_show_caves: true,
|
||||
map_show_trees: true,
|
||||
minimap_show: true,
|
||||
minimap_face_north: false,
|
||||
}
|
||||
}
|
||||
}
|
16
voxygen/src/settings/language.rs
Normal file
16
voxygen/src/settings/language.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use crate::i18n;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct LanguageSettings {
|
||||
pub selected_language: String,
|
||||
}
|
||||
|
||||
impl Default for LanguageSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
selected_language: i18n::REFERENCE_LANG.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
193
voxygen/src/settings/mod.rs
Normal file
193
voxygen/src/settings/mod.rs
Normal file
@ -0,0 +1,193 @@
|
||||
use directories_next::UserDirs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fs, path::PathBuf};
|
||||
use tracing::warn;
|
||||
|
||||
mod audio;
|
||||
mod control;
|
||||
mod gamepad;
|
||||
mod gameplay;
|
||||
mod graphics;
|
||||
mod interface;
|
||||
mod language;
|
||||
mod networking;
|
||||
|
||||
pub use audio::{AudioOutput, AudioSettings};
|
||||
pub use control::ControlSettings;
|
||||
pub use gamepad::GamepadSettings;
|
||||
pub use gameplay::GameplaySettings;
|
||||
pub use graphics::{get_fps, Fps, GraphicsSettings};
|
||||
pub use interface::InterfaceSettings;
|
||||
pub use language::LanguageSettings;
|
||||
pub use networking::NetworkingSettings;
|
||||
|
||||
/// `Log` stores whether we should create a log file
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct Log {
|
||||
// Whether to create a log file or not.
|
||||
// Default is to create one.
|
||||
pub log_to_file: bool,
|
||||
// The path on which the logs will be stored
|
||||
pub logs_path: PathBuf,
|
||||
}
|
||||
|
||||
impl Default for Log {
|
||||
fn default() -> Self {
|
||||
// Chooses a path to store the logs by the following order:
|
||||
// - The VOXYGEN_LOGS environment variable
|
||||
// - The ProjectsDirs data local directory
|
||||
// This function is only called if there isn't already an entry in the settings
|
||||
// file. However, the VOXYGEN_LOGS environment variable always overrides
|
||||
// the log file path if set.
|
||||
let logs_path = std::env::var_os("VOXYGEN_LOGS")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| {
|
||||
let mut path = voxygen_data_dir();
|
||||
path.push("logs");
|
||||
path
|
||||
});
|
||||
|
||||
Self {
|
||||
log_to_file: true,
|
||||
logs_path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `Settings` contains everything that can be configured in the settings.ron
|
||||
/// file.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct Settings {
|
||||
pub controls: ControlSettings,
|
||||
pub interface: InterfaceSettings,
|
||||
pub gameplay: GameplaySettings,
|
||||
pub networking: NetworkingSettings,
|
||||
pub log: Log,
|
||||
pub graphics: GraphicsSettings,
|
||||
pub audio: AudioSettings,
|
||||
pub show_disclaimer: bool,
|
||||
pub send_logon_commands: bool,
|
||||
// TODO: Remove at a later date, for dev testing
|
||||
pub logon_commands: Vec<String>,
|
||||
pub language: LanguageSettings,
|
||||
pub screenshots_path: PathBuf,
|
||||
pub controller: GamepadSettings,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
let user_dirs = UserDirs::new().expect("System's $HOME directory path not found!");
|
||||
|
||||
// Chooses a path to store the screenshots by the following order:
|
||||
// - The VOXYGEN_SCREENSHOT environment variable
|
||||
// - The user's picture directory
|
||||
// - The executable's directory
|
||||
// This only selects if there isn't already an entry in the settings file
|
||||
let screenshots_path = std::env::var_os("VOXYGEN_SCREENSHOT")
|
||||
.map(PathBuf::from)
|
||||
.or_else(|| user_dirs.picture_dir().map(|dir| dir.join("veloren")))
|
||||
.or_else(|| {
|
||||
std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|dir| dir.parent().map(PathBuf::from))
|
||||
})
|
||||
.expect("Couldn't choose a place to store the screenshots");
|
||||
|
||||
Settings {
|
||||
controls: ControlSettings::default(),
|
||||
interface: InterfaceSettings::default(),
|
||||
gameplay: GameplaySettings::default(),
|
||||
networking: NetworkingSettings::default(),
|
||||
log: Log::default(),
|
||||
graphics: GraphicsSettings::default(),
|
||||
audio: AudioSettings::default(),
|
||||
show_disclaimer: true,
|
||||
send_logon_commands: false,
|
||||
logon_commands: Vec::new(),
|
||||
language: LanguageSettings::default(),
|
||||
screenshots_path,
|
||||
controller: GamepadSettings::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn load() -> Self {
|
||||
let path = Self::get_settings_path();
|
||||
|
||||
if let Ok(file) = fs::File::open(&path) {
|
||||
match ron::de::from_reader::<_, Self>(file) {
|
||||
Ok(mut s) => {
|
||||
// Override the logs path if it is explicitly set using the VOXYGEN_LOGS
|
||||
// environment variable. This is needed to support package managers that enforce
|
||||
// strict application confinement (e.g. snap). In fact, the veloren snap package
|
||||
// relies on this environment variable to be respected in
|
||||
// order to communicate a path where the snap package is
|
||||
// allowed to write to.
|
||||
if let Some(logs_path_override) =
|
||||
std::env::var_os("VOXYGEN_LOGS").map(PathBuf::from)
|
||||
{
|
||||
s.log.logs_path = logs_path_override;
|
||||
}
|
||||
return s;
|
||||
},
|
||||
Err(e) => {
|
||||
warn!(?e, "Failed to parse setting file! Fallback to default.");
|
||||
// Rename the corrupted settings file
|
||||
let mut new_path = path.to_owned();
|
||||
new_path.pop();
|
||||
new_path.push("settings.invalid.ron");
|
||||
if let Err(e) = std::fs::rename(&path, &new_path) {
|
||||
warn!(?e, ?path, ?new_path, "Failed to rename settings file.");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
// This is reached if either:
|
||||
// - The file can't be opened (presumably it doesn't exist)
|
||||
// - Or there was an error parsing the file
|
||||
let default_settings = Self::default();
|
||||
default_settings.save_to_file_warn();
|
||||
default_settings
|
||||
}
|
||||
|
||||
pub fn save_to_file_warn(&self) {
|
||||
if let Err(e) = self.save_to_file() {
|
||||
warn!(?e, "Failed to save settings");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save_to_file(&self) -> std::io::Result<()> {
|
||||
let path = Self::get_settings_path();
|
||||
if let Some(dir) = path.parent() {
|
||||
fs::create_dir_all(dir)?;
|
||||
}
|
||||
|
||||
let ron = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
|
||||
fs::write(path, ron.as_bytes())
|
||||
}
|
||||
|
||||
pub fn get_settings_path() -> PathBuf {
|
||||
if let Some(path) = std::env::var_os("VOXYGEN_CONFIG") {
|
||||
let settings = PathBuf::from(&path).join("settings.ron");
|
||||
if settings.exists() || settings.parent().map(|x| x.exists()).unwrap_or(false) {
|
||||
return settings;
|
||||
}
|
||||
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
|
||||
}
|
||||
|
||||
let mut path = voxygen_data_dir();
|
||||
path.push("settings.ron");
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
pub fn voxygen_data_dir() -> PathBuf {
|
||||
// Note: since voxygen is technically a lib we made need to lift this up to
|
||||
// run.rs
|
||||
let mut path = common_base::userdata_dir_workspace!();
|
||||
path.push("voxygen");
|
||||
path
|
||||
}
|
26
voxygen/src/settings/networking.rs
Normal file
26
voxygen/src/settings/networking.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use hashbrown::HashSet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// `NetworkingSettings` stores server and networking settings.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct NetworkingSettings {
|
||||
pub username: String,
|
||||
pub servers: Vec<String>,
|
||||
pub default_server: String,
|
||||
pub trusted_auth_servers: HashSet<String>,
|
||||
}
|
||||
|
||||
impl Default for NetworkingSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
username: "".to_string(),
|
||||
servers: vec!["server.veloren.net".to_string()],
|
||||
default_server: "server.veloren.net".to_string(),
|
||||
trusted_auth_servers: ["https://auth.veloren.net"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user