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