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