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