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