Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import net.caffeinemc.mods.sodium.client.config.structure.IntegerOption;
import net.caffeinemc.mods.sodium.client.config.structure.Option;
import net.caffeinemc.mods.sodium.client.config.structure.OptionPage;
import net.caffeinemc.mods.sodium.client.config.structure.Option;
import net.caffeinemc.mods.sodium.client.config.structure.StatefulOption;
import net.caffeinemc.mods.sodium.client.config.structure.Page;
import net.caffeinemc.mods.sodium.client.data.fingerprint.HashedFingerprint;
import net.caffeinemc.mods.sodium.client.gui.options.control.ControlElement;
Expand Down Expand Up @@ -48,6 +50,7 @@ public class VideoSettingsScreen extends Screen implements ScreenPromptable, Scr
private OptionListWidget optionList;

private KeyBoundButtonWidget applyButton, closeButton, undoButton;
private KeyBoundButtonWidget performancePresetButton, balancedPresetButton;
private List<KeyBoundButtonWidget> shortcutButtons = List.of();
private DonationButtonWidget donateButton;

Expand Down Expand Up @@ -183,7 +186,29 @@ private void rebuild() {
int topBarHeight = Layout.BUTTON_SHORT;
this.searchWidget = new SearchWidget(this::onSearchResults, new Dim2i(x, y, w, topBarHeight));

int topBarClear = topBarHeight + ifInsetY(Layout.INNER_MARGIN);
int presetButtonW = Layout.BUTTON_LONG;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced adding more buttons to the button stack is a good idea, in particular not for presets since there can be potentially arbitrarily many presets if we allow such customization in the API.

int presetButtonH = Layout.BUTTON_SHORT;
int presetY = y + topBarHeight + Layout.INNER_MARGIN;
this.performancePresetButton = new KeyBoundButtonWidget(
new Dim2i(x, presetY, presetButtonW, presetButtonH),
Component.translatable("sodium.options.buttons.max_performance"),
this::applyPerformancePreset,
true,
false,
GLFW.GLFW_KEY_M
);
this.balancedPresetButton = new KeyBoundButtonWidget(
new Dim2i(x + presetButtonW + Layout.INNER_MARGIN, presetY, presetButtonW, presetButtonH),
Component.translatable("sodium.options.buttons.balanced"),
this::applyBalancedPreset,
true,
false,
GLFW.GLFW_KEY_B
);
this.addRenderableWidget(this.performancePresetButton);
this.addRenderableWidget(this.balancedPresetButton);

int topBarClear = topBarHeight + Layout.BUTTON_SHORT + ifInsetY(Layout.INNER_MARGIN);
this.pageList = new PageListWidget(new Dim2i(x, y + topBarClear, Layout.PAGE_LIST_WIDTH, h - topBarClear), this);
this.addRenderableWidget(this.pageList);

Expand All @@ -207,14 +232,14 @@ private void rebuild() {

var optionListDim = new Dim2i(
this.pageList.getLimitX(),
y + topBarHeight + Layout.INNER_MARGIN,
y + topBarClear,
Layout.OPTION_WIDTH + Layout.OPTION_LIST_SCROLLBAR_OFFSET + Layout.SCROLLBAR_WIDTH,
h - topBarHeight - (reserveBottomSpace ? (Layout.INNER_MARGIN * 2 + Layout.BUTTON_SHORT) : Layout.INNER_MARGIN) - ifNotInsetY(Layout.INNER_MARGIN)
h - topBarClear - (reserveBottomSpace ? (Layout.INNER_MARGIN * 2 + Layout.BUTTON_SHORT) : Layout.INNER_MARGIN) - ifNotInsetY(Layout.INNER_MARGIN)
);
this.optionList = new OptionListWidget(this, optionListDim, this::onSectionFocused);
this.addRenderableWidget(this.optionList);

var tooltipAreaY = y + topBarHeight + ifInsetY(Layout.TOOLTIP_OUTER_MARGIN);
var tooltipAreaY = y + topBarClear + ifInsetY(Layout.TOOLTIP_OUTER_MARGIN);
this.tooltip.setTooltipArea(
new Dim2i(
this.optionList.getLimitX(),
Expand Down Expand Up @@ -243,7 +268,7 @@ private void rebuildActionButtons(boolean stackVertically) {
this.addRenderableWidget(this.closeButton);
this.addRenderableWidget(this.undoButton);
this.addRenderableWidget(this.applyButton);
this.shortcutButtons = List.of(this.closeButton, this.applyButton, this.undoButton);
this.shortcutButtons = List.of(this.closeButton, this.applyButton, this.undoButton, this.performancePresetButton, this.balancedPresetButton);
}

private void updateScreenDimensions() {
Expand Down Expand Up @@ -322,6 +347,57 @@ private void hideDonationButton() {
this.updateSearchWidgetWidth();
}

private void applyPerformancePreset() {
this.applyPresetValues(true);
}

private void applyBalancedPreset() {
this.applyPresetValues(false);
}

@SuppressWarnings("unchecked")
private static <V> void setOptionValue(Identifier id, V value) {
Option option = ConfigManager.CONFIG.getOption(id);
if (option instanceof StatefulOption<?> statefulOption) {
((StatefulOption<V>) statefulOption).modifyValue(value);
}
}

private void applyPresetValues(boolean maxPerformance) {

@douira douira Apr 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not in favor of this way of doing the preset values since it requires us to manually extract preset values from vanilla, and requires a code change any time new presets are added or they change any of the values. If we were to hardcode preset values, we'd do so on the options themselves and not in one giant method like this. This ties into the fact that we want to eventually work on a system that automatically extracts the default values for options from vanilla instead of hardcoding them into our option builder.

setOptionValue(Identifier.parse("sodium:general.render_distance"), maxPerformance ? 8 : 12);
setOptionValue(Identifier.parse("sodium:general.simulation_distance"), maxPerformance ? 8 : 12);
setOptionValue(Identifier.parse("sodium:general.framerate_limit"), maxPerformance ? 60 : 120);
setOptionValue(Identifier.parse("sodium:quality.clouds"), maxPerformance ? Options.CloudStatus.OFF : Options.CloudStatus.FAST);
setOptionValue(Identifier.parse("sodium:quality.render_cloud_distance"), maxPerformance ? 2 : 64);
setOptionValue(Identifier.parse("sodium:quality.weather"), maxPerformance ? 3 : 6);
setOptionValue(Identifier.parse("sodium:quality.leaves"), !maxPerformance);
setOptionValue(Identifier.parse("sodium:quality.particles"), maxPerformance ? Options.ParticleStatus.MINIMAL : Options.ParticleStatus.DECREASED);
setOptionValue(Identifier.parse("sodium:quality.ao"), !maxPerformance);
setOptionValue(Identifier.parse("sodium:quality.biome_blend"), maxPerformance ? 0 : 2);
setOptionValue(Identifier.parse("sodium:quality.entity_distance"), maxPerformance ? 50 : 100);
setOptionValue(Identifier.parse("sodium:quality.entity_shadows"), !maxPerformance);
setOptionValue(Identifier.parse("sodium:quality.vignette"), !maxPerformance);
setOptionValue(Identifier.parse("sodium:quality.fade_time"), maxPerformance ? 0 : 750);
setOptionValue(Identifier.parse("sodium:quality.mipmap_levels"), maxPerformance ? 0 : 2);
setOptionValue(Identifier.parse("sodium:quality.filtering_mode"), maxPerformance ? Options.TextureFilteringMethod.BILINEAR : Options.TextureFilteringMethod.RGSS);
setOptionValue(Identifier.parse("sodium:quality.anisotropy_bit"), 0);
setOptionValue(Identifier.parse("sodium:quality.hidden_fluid_culling"), true);
setOptionValue(Identifier.parse("sodium:quality.improved_fluid_shaping"), false);
setOptionValue(Identifier.parse("sodium:performance.chunk_update_threads"), maxPerformance ? Math.max(1, Runtime.getRuntime().availableProcessors() - 1) : 0);
setOptionValue(Identifier.parse("sodium:performance.always_defer_chunk_updates"), maxPerformance ? DeferMode.ALWAYS : DeferMode.ONE_FRAME);
setOptionValue(Identifier.parse("sodium:performance.use_block_face_culling"), true);
setOptionValue(Identifier.parse("sodium:performance.use_fog_occlusion"), true);
setOptionValue(Identifier.parse("sodium:performance.use_entity_culling"), true);
setOptionValue(Identifier.parse("sodium:performance.animate_only_visible_textures"), true);
setOptionValue(Identifier.parse("sodium:performance.use_no_error_context"), true);
setOptionValue(Identifier.parse("sodium:performance.inactivity_fps_limit"), Options.InactivityFpsLimit.AFK);
setOptionValue(Identifier.parse("sodium:performance.quad_splitting"), maxPerformance ? net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.QuadSplittingMode.OFF : net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.QuadSplittingMode.SAFE);
setOptionValue(Identifier.parse("sodium:advanced.use_persistent_mapping"), true);
setOptionValue(Identifier.parse("sodium:advanced.cpu_render_ahead_limit"), maxPerformance ? 0 : 1);

ConfigManager.CONFIG.applyAllOptions();
}

@Override
public void extractRenderState(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) {
this.updateControls(mouseX, mouseY);
Expand Down
2 changes: 2 additions & 0 deletions common/src/main/resources/assets/sodium/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
"sodium.options.use_no_error_context.tooltip": "When enabled, the OpenGL context will be created with error checking disabled. This slightly improves rendering performance, but it can make debugging sudden unexplained crashes much harder.",
"sodium.options.buttons.undo": "Undo",
"sodium.options.buttons.apply": "Apply",
"sodium.options.buttons.max_performance": "Max performance",
"sodium.options.buttons.balanced": "Balanced",
"sodium.options.buttons.donate": "Buy us a coffee!",
"sodium.console.game_restart": "The game must be restarted to apply one or more video settings!",
"sodium.console.broken_nvidia_driver": "Your NVIDIA graphics drivers are out of date!\n * This will cause severe performance issues and crashes when Sodium is installed.\n * Please update your graphics drivers to the latest version (version 536.23 or newer.)",
Expand Down