Skip to main content

veloren_voxygen/session/
settings_change.rs

1use super::SessionState;
2use crate::{
3    GlobalState,
4    audio::SfxChannelSettings,
5    game_input::GameInput,
6    hud::{
7        AutoPressBehavior, BarNumbers, BuffPosition, ChatTab, CrosshairType, Intro, PressBehavior,
8        ScaleChange, ShortcutNumbers, XpBar,
9    },
10    render::RenderMode,
11    settings::{
12        AudioSettings, ChatSettings, ControlSettings, ControllerSettings, Fps, GameplaySettings,
13        GraphicsSettings, HudPositionSettings, InterfaceSettings, audio::AudioVolume,
14    },
15    window::{FullScreenSettings, MenuInput, Window},
16};
17use common::comp::inventory::InventorySortOrder;
18use i18n::{LanguageMetadata, LocalizationHandle};
19use std::rc::Rc;
20
21#[derive(Clone)]
22pub enum Audio {
23    AdjustMasterVolume(f32),
24    MuteMasterVolume(bool),
25    AdjustInactiveMasterVolume(f32),
26    MuteInactiveMasterVolume(bool),
27    AdjustMusicVolume(f32),
28    MuteMusicVolume(bool),
29    AdjustSfxVolume(f32),
30    MuteSfxVolume(bool),
31    AdjustInstrumentVolume(f32),
32    MuteInstrumentVolume(bool),
33    AdjustAmbienceVolume(f32),
34    MuteAmbienceVolume(bool),
35    RainAmbience(bool),
36    IndoorAmbience(bool),
37    AdjustMusicSpacing(f32),
38    ToggleCombatMusic(bool),
39    SetNumSfxChannels(SfxChannelSettings),
40    ResetAudioSettings,
41}
42#[derive(Clone)]
43pub enum Chat {
44    Transparency(f32),
45    LockChat(bool),
46    CharName(bool),
47    ShowChatTimestamp(bool),
48    ChangeChatTab(Option<usize>),
49    ChatTabUpdate(usize, ChatTab),
50    ChatTabInsert(usize, ChatTab),
51    ChatTabMove(usize, usize), //(i, j) move item from position i, and insert into position j
52    ChatTabRemove(usize),
53    ResetChatSettings,
54}
55#[derive(Clone)]
56pub enum Control {
57    // change keyboard bindings
58    ChangeBindingKeyboard(GameInput),
59    RemoveBindingKeyboard(GameInput),
60    ResetKeyBindingsKeyboard,
61
62    // change keyboard menu bindings
63    ChangeBindingKeyboardMenu(MenuInput),
64    RemoveBindingKeyboardMenu(MenuInput),
65
66    // reset all gamepad bindings
67    ResetKeyBindingsGamepad,
68
69    // change gamepad button bindings
70    ChangeBindingGamepadButton(GameInput),
71    RemoveBindingGamepadButton(GameInput),
72
73    // change gamepad menu button bindings
74    ChangeBindingGamepadMenu(MenuInput),
75    RemoveBindingGamepadMenu(MenuInput),
76
77    // change gamepad layer bindings
78    ChangeBindingGamepadLayer(GameInput),
79    RemoveBindingGamepadLayer(GameInput),
80    GameLayerMod1(bool),
81    GameLayerMod2(bool),
82
83    // reset binding mode
84    ResetBindingMode,
85}
86#[derive(Clone)]
87pub enum Gamepad {}
88#[derive(Clone)]
89pub enum Gameplay {
90    AdjustMousePan(u32),
91    AdjustMouseZoom(u32),
92    AdjustCameraClamp(u32),
93    AdjustWalkingSpeed(f32),
94
95    ToggleControllerYInvert(bool),
96    ToggleMouseYInvert(bool),
97    ToggleZoomInvert(bool),
98    ToggleSmoothPan(bool),
99
100    ChangeFreeLookBehavior(PressBehavior),
101    ChangeAutoWalkBehavior(PressBehavior),
102    ChangeWalkingSpeedBehavior(PressBehavior),
103    ChangeCameraClampBehavior(PressBehavior),
104    ChangeZoomLockBehavior(AutoPressBehavior),
105    ChangeStopAutoWalkOnInput(bool),
106    ChangeAutoCamera(bool),
107    ChangeBowZoom(bool),
108    ChangeZoomLock(bool),
109    ChangeShowAllRecipes(bool),
110
111    AdjustAimOffsetX(f32),
112    AdjustAimOffsetY(f32),
113
114    ResetGameplaySettings,
115}
116#[derive(Clone)]
117pub enum Graphics {
118    AdjustTerrainViewDistance(u32),
119    AdjustEntityViewDistance(u32),
120    AdjustLodDistance(u32),
121    AdjustLodDetail(u32),
122    AdjustSpriteRenderDistance(u32),
123    AdjustFigureLoDRenderDistance(u32),
124
125    ChangeMaxFPS(Fps),
126    ChangeMaxBackgroundFPS(Fps),
127    ChangeFOV(u16),
128
129    ChangeGamma(f32),
130    ChangeExposure(f32),
131    ChangeAmbiance(f32),
132
133    ChangeRenderMode(Box<RenderMode>),
134
135    ChangeFullscreenMode(FullScreenSettings),
136    ToggleParticlesEnabled(bool),
137    ToggleWeaponTrailsEnabled(bool),
138
139    ResetGraphicsSettings,
140    ChangeGraphicsSettings(Rc<dyn Fn(GraphicsSettings) -> GraphicsSettings>),
141}
142#[derive(Clone)]
143pub enum Interface {
144    Sct(bool),
145    SctRoundDamage(bool),
146    SctDamageAccumDuration(f32),
147    SctIncomingDamage(bool),
148    SctIncomingDamageAccumDuration(f32),
149    SpeechBubbleSelf(bool),
150    SpeechBubbleDarkMode(bool),
151    SpeechBubbleIcon(bool),
152    ToggleDebug(bool),
153    ToggleHitboxes(bool),
154    ToggleChat(bool),
155    ToggleDraggableWindows(bool),
156    ToggleTips(bool),
157
158    CrosshairTransp(f32),
159    CrosshairType(CrosshairType),
160    Intro(Intro),
161    ToggleXpBar(XpBar),
162    ToggleHealthPrefixes(bool),
163    ToggleBarNumbers(BarNumbers),
164    ToggleAlwaysShowBars(bool),
165    TogglePoiseBar(bool),
166    ToggleShortcutNumbers(ShortcutNumbers),
167    BuffPosition(BuffPosition),
168    RowBackgroundOpacity(f32),
169
170    UiScale(ScaleChange),
171    //Minimap
172    MinimapShow(bool),
173    MinimapFaceNorth(bool),
174    MinimapZoom(f64),
175    MinimapScale(f64),
176    MinimapColoredPlayerMarker(bool),
177    //Map settings
178    MapZoom(f64),
179    MapShowTopoMap(bool),
180    MapShowDifficulty(bool),
181    MapShowTowns(bool),
182    MapShowDungeons(bool),
183    MapShowCastles(bool),
184    MapShowBridges(bool),
185    MapShowGliderCourses(bool),
186    MapShowCaves(bool),
187    MapShowTrees(bool),
188    MapShowPeaks(bool),
189    MapShowBiomes(bool),
190    MapShowVoxelMap(bool),
191    MapShowQuests(bool),
192    AccumExperience(bool),
193    //Slots
194    SlotsUsePrefixes(bool),
195    SlotsPrefixSwitchPoint(u32),
196
197    ResetInterfaceSettings,
198}
199#[derive(Clone)]
200pub enum Inventory {
201    ChangeSortOrder(InventorySortOrder),
202}
203#[derive(Clone)]
204pub enum Language {
205    ChangeLanguage(Box<LanguageMetadata>),
206    ToggleSendToServer(bool),
207    ToggleEnglishFallback(bool),
208}
209#[derive(Clone)]
210pub enum Networking {
211    AdjustTerrainViewDistance(u32),
212    AdjustEntityViewDistance(u32),
213    ChangePlayerPhysicsBehavior {
214        server_authoritative: bool,
215    },
216    ToggleLossyTerrainCompression(bool),
217
218    #[cfg(feature = "discord")]
219    ToggleDiscordIntegration(bool),
220    // TODO: reset option (ensure it handles the entity/terrain vd the same as graphics reset
221    // option)
222}
223
224#[derive(Clone)]
225pub enum Accessibility {
226    ChangeRenderMode(Box<RenderMode>),
227    SetSubtitles(bool),
228}
229
230#[derive(Clone)]
231pub enum SettingsChange {
232    Audio(Audio),
233    Chat(Chat),
234    Control(Control),
235    Gamepad(Gamepad),
236    Gameplay(Gameplay),
237    Graphics(Graphics),
238    Interface(Interface),
239    Inventory(Inventory),
240    Language(Language),
241    Networking(Networking),
242    Accessibility(Accessibility),
243}
244
245macro_rules! settings_change_from {
246    ($i: ident) => {
247        impl From<$i> for SettingsChange {
248            fn from(change: $i) -> Self { SettingsChange::$i(change) }
249        }
250    };
251}
252settings_change_from!(Audio);
253settings_change_from!(Chat);
254settings_change_from!(Control);
255settings_change_from!(Gamepad);
256settings_change_from!(Gameplay);
257settings_change_from!(Graphics);
258settings_change_from!(Interface);
259settings_change_from!(Language);
260settings_change_from!(Networking);
261settings_change_from!(Accessibility);
262
263impl SettingsChange {
264    pub fn process(self, global_state: &mut GlobalState, session_state: &mut SessionState) {
265        let settings = &mut global_state.settings;
266
267        match self {
268            SettingsChange::Audio(audio_change) => {
269                fn update_volume(audio: &mut AudioVolume, volume: f32) -> f32 {
270                    audio.volume = volume;
271                    audio.get_checked()
272                }
273                fn update_muted(audio: &mut AudioVolume, muted: bool) -> f32 {
274                    audio.muted = muted;
275                    audio.get_checked()
276                }
277
278                match audio_change {
279                    Audio::AdjustMasterVolume(master_volume) => {
280                        let volume_checked =
281                            update_volume(&mut settings.audio.master_volume, master_volume);
282
283                        global_state.audio.set_master_volume(volume_checked);
284                    },
285                    Audio::MuteMasterVolume(master_muted) => {
286                        let volume_checked =
287                            update_muted(&mut settings.audio.master_volume, master_muted);
288
289                        global_state.audio.set_master_volume(volume_checked);
290                    },
291                    Audio::AdjustInactiveMasterVolume(inactive_master_volume_perc) => {
292                        settings.audio.inactive_master_volume_perc.volume =
293                            inactive_master_volume_perc;
294                    },
295                    Audio::MuteInactiveMasterVolume(inactive_master_volume_muted) => {
296                        settings.audio.inactive_master_volume_perc.muted =
297                            inactive_master_volume_muted;
298                    },
299                    Audio::AdjustMusicVolume(music_volume) => {
300                        let volume_checked =
301                            update_volume(&mut settings.audio.music_volume, music_volume);
302
303                        global_state.audio.set_music_volume(volume_checked);
304                    },
305                    Audio::MuteMusicVolume(music_muted) => {
306                        let volume_checked =
307                            update_muted(&mut settings.audio.music_volume, music_muted);
308
309                        global_state.audio.set_music_volume(volume_checked);
310                    },
311                    Audio::AdjustSfxVolume(sfx_volume) => {
312                        let volume_checked =
313                            update_volume(&mut settings.audio.sfx_volume, sfx_volume);
314
315                        global_state.audio.set_sfx_volume(volume_checked);
316                    },
317                    Audio::MuteSfxVolume(sfx_muted) => {
318                        let volume_checked =
319                            update_muted(&mut settings.audio.sfx_volume, sfx_muted);
320
321                        global_state.audio.set_sfx_volume(volume_checked);
322                    },
323                    Audio::AdjustInstrumentVolume(instrument_volume) => {
324                        global_state.audio.set_instrument_volume(instrument_volume);
325
326                        settings.audio.instrument_volume.volume = instrument_volume;
327                    },
328                    Audio::MuteInstrumentVolume(instrument_muted) => {
329                        let volume_checked =
330                            update_muted(&mut settings.audio.instrument_volume, instrument_muted);
331
332                        global_state.audio.set_instrument_volume(volume_checked);
333                    },
334                    Audio::AdjustAmbienceVolume(ambience_volume) => {
335                        global_state.audio.set_ambience_volume(ambience_volume);
336
337                        settings.audio.ambience_volume.volume = ambience_volume;
338                    },
339                    Audio::MuteAmbienceVolume(ambience_muted) => {
340                        let volume_checked =
341                            update_muted(&mut settings.audio.ambience_volume, ambience_muted);
342
343                        global_state.audio.set_ambience_volume(volume_checked);
344                    },
345                    Audio::RainAmbience(rain_ambience_enabled) => {
346                        settings.audio.rain_ambience_enabled = rain_ambience_enabled;
347                    },
348                    Audio::IndoorAmbience(indoor_ambience_enabled) => {
349                        settings.audio.indoor_ambience_enabled = indoor_ambience_enabled;
350                    },
351                    Audio::AdjustMusicSpacing(multiplier) => {
352                        global_state.audio.set_music_spacing(multiplier);
353
354                        settings.audio.music_spacing = multiplier;
355                    },
356                    Audio::ToggleCombatMusic(combat_music_enabled) => {
357                        global_state.audio.combat_music_enabled = combat_music_enabled
358                    },
359                    Audio::SetNumSfxChannels(level) => {
360                        let num = SfxChannelSettings::to_usize(&level);
361                        global_state.audio.set_num_sfx_channels(num);
362                        settings.audio.num_sfx_channels = num;
363                    },
364                    Audio::ResetAudioSettings => {
365                        let previous_sample_rate = settings.audio.sample_rate;
366                        let previous_buffer_size = settings.audio.buffer_size;
367                        settings.audio = AudioSettings::default();
368                        settings.audio.sample_rate = previous_sample_rate;
369                        settings.audio.buffer_size = previous_buffer_size;
370
371                        let audio = &mut global_state.audio;
372
373                        audio.set_master_volume(settings.audio.master_volume.get_checked());
374                        audio.set_music_volume(settings.audio.music_volume.get_checked());
375                        audio.set_ambience_volume(settings.audio.ambience_volume.get_checked());
376                        audio.set_sfx_volume(settings.audio.sfx_volume.get_checked());
377                        audio.set_instrument_volume(settings.audio.instrument_volume.get_checked());
378                        audio.set_music_spacing(settings.audio.music_spacing);
379                        audio.set_num_sfx_channels(settings.audio.num_sfx_channels);
380                    },
381                }
382            },
383            SettingsChange::Chat(chat_change) => {
384                let chat_tabs = &mut settings.chat.chat_tabs;
385                match chat_change {
386                    Chat::Transparency(chat_opacity) => {
387                        settings.chat.chat_opacity = chat_opacity;
388                    },
389                    Chat::LockChat(lock_chat) => {
390                        settings.chat.lock_chat = lock_chat;
391                    },
392                    Chat::CharName(chat_char_name) => {
393                        settings.chat.chat_character_name = chat_char_name;
394                    },
395                    Chat::ShowChatTimestamp(show_chat_timestamp) => {
396                        settings.chat.show_chat_timestamp = show_chat_timestamp;
397                    },
398                    Chat::ChangeChatTab(chat_tab_index) => {
399                        settings.chat.chat_tab_index =
400                            chat_tab_index.filter(|i| *i < chat_tabs.len());
401                    },
402                    Chat::ChatTabUpdate(i, chat_tab) => {
403                        if i < chat_tabs.len() {
404                            chat_tabs[i] = chat_tab;
405                        }
406                    },
407                    Chat::ChatTabInsert(i, chat_tab) => {
408                        if i <= chat_tabs.len() {
409                            settings.chat.chat_tabs.insert(i, chat_tab);
410                        }
411                    },
412                    Chat::ChatTabMove(i, j) => {
413                        if i < chat_tabs.len() && j < chat_tabs.len() {
414                            let chat_tab = settings.chat.chat_tabs.remove(i);
415                            settings.chat.chat_tabs.insert(j, chat_tab);
416                        }
417                    },
418                    Chat::ChatTabRemove(i) => {
419                        if i < chat_tabs.len() {
420                            settings.chat.chat_tabs.remove(i);
421                        }
422                    },
423                    Chat::ResetChatSettings => {
424                        settings.chat = ChatSettings::default();
425                    },
426                }
427            },
428            SettingsChange::Control(control_change) => match control_change {
429                // keyboard
430                Control::ChangeBindingKeyboard(game_input) => {
431                    global_state.window.set_remapping_mode(
432                        crate::window::RemappingMode::RemapKeyboard(game_input),
433                    );
434                },
435                Control::RemoveBindingKeyboard(game_input) => {
436                    settings.controls.remove_binding(game_input);
437                },
438                Control::ChangeBindingKeyboardMenu(menu_input) => {
439                    global_state.window.set_remapping_mode(
440                        crate::window::RemappingMode::RemapKeyboardMenu(menu_input),
441                    );
442                },
443                Control::RemoveBindingKeyboardMenu(menu_input) => {
444                    settings.controls.remove_menu_binding(menu_input);
445                },
446                Control::ResetKeyBindingsKeyboard => {
447                    settings.controls = ControlSettings::default();
448                },
449
450                // reset gamepad
451                Control::ResetKeyBindingsGamepad => {
452                    // Currently resets everything on the controller to the default controls, this
453                    // should be intended behavior
454                    settings.controller = ControllerSettings::default();
455                },
456
457                // change gamepad button bindings
458                Control::ChangeBindingGamepadButton(game_input) => {
459                    global_state.window.set_remapping_mode(
460                        crate::window::RemappingMode::RemapGamepadButtons(game_input),
461                    );
462                },
463                Control::RemoveBindingGamepadButton(game_input) => {
464                    settings.controller.remove_button_binding(game_input);
465                },
466
467                // change gamepad menu button bindings
468                Control::ChangeBindingGamepadMenu(menu_input) => {
469                    global_state.window.set_remapping_mode(
470                        crate::window::RemappingMode::RemapGamepadMenu(menu_input),
471                    );
472                },
473                Control::RemoveBindingGamepadMenu(menu_input) => {
474                    settings.controller.remove_menu_binding(menu_input);
475                },
476
477                // change gamepad layer bindings
478                Control::ChangeBindingGamepadLayer(game_input) => {
479                    global_state.window.set_remapping_mode(
480                        crate::window::RemappingMode::RemapGamepadLayers(game_input),
481                    );
482                },
483                Control::RemoveBindingGamepadLayer(layer_input) => {
484                    settings.controller.remove_layer_binding(layer_input);
485                },
486                Control::GameLayerMod1(glm1) => {
487                    global_state.window.gamelayer_mod1 = glm1;
488                },
489                Control::GameLayerMod2(glm2) => {
490                    global_state.window.gamelayer_mod2 = glm2;
491                },
492
493                // resets remapping mode (useful if user leaves without actually remapping)
494                Control::ResetBindingMode => {
495                    global_state.window.reset_mapping_mode();
496                },
497            },
498            SettingsChange::Gamepad(gamepad_change) => match gamepad_change {},
499            SettingsChange::Gameplay(gameplay_change) => {
500                let window = &mut global_state.window;
501                match gameplay_change {
502                    Gameplay::AdjustMousePan(sensitivity) => {
503                        window.pan_sensitivity = sensitivity;
504                        settings.gameplay.pan_sensitivity = sensitivity;
505                    },
506                    Gameplay::AdjustMouseZoom(sensitivity) => {
507                        window.zoom_sensitivity = sensitivity;
508                        settings.gameplay.zoom_sensitivity = sensitivity;
509                    },
510                    Gameplay::AdjustCameraClamp(angle) => {
511                        settings.gameplay.camera_clamp_angle = angle;
512                    },
513                    Gameplay::AdjustWalkingSpeed(speed) => {
514                        settings.gameplay.walking_speed = speed;
515                    },
516                    Gameplay::ToggleControllerYInvert(controller_y_inverted) => {
517                        settings.controller.pan_invert_y = controller_y_inverted;
518                    },
519                    Gameplay::ToggleMouseYInvert(mouse_y_inverted) => {
520                        window.mouse_y_inversion = mouse_y_inverted;
521                        settings.gameplay.mouse_y_inversion = mouse_y_inverted;
522                    },
523                    Gameplay::ToggleZoomInvert(zoom_inverted) => {
524                        window.zoom_inversion = zoom_inverted;
525                        settings.gameplay.zoom_inversion = zoom_inverted;
526                    },
527                    Gameplay::ToggleSmoothPan(smooth_pan_enabled) => {
528                        settings.gameplay.smooth_pan_enable = smooth_pan_enabled;
529                    },
530                    Gameplay::ChangeFreeLookBehavior(behavior) => {
531                        settings.gameplay.free_look_behavior = behavior;
532                    },
533                    Gameplay::ChangeAutoWalkBehavior(behavior) => {
534                        settings.gameplay.auto_walk_behavior = behavior;
535                    },
536                    Gameplay::ChangeWalkingSpeedBehavior(behavior) => {
537                        settings.gameplay.walking_speed_behavior = behavior;
538                    },
539                    Gameplay::ChangeCameraClampBehavior(behavior) => {
540                        settings.gameplay.camera_clamp_behavior = behavior;
541                    },
542                    Gameplay::ChangeZoomLockBehavior(state) => {
543                        settings.gameplay.zoom_lock_behavior = state;
544                    },
545                    Gameplay::ChangeStopAutoWalkOnInput(state) => {
546                        settings.gameplay.stop_auto_walk_on_input = state;
547                    },
548                    Gameplay::ChangeAutoCamera(state) => {
549                        settings.gameplay.auto_camera = state;
550                    },
551                    Gameplay::ChangeBowZoom(state) => {
552                        settings.gameplay.bow_zoom = state;
553                    },
554                    Gameplay::ChangeZoomLock(state) => {
555                        settings.gameplay.zoom_lock = state;
556                    },
557                    Gameplay::AdjustAimOffsetX(offset) => {
558                        settings.gameplay.aim_offset_x = offset;
559                    },
560                    Gameplay::AdjustAimOffsetY(offset) => {
561                        settings.gameplay.aim_offset_y = offset;
562                    },
563                    Gameplay::ResetGameplaySettings => {
564                        // Reset Gameplay Settings
565                        settings.gameplay = GameplaySettings::default();
566                        // Reset Controller Settings
567                        settings.controller = ControllerSettings::default();
568                        // Pan Sensitivity
569                        window.pan_sensitivity = settings.gameplay.pan_sensitivity;
570                        // Zoom Sensitivity
571                        window.zoom_sensitivity = settings.gameplay.zoom_sensitivity;
572                        // Invert Scroll Zoom
573                        window.zoom_inversion = settings.gameplay.zoom_inversion;
574                        // Invert Mouse Y Axis
575                        window.mouse_y_inversion = settings.gameplay.mouse_y_inversion;
576                    },
577                    Gameplay::ChangeShowAllRecipes(state) => {
578                        settings.gameplay.show_all_recipes = state;
579                    },
580                }
581            },
582            SettingsChange::Graphics(graphics_change) => {
583                let mut change_preset = false;
584
585                match graphics_change {
586                    Graphics::AdjustTerrainViewDistance(terrain_vd) => {
587                        adjust_terrain_view_distance(terrain_vd, settings, session_state)
588                    },
589                    Graphics::AdjustEntityViewDistance(entity_vd) => {
590                        adjust_entity_view_distance(entity_vd, settings, session_state)
591                    },
592                    Graphics::AdjustLodDistance(lod_distance) => {
593                        session_state
594                            .client
595                            .borrow_mut()
596                            .set_lod_distance(lod_distance);
597
598                        settings.graphics.lod_distance = lod_distance;
599                    },
600                    Graphics::AdjustLodDetail(lod_detail) => {
601                        session_state.scene.lod.set_detail(lod_detail);
602
603                        settings.graphics.lod_detail = lod_detail;
604                    },
605                    Graphics::AdjustSpriteRenderDistance(sprite_render_distance) => {
606                        settings.graphics.sprite_render_distance = sprite_render_distance;
607                    },
608                    Graphics::AdjustFigureLoDRenderDistance(figure_lod_render_distance) => {
609                        settings.graphics.figure_lod_render_distance = figure_lod_render_distance;
610                    },
611                    Graphics::ChangeMaxFPS(fps) => {
612                        settings.graphics.max_fps = fps;
613                    },
614                    Graphics::ChangeMaxBackgroundFPS(fps) => {
615                        settings.graphics.max_background_fps = fps;
616                    },
617                    Graphics::ChangeFOV(new_fov) => {
618                        settings.graphics.fov = new_fov;
619                        session_state.scene.camera_mut().set_fov_deg(new_fov);
620                        session_state
621                            .scene
622                            .camera_mut()
623                            .compute_dependents(&session_state.client.borrow().state().terrain());
624                    },
625                    Graphics::ChangeGamma(new_gamma) => {
626                        settings.graphics.gamma = new_gamma;
627                    },
628                    Graphics::ChangeExposure(new_exposure) => {
629                        settings.graphics.exposure = new_exposure;
630                    },
631                    Graphics::ChangeAmbiance(new_ambiance) => {
632                        settings.graphics.ambiance = new_ambiance;
633                    },
634                    Graphics::ChangeRenderMode(new_render_mode) => {
635                        change_render_mode(*new_render_mode, &mut global_state.window, settings);
636                    },
637                    Graphics::ChangeFullscreenMode(new_fullscreen_settings) => {
638                        global_state
639                            .window
640                            .set_fullscreen_mode(new_fullscreen_settings);
641                        settings.graphics.fullscreen = new_fullscreen_settings;
642                    },
643                    Graphics::ToggleParticlesEnabled(particles_enabled) => {
644                        settings.graphics.particles_enabled = particles_enabled;
645                    },
646                    Graphics::ToggleWeaponTrailsEnabled(weapon_trails_enabled) => {
647                        settings.graphics.weapon_trails_enabled = weapon_trails_enabled;
648                    },
649                    Graphics::ResetGraphicsSettings => {
650                        settings.graphics = GraphicsSettings::default();
651                        change_preset = true;
652                        // Fullscreen mode
653                        global_state
654                            .window
655                            .set_fullscreen_mode(settings.graphics.fullscreen);
656                        // Window size
657                        global_state
658                            .window
659                            .set_size(settings.graphics.window.size.into());
660                    },
661                    Graphics::ChangeGraphicsSettings(f) => {
662                        settings.graphics = f(settings.graphics.clone());
663                        change_preset = true;
664                    },
665                }
666
667                if change_preset {
668                    let graphics = &settings.graphics;
669                    // View distance
670                    client_set_view_distance(settings, session_state);
671                    // FOV
672                    session_state.scene.camera_mut().set_fov_deg(graphics.fov);
673                    session_state
674                        .scene
675                        .camera_mut()
676                        .compute_dependents(&session_state.client.borrow().state().terrain());
677                    // LoD
678                    session_state.scene.lod.set_detail(graphics.lod_detail);
679                    // LoD distance
680                    session_state
681                        .client
682                        .borrow_mut()
683                        .set_lod_distance(graphics.lod_distance);
684                    // Render mode
685                    global_state
686                        .window
687                        .renderer_mut()
688                        .set_render_mode(graphics.render_mode.clone())
689                        .unwrap();
690                }
691            },
692            SettingsChange::Interface(interface_change) => {
693                match interface_change {
694                    Interface::Sct(sct) => {
695                        settings.interface.sct = sct;
696                    },
697                    Interface::SctRoundDamage(sct_round_damage) => {
698                        settings.interface.sct_damage_rounding = sct_round_damage;
699                    },
700                    Interface::SctDamageAccumDuration(sct_dmg_accum_duration) => {
701                        settings.interface.sct_dmg_accum_duration = sct_dmg_accum_duration;
702                    },
703                    Interface::SctIncomingDamage(sct_inc_dmg) => {
704                        settings.interface.sct_inc_dmg = sct_inc_dmg;
705                    },
706                    Interface::SctIncomingDamageAccumDuration(sct_inc_dmg_accum_duration) => {
707                        settings.interface.sct_inc_dmg_accum_duration = sct_inc_dmg_accum_duration;
708                    },
709                    Interface::SpeechBubbleSelf(sbdm) => {
710                        settings.interface.speech_bubble_self = sbdm;
711                    },
712                    Interface::SpeechBubbleDarkMode(sbdm) => {
713                        settings.interface.speech_bubble_dark_mode = sbdm;
714                    },
715                    Interface::SpeechBubbleIcon(sbi) => {
716                        settings.interface.speech_bubble_icon = sbi;
717                    },
718                    Interface::ToggleDebug(toggle_debug) => {
719                        settings.interface.toggle_debug = toggle_debug;
720                    },
721                    Interface::ToggleHitboxes(toggle_hitboxes) => {
722                        settings.interface.toggle_hitboxes = toggle_hitboxes;
723                    },
724                    Interface::ToggleChat(toggle_chat) => {
725                        settings.interface.toggle_chat = toggle_chat;
726                    },
727                    Interface::ToggleDraggableWindows(toggle_draggable_windows) => {
728                        settings.interface.toggle_draggable_windows = toggle_draggable_windows;
729                    },
730                    Interface::ToggleTips(loading_tips) => {
731                        settings.interface.loading_tips = loading_tips;
732                    },
733                    Interface::CrosshairTransp(crosshair_opacity) => {
734                        settings.interface.crosshair_opacity = crosshair_opacity;
735                    },
736                    Interface::CrosshairType(crosshair_type) => {
737                        settings.interface.crosshair_type = crosshair_type;
738                    },
739                    Interface::Intro(intro_show) => {
740                        settings.interface.intro_show = intro_show;
741                    },
742                    Interface::ToggleXpBar(xp_bar) => {
743                        settings.interface.xp_bar = xp_bar;
744                    },
745                    Interface::ToggleBarNumbers(bar_numbers) => {
746                        settings.interface.bar_numbers = bar_numbers;
747                    },
748                    Interface::ToggleAlwaysShowBars(always_show_bars) => {
749                        settings.interface.always_show_bars = always_show_bars;
750                    },
751                    Interface::TogglePoiseBar(enable_poise_bar) => {
752                        settings.interface.enable_poise_bar = enable_poise_bar;
753                    },
754                    Interface::ToggleHealthPrefixes(use_health_prefixes) => {
755                        settings.interface.use_health_prefixes = use_health_prefixes;
756                    },
757                    Interface::ToggleShortcutNumbers(shortcut_numbers) => {
758                        settings.interface.shortcut_numbers = shortcut_numbers;
759                    },
760                    Interface::BuffPosition(buff_position) => {
761                        settings.interface.buff_position = buff_position;
762                    },
763                    Interface::UiScale(scale_change) => {
764                        settings.interface.ui_scale = session_state.hud.scale_change(scale_change);
765                    },
766                    Interface::MinimapShow(state) => {
767                        settings.interface.minimap_show = state;
768                    },
769                    Interface::MinimapFaceNorth(state) => {
770                        settings.interface.minimap_face_north = state;
771                    },
772                    Interface::MinimapZoom(minimap_zoom) => {
773                        settings.interface.minimap_zoom = minimap_zoom;
774                    },
775                    Interface::MinimapScale(minimap_scale) => {
776                        settings.interface.minimap_scale = minimap_scale;
777                    },
778                    Interface::MinimapColoredPlayerMarker(state) => {
779                        settings.interface.minimap_colored_player_marker = state;
780                    },
781                    Interface::MapZoom(map_zoom) => {
782                        settings.interface.map_zoom = map_zoom;
783                    },
784                    Interface::MapShowTopoMap(map_show_topo_map) => {
785                        settings.interface.map_show_topo_map = map_show_topo_map;
786                    },
787                    Interface::MapShowDifficulty(map_show_difficulty) => {
788                        settings.interface.map_show_difficulty = map_show_difficulty;
789                    },
790                    Interface::MapShowTowns(map_show_towns) => {
791                        settings.interface.map_show_towns = map_show_towns;
792                    },
793                    Interface::MapShowDungeons(map_show_dungeons) => {
794                        settings.interface.map_show_dungeons = map_show_dungeons;
795                    },
796                    Interface::MapShowCastles(map_show_castles) => {
797                        settings.interface.map_show_castles = map_show_castles;
798                    },
799                    Interface::MapShowBridges(map_show_bridges) => {
800                        settings.interface.map_show_bridges = map_show_bridges;
801                    },
802                    Interface::MapShowGliderCourses(map_show_glider_courses) => {
803                        settings.interface.map_show_glider_courses = map_show_glider_courses;
804                    },
805                    Interface::MapShowCaves(map_show_caves) => {
806                        settings.interface.map_show_caves = map_show_caves;
807                    },
808                    Interface::MapShowTrees(map_show_trees) => {
809                        settings.interface.map_show_trees = map_show_trees;
810                    },
811                    Interface::MapShowPeaks(map_show_peaks) => {
812                        settings.interface.map_show_peaks = map_show_peaks;
813                    },
814                    Interface::MapShowQuests(map_show_quests) => {
815                        settings.interface.map_show_quests = map_show_quests;
816                    },
817                    Interface::MapShowBiomes(map_show_biomes) => {
818                        settings.interface.map_show_biomes = map_show_biomes;
819                    },
820                    Interface::MapShowVoxelMap(map_show_voxel_map) => {
821                        settings.interface.map_show_voxel_map = map_show_voxel_map;
822                    },
823                    Interface::AccumExperience(accum_experience) => {
824                        settings.interface.accum_experience = accum_experience;
825                    },
826                    Interface::SlotsUsePrefixes(slots_use_prefixes) => {
827                        settings.interface.slots_use_prefixes = slots_use_prefixes;
828                        session_state.hud.set_slots_use_prefixes(slots_use_prefixes);
829                    },
830                    Interface::SlotsPrefixSwitchPoint(slots_prefix_switch_point) => {
831                        settings.interface.slots_prefix_switch_point = slots_prefix_switch_point;
832                        session_state
833                            .hud
834                            .set_slots_prefix_switch_point(slots_prefix_switch_point);
835                    },
836                    Interface::ResetInterfaceSettings => {
837                        // Reset Interface Settings
838                        let tmp = settings.interface.intro_show;
839                        settings.interface = InterfaceSettings::default();
840                        settings.interface.intro_show = tmp;
841                        // Reset Hud Position Settings
842                        settings.hud_position = HudPositionSettings::default();
843                        // Update Current Scaling Mode
844                        session_state
845                            .hud
846                            .set_scaling_mode(settings.interface.ui_scale);
847                    },
848                    Interface::RowBackgroundOpacity(opacity) => {
849                        settings.interface.row_background_opacity = opacity;
850                    },
851                }
852            },
853            SettingsChange::Inventory(inventory_change) => match inventory_change {
854                Inventory::ChangeSortOrder(sort_order) => {
855                    settings.inventory.sort_order = sort_order
856                },
857            },
858            SettingsChange::Language(language_change) => match language_change {
859                Language::ChangeLanguage(new_language) => {
860                    settings.language.selected_language = new_language.language_identifier;
861                    global_state.i18n =
862                        LocalizationHandle::load_expect(&settings.language.selected_language);
863                    global_state
864                        .i18n
865                        .set_english_fallback(settings.language.use_english_fallback);
866                    session_state.hud.update_fonts(&global_state.i18n.read());
867                },
868                Language::ToggleEnglishFallback(toggle_fallback) => {
869                    settings.language.use_english_fallback = toggle_fallback;
870                    global_state
871                        .i18n
872                        .set_english_fallback(settings.language.use_english_fallback);
873                },
874                Language::ToggleSendToServer(share) => {
875                    settings.language.send_to_server = share;
876                },
877            },
878            SettingsChange::Networking(networking_change) => match networking_change {
879                Networking::AdjustTerrainViewDistance(terrain_vd) => {
880                    adjust_terrain_view_distance(terrain_vd, settings, session_state)
881                },
882                Networking::AdjustEntityViewDistance(entity_vd) => {
883                    adjust_entity_view_distance(entity_vd, settings, session_state)
884                },
885                Networking::ChangePlayerPhysicsBehavior {
886                    server_authoritative,
887                } => {
888                    settings.networking.player_physics_behavior = server_authoritative;
889                    session_state
890                        .client
891                        .borrow_mut()
892                        .request_player_physics(server_authoritative);
893                },
894                Networking::ToggleLossyTerrainCompression(lossy_terrain_compression) => {
895                    settings.networking.lossy_terrain_compression = lossy_terrain_compression;
896                    session_state
897                        .client
898                        .borrow_mut()
899                        .request_lossy_terrain_compression(lossy_terrain_compression);
900                },
901                #[cfg(feature = "discord")]
902                Networking::ToggleDiscordIntegration(enabled) => {
903                    use crate::discord::Discord;
904
905                    settings.networking.enable_discord_integration = enabled;
906                    if enabled {
907                        global_state.discord = Discord::start(&global_state.tokio_runtime);
908
909                        #[cfg(feature = "singleplayer")]
910                        let singleplayer = global_state.singleplayer.is_running();
911                        #[cfg(not(feature = "singleplayer"))]
912                        let singleplayer = false;
913
914                        if singleplayer {
915                            global_state.discord.join_singleplayer();
916                        } else {
917                            global_state.discord.join_server(
918                                session_state.client.borrow().server_info().name.clone(),
919                            );
920                        }
921                    } else {
922                        global_state.discord.clear_activity();
923                        global_state.discord = Discord::Inactive;
924                    }
925                },
926            },
927            SettingsChange::Accessibility(accessibility_change) => match accessibility_change {
928                Accessibility::ChangeRenderMode(new_render_mode) => {
929                    change_render_mode(*new_render_mode, &mut global_state.window, settings);
930                },
931                Accessibility::SetSubtitles(enabled) => {
932                    global_state.settings.audio.subtitles = enabled;
933                    global_state.audio.set_subtitles(enabled);
934                },
935            },
936        }
937        global_state
938            .settings
939            .save_to_file_warn(&global_state.config_dir);
940    }
941}
942
943use crate::settings::Settings;
944
945pub fn change_render_mode(
946    new_render_mode: RenderMode,
947    window: &mut Window,
948    settings: &mut Settings,
949) {
950    // Do this first so if it crashes the setting isn't saved :)
951    window
952        .renderer_mut()
953        .set_render_mode(new_render_mode.clone())
954        .unwrap();
955    settings.graphics.render_mode = new_render_mode;
956}
957
958fn adjust_terrain_view_distance(
959    terrain_vd: u32,
960    settings: &mut Settings,
961    session_state: &mut SessionState,
962) {
963    settings.graphics.terrain_view_distance = terrain_vd;
964    client_set_view_distance(settings, session_state);
965}
966
967fn adjust_entity_view_distance(
968    entity_vd: u32,
969    settings: &mut Settings,
970    session_state: &mut SessionState,
971) {
972    settings.graphics.entity_view_distance = entity_vd;
973    client_set_view_distance(settings, session_state);
974}
975
976fn client_set_view_distance(settings: &Settings, session_state: &mut SessionState) {
977    let view_distances = common::ViewDistances {
978        terrain: settings.graphics.terrain_view_distance,
979        entity: settings.graphics.entity_view_distance,
980    };
981    session_state
982        .client
983        .borrow_mut()
984        .set_view_distances(view_distances);
985}