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