- docs: Cosmetics Overhaul design spec (slot-based cosmetics + built-in head/back modules) - chore: drop design doc, implementing directly from TODO.md - feat: Cosmetics module overhaul — 8 body-zone slots + 3D preview screen - feat: AlwaysVisibleHand module + KineticLyrics text scale & timing offset - feat: KillEffect Portal/Tornado procedural shader modes - feat: KineticLyrics sync — millisecond position prediction (playerctl-style) - feat: SkyShader Nebula mode, BlockHighlight shader outlines, crosshairs - feat: CombatLog module — damage dealt/taken log with DPS stats - refactor(8.5.1): regroup mixins/ 108 files into domain leaf packages (<=4 each) + regenerate mixins.json - refactor(8.5.1): split accessors into 12 groups, iris/sodium/security into leaves, fix plugin FQNs + mixins.json - refactor(8.5.1): split visuals/ 67 files into esp/nametags/hats/effects/weather/scene/camera/player/items/fx packages; lyrics->lrc; member visibility fixes; configs untouched (module ids preserved) - refactor(8.5.1): split features/gui/clickgui/settings 51 files into 18 leaf packages (core/color/slider/text/bind/...); visibility promotion only, no behavior changes - refactor(8.5.1): split features/gui/hud/draggable/impl 40 files into stats/metrics/status/combat/panels/targethud/scripted leaves; TargetHudModel records nested; visibility-only - refactor(8.5.1): split events tree (impl 32 -> 8 domains, top -> core/meta); TODO 8.5 progress notes - refactor(8.5.1): split features/gui/chat 31 files into model/render/text/input/suggestions/menu/messages leaves - fix(8.5.1 audit): delete dead unregistered ItemRenderStateLayerAccessor, drop ghost sodium FQNs from plugin, remove vestigial visuals.* star import
476 lines
18 KiB
Java
476 lines
18 KiB
Java
/*
|
|
* This file is part of the LoVisual Client distribution.
|
|
* Copyright (c) 2026 loki5512344.
|
|
*
|
|
* Licensed under the GNU General Public License v3.0.
|
|
*/
|
|
|
|
package dev.loki.lovisual.config;
|
|
|
|
import dev.loki.lovisual.config.values.*;
|
|
import dev.loki.lovisual.render.iris.IrisRuntime;
|
|
import dev.loki.lovisual.util.logging.DebugLog;
|
|
import dev.loki.lovisual.util.logging.DebugMode;
|
|
import dev.loki.lovisual.util.player.inventory.InventorySearchScope;
|
|
import dev.loki.lovisual.util.player.inventory.InventorySwap;
|
|
import dev.loki.lovisual.util.player.inventory.InventorySwapPolicy;
|
|
import dev.loki.lovisual.util.player.inventory.InventorySwapVisibility;
|
|
import net.minecraft.client.resources.language.I18n;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
public final class MainConfig implements ConfigObject, ConfigNameProvider, SettingOwner {
|
|
|
|
public static final MainConfig INSTANCE = new MainConfig();
|
|
private static final String IRIS_MSAA_REASON_KEY = "setting.main_config.msaa3d.iris_blocked";
|
|
private static final String IRIS_MSAA_REASON_FALLBACK = "Iris shaderpack pipeline is active.";
|
|
|
|
//@CFGComment("Debug logging mode: off / error_only / error_and_warnings / info / config / render_thread / stencil / serverdebug / all")
|
|
private final ModeValue debug =
|
|
new ModeValue("debug", "off", "off", "error_only", "error_and_warnings", "info", "config", "render_thread", "stencil", "serverdebug", "all");
|
|
|
|
//@CFGComment("Force PvP mode ON everywhere (dev/testing only)")
|
|
private final BooleanValue forcePvp =
|
|
new BooleanValue("forcePvp", false);
|
|
|
|
//@CFGComment("Menu background shader: off / waves / aurora")
|
|
private final ModeValue menuBg =
|
|
new ModeValue("menuBg", "off", "off", "waves", "aurora");
|
|
|
|
//@CFGComment("Use ClickGUI theme colors for menu background shader")
|
|
private final BooleanValue menuBgUseTheme =
|
|
new BooleanValue("menuBgUseTheme", false);
|
|
|
|
//@CFGComment("Show seconds in the custom main menu clock")
|
|
private final BooleanValue menuClockShowSeconds =
|
|
new BooleanValue("menuClockShowSeconds", false);
|
|
|
|
//@CFGComment("MSAA for world render: off / 2x / 4x")
|
|
private final ModeValue msaa3d =
|
|
new ModeValue("msaa3d", "off", "off", "2x", "4x");
|
|
|
|
//@CFGComment("Show ClickGUI modules hotkey hints")
|
|
private final BooleanValue clickGuiModulesHints =
|
|
new BooleanValue("clickGuiModulesHints", true);
|
|
|
|
//@CFGComment("Show ClickGUI HUD editor hotkey hints")
|
|
private final BooleanValue clickGuiHudEditorHints =
|
|
new BooleanValue("clickGuiHudEditorHints", true);
|
|
|
|
//@CFGComment("Default inventory swap safety policy: none / grim_strict / legit")
|
|
private final EnumValue<InventorySwapPolicy> inventorySwapPolicy =
|
|
new EnumValue<>("inventorySwapPolicy", InventorySwapPolicy.NONE, InventorySwapPolicy.class);
|
|
|
|
//@CFGComment("Default inventory swap search scope: hotbar / inventory / full")
|
|
private final EnumValue<InventorySearchScope> inventorySwapScope =
|
|
new EnumValue<>("inventorySwapScope", InventorySearchScope.FULL, InventorySearchScope.class);
|
|
|
|
//@CFGComment("Default inventory swap visibility: normal / silent")
|
|
private final EnumValue<InventorySwapVisibility> inventorySwapVisibility =
|
|
new EnumValue<>("inventorySwapVisibility", InventorySwapVisibility.SILENT, InventorySwapVisibility.class);
|
|
|
|
//@CFGComment("Restore the original hotbar slot after default swap requests")
|
|
private final BooleanValue inventorySwapRestore =
|
|
new BooleanValue("inventorySwapRestore", true);
|
|
|
|
//@CFGComment("Prefer hotbar matches before inventory matches for full-scope swap requests")
|
|
private final BooleanValue inventorySwapPreferHotbar =
|
|
new BooleanValue("inventorySwapPreferHotbar", true);
|
|
|
|
//@CFGComment("Extra delay before queued legit inventory swap actions")
|
|
private final NumberValue<Integer> inventorySwapLegitWaitTicks =
|
|
new NumberValue<>("inventorySwapLegitWaitTicks", 2, 0, 20);
|
|
|
|
// @CFGComment("Extra delay before queued Grim-strict inventory click/close actions")
|
|
private final NumberValue<Integer> inventorySwapStrictInventoryWaitTicks =
|
|
new NumberValue<>("inventorySwapStrictInventoryWaitTicks", 1, 0, 20);
|
|
|
|
//@CFGComment("Movement input lock duration while waiting for Grim-strict inventory actions")
|
|
private final NumberValue<Integer> inventorySwapStrictMovementLockTicks =
|
|
new NumberValue<>("inventorySwapStrictMovementLockTicks", 2, 0, 20);
|
|
|
|
//@CFGComment("Hard-disable narrator and narrator hotkey")
|
|
private final BooleanValue disableNarrator =
|
|
new BooleanValue("disableNarrator", true);
|
|
|
|
//@CFGComment("Always-on backdoor protection master switch")
|
|
private final BooleanValue backdoorProtection =
|
|
new BooleanValue("backdoorProtection", true);
|
|
|
|
//@CFGComment("Filter non-whitelisted translation keys in server-controlled sign/anvil text")
|
|
private final BooleanValue backdoorTranslationFilter =
|
|
new BooleanValue("backdoorTranslationFilter", true);
|
|
|
|
//@CFGComment("Filter non-vanilla keybind text keys in server-controlled text")
|
|
private final BooleanValue backdoorKeybindFilter =
|
|
new BooleanValue("backdoorKeybindFilter", true);
|
|
|
|
//@CFGComment("Block remote servers from redirecting resource-pack downloads into local/private network addresses")
|
|
private final BooleanValue backdoorLocalHttpGuard =
|
|
new BooleanValue("backdoorLocalHttpGuard", true);
|
|
|
|
//@CFGComment("Isolate downloaded server-pack cache by account UUID to reduce pack-cache fingerprinting")
|
|
private final BooleanValue backdoorPackCacheIsolation =
|
|
new BooleanValue("backdoorPackCacheIsolation", true);
|
|
|
|
//@CFGComment("Allow local/private HTTP requests when connected to local/integrated server")
|
|
private final BooleanValue backdoorAllowLocalHttpWhenServerLocal =
|
|
new BooleanValue("backdoorAllowLocalHttpWhenServerLocal", true);
|
|
|
|
//@CFGComment("Extra allowed translation resource-pack ids for server-controlled text")
|
|
private final SetValue backdoorAllowedTranslationPacks =
|
|
new SetValue("backdoorAllowedTranslationPacks", defaultAllowedTranslationPacks());
|
|
|
|
//@CFGComment("Extra allowed keybind ids for server-controlled text")
|
|
private final SetValue backdoorAllowedKeybinds =
|
|
new SetValue("backdoorAllowedKeybinds");
|
|
|
|
private MainConfig() {
|
|
ConfigSerializer.load(this);
|
|
applyDebugMode();
|
|
applyInventorySwapSettings();
|
|
}
|
|
|
|
public static MainConfig get() {
|
|
return INSTANCE;
|
|
}
|
|
|
|
private static Set<String> defaultAllowedTranslationPacks() {
|
|
LinkedHashSet<String> out = new LinkedHashSet<>();
|
|
out.add("vanilla");
|
|
return out;
|
|
}
|
|
|
|
@Override
|
|
public String getConfigName() {
|
|
return "mainconfig";
|
|
}
|
|
|
|
@Override
|
|
public String name() {
|
|
return "main_config";
|
|
}
|
|
|
|
// ================= DEBUG =================
|
|
|
|
@Override
|
|
public void saveConfig() {
|
|
applyDebugMode();
|
|
applyInventorySwapSettings();
|
|
ConfigSerializer.requestSave(this);
|
|
}
|
|
|
|
public DebugMode getDebugMode() {
|
|
try {
|
|
return DebugMode.valueOf(debug.get().toUpperCase());
|
|
} catch (IllegalArgumentException e) {
|
|
return DebugMode.OFF;
|
|
}
|
|
}
|
|
|
|
public void setDebugMode(DebugMode mode) {
|
|
if (mode == null) mode = DebugMode.OFF;
|
|
debug.set(mode.name().toLowerCase());
|
|
applyDebugMode();
|
|
ConfigSerializer.requestSave(this);
|
|
}
|
|
|
|
private void applyDebugMode() {
|
|
DebugLog.setMode(getDebugMode());
|
|
}
|
|
|
|
public boolean isForcePvp() {
|
|
return forcePvp.get();
|
|
}
|
|
|
|
public String getMenuBackgroundMode() {
|
|
return menuBg.get();
|
|
}
|
|
|
|
public boolean isMenuBackgroundUseTheme() {
|
|
return menuBgUseTheme.get();
|
|
}
|
|
|
|
public boolean isMenuClockShowSeconds() {
|
|
return menuClockShowSeconds.get();
|
|
}
|
|
|
|
public int getMsaa3dSamples() {
|
|
if (IrisRuntime.isShaderpackRendererActive()) return 0;
|
|
String v = msaa3d.get();
|
|
if (v == null) return 0;
|
|
if (v.equalsIgnoreCase("2x")) return 2;
|
|
if (v.equalsIgnoreCase("4x")) return 4;
|
|
return 0;
|
|
}
|
|
|
|
public boolean isClickGuiModulesHintsEnabled() {
|
|
return clickGuiModulesHints.get();
|
|
}
|
|
|
|
public boolean isClickGuiHintsEnabled() {
|
|
return clickGuiModulesHints.get();
|
|
}
|
|
|
|
public void setClickGuiModulesHintsEnabled(boolean enabled) {
|
|
clickGuiModulesHints.set(enabled);
|
|
ConfigSerializer.requestSave(this);
|
|
}
|
|
|
|
public void setClickGuiHintsEnabled(boolean enabled) {
|
|
setClickGuiModulesHintsEnabled(enabled);
|
|
}
|
|
|
|
public boolean isClickGuiHudEditorHintsEnabled() {
|
|
return clickGuiHudEditorHints.get();
|
|
}
|
|
|
|
public void setClickGuiHudEditorHintsEnabled(boolean enabled) {
|
|
clickGuiHudEditorHints.set(enabled);
|
|
ConfigSerializer.requestSave(this);
|
|
}
|
|
|
|
public InventorySwapPolicy getInventorySwapPolicy() {
|
|
return inventorySwapPolicy.get();
|
|
}
|
|
|
|
public void setInventorySwapPolicy(InventorySwapPolicy policy) {
|
|
inventorySwapPolicy.set(policy != null ? policy : InventorySwapPolicy.NONE);
|
|
saveAndApplyInventorySwapSettings();
|
|
}
|
|
|
|
public InventorySearchScope getInventorySwapScope() {
|
|
return inventorySwapScope.get();
|
|
}
|
|
|
|
public void setInventorySwapScope(InventorySearchScope scope) {
|
|
inventorySwapScope.set(scope != null ? scope : InventorySearchScope.FULL);
|
|
saveAndApplyInventorySwapSettings();
|
|
}
|
|
|
|
public InventorySwapVisibility getInventorySwapVisibility() {
|
|
return inventorySwapVisibility.get();
|
|
}
|
|
|
|
public void setInventorySwapVisibility(InventorySwapVisibility visibility) {
|
|
inventorySwapVisibility.set(visibility != null ? visibility : InventorySwapVisibility.SILENT);
|
|
saveAndApplyInventorySwapSettings();
|
|
}
|
|
|
|
public boolean isInventorySwapRestore() {
|
|
return inventorySwapRestore.get();
|
|
}
|
|
|
|
public void setInventorySwapRestore(boolean restore) {
|
|
inventorySwapRestore.set(restore);
|
|
saveAndApplyInventorySwapSettings();
|
|
}
|
|
|
|
public boolean isInventorySwapPreferHotbar() {
|
|
return inventorySwapPreferHotbar.get();
|
|
}
|
|
|
|
public void setInventorySwapPreferHotbar(boolean preferHotbar) {
|
|
inventorySwapPreferHotbar.set(preferHotbar);
|
|
saveAndApplyInventorySwapSettings();
|
|
}
|
|
|
|
public int getInventorySwapLegitWaitTicks() {
|
|
return inventorySwapLegitWaitTicks.get();
|
|
}
|
|
|
|
public void setInventorySwapLegitWaitTicks(int ticks) {
|
|
inventorySwapLegitWaitTicks.fromJson(ticks);
|
|
saveAndApplyInventorySwapSettings();
|
|
}
|
|
|
|
public int getInventorySwapStrictInventoryWaitTicks() {
|
|
return inventorySwapStrictInventoryWaitTicks.get();
|
|
}
|
|
|
|
public void setInventorySwapStrictInventoryWaitTicks(int ticks) {
|
|
inventorySwapStrictInventoryWaitTicks.fromJson(ticks);
|
|
saveAndApplyInventorySwapSettings();
|
|
}
|
|
|
|
public int getInventorySwapStrictMovementLockTicks() {
|
|
return inventorySwapStrictMovementLockTicks.get();
|
|
}
|
|
|
|
public void setInventorySwapStrictMovementLockTicks(int ticks) {
|
|
inventorySwapStrictMovementLockTicks.fromJson(ticks);
|
|
saveAndApplyInventorySwapSettings();
|
|
}
|
|
|
|
public EnumValue<InventorySwapPolicy> inventorySwapPolicyValue() {
|
|
return inventorySwapPolicy;
|
|
}
|
|
|
|
public EnumValue<InventorySearchScope> inventorySwapScopeValue() {
|
|
return inventorySwapScope;
|
|
}
|
|
|
|
public EnumValue<InventorySwapVisibility> inventorySwapVisibilityValue() {
|
|
return inventorySwapVisibility;
|
|
}
|
|
|
|
public BooleanValue inventorySwapRestoreValue() {
|
|
return inventorySwapRestore;
|
|
}
|
|
|
|
public BooleanValue inventorySwapPreferHotbarValue() {
|
|
return inventorySwapPreferHotbar;
|
|
}
|
|
|
|
public NumberValue<Integer> inventorySwapLegitWaitTicksValue() {
|
|
return inventorySwapLegitWaitTicks;
|
|
}
|
|
|
|
public NumberValue<Integer> inventorySwapStrictInventoryWaitTicksValue() {
|
|
return inventorySwapStrictInventoryWaitTicks;
|
|
}
|
|
|
|
public NumberValue<Integer> inventorySwapStrictMovementLockTicksValue() {
|
|
return inventorySwapStrictMovementLockTicks;
|
|
}
|
|
|
|
public List<SettingDef> getImageSettingDefs() {
|
|
List<SettingDef> list = new ArrayList<>();
|
|
list.add(SettingDef.mode(msaa3d)
|
|
.unavailableWhen(IrisRuntime::isShaderpackRendererActive, MainConfig::irisMsaaReason));
|
|
list.add(SettingDef.mode(menuBg));
|
|
list.add(SettingDef.bool(menuClockShowSeconds));
|
|
list.add(SettingDef.bool(menuBgUseTheme));
|
|
return list;
|
|
}
|
|
|
|
private static String irisMsaaReason() {
|
|
String translated = I18n.get(IRIS_MSAA_REASON_KEY);
|
|
return IRIS_MSAA_REASON_KEY.equals(translated) ? IRIS_MSAA_REASON_FALLBACK : translated;
|
|
}
|
|
|
|
public List<SettingDef> getMiscellaneousSettingDefs() {
|
|
List<SettingDef> list = new ArrayList<>();
|
|
list.add(SettingDef.mode(debug));
|
|
list.add(SettingDef.bool(forcePvp));
|
|
list.add(SettingDef.bool(disableNarrator));
|
|
return list;
|
|
}
|
|
|
|
public List<SettingDef> getSecuritySettingDefs() {
|
|
List<SettingDef> list = new ArrayList<>();
|
|
list.add(SettingDef.bool(backdoorProtection));
|
|
list.add(SettingDef.bool(backdoorTranslationFilter).visibleWhen(backdoorProtection::get));
|
|
list.add(SettingDef.bool(backdoorKeybindFilter).visibleWhen(backdoorProtection::get));
|
|
list.add(SettingDef.bool(backdoorLocalHttpGuard).visibleWhen(backdoorProtection::get));
|
|
list.add(SettingDef.bool(backdoorPackCacheIsolation).visibleWhen(backdoorProtection::get));
|
|
list.add(SettingDef.bool(backdoorAllowLocalHttpWhenServerLocal).visibleWhen(backdoorProtection::get));
|
|
list.add(SettingDef.textList(backdoorAllowedTranslationPacks)
|
|
.visibleWhen(() -> backdoorProtection.get() && backdoorTranslationFilter.get()));
|
|
list.add(SettingDef.textList(backdoorAllowedKeybinds)
|
|
.visibleWhen(() -> backdoorProtection.get() && backdoorKeybindFilter.get()));
|
|
return list;
|
|
}
|
|
|
|
public List<SettingDef> getUtilitySettingDefs() {
|
|
List<SettingDef> list = new ArrayList<>();
|
|
list.add(SettingDef.mode(inventorySwapPolicy).common("inventory.swap_policy"));
|
|
list.add(SettingDef.mode(inventorySwapScope).common("inventory.search_scope"));
|
|
list.add(SettingDef.mode(inventorySwapVisibility).common("inventory.swap_visibility"));
|
|
list.add(SettingDef.bool(inventorySwapRestore).common("inventory.restore_item"));
|
|
list.add(SettingDef.bool(inventorySwapPreferHotbar).common("inventory.prefer_hotbar"));
|
|
list.add(SettingDef.number(inventorySwapLegitWaitTicks).common("inventory.legit_wait_ticks"));
|
|
list.add(SettingDef.number(inventorySwapStrictInventoryWaitTicks).common("inventory.strict_inventory_wait_ticks"));
|
|
list.add(SettingDef.number(inventorySwapStrictMovementLockTicks).common("inventory.strict_movement_lock_ticks"));
|
|
return list;
|
|
}
|
|
|
|
public boolean isNarratorDisabled() {
|
|
return disableNarrator.get();
|
|
}
|
|
|
|
public boolean isBackdoorProtectionEnabled() {
|
|
return backdoorProtection.get();
|
|
}
|
|
|
|
public boolean isBackdoorTranslationFilterEnabled() {
|
|
return backdoorProtection.get() && backdoorTranslationFilter.get();
|
|
}
|
|
|
|
public boolean isBackdoorKeybindFilterEnabled() {
|
|
return backdoorProtection.get() && backdoorKeybindFilter.get();
|
|
}
|
|
|
|
public boolean isBackdoorLocalHttpGuardEnabled() {
|
|
return backdoorProtection.get() && backdoorLocalHttpGuard.get();
|
|
}
|
|
|
|
public boolean isBackdoorPackCacheIsolationEnabled() {
|
|
return backdoorProtection.get() && backdoorPackCacheIsolation.get();
|
|
}
|
|
|
|
public boolean isBackdoorAllowLocalHttpWhenServerLocal() {
|
|
return backdoorAllowLocalHttpWhenServerLocal.get();
|
|
}
|
|
|
|
public Set<String> getBackdoorAllowedTranslationPacks() {
|
|
return new LinkedHashSet<>(backdoorAllowedTranslationPacks.get());
|
|
}
|
|
|
|
// ================= CONFIG =================
|
|
|
|
public Set<String> getBackdoorAllowedKeybinds() {
|
|
return new LinkedHashSet<>(backdoorAllowedKeybinds.get());
|
|
}
|
|
|
|
@Override
|
|
public List<ConfigValue<?>> getConfigValues() {
|
|
List<ConfigValue<?>> list = new ArrayList<>();
|
|
list.add(debug);
|
|
list.add(forcePvp);
|
|
list.add(menuBg);
|
|
list.add(menuClockShowSeconds);
|
|
list.add(menuBgUseTheme);
|
|
list.add(msaa3d);
|
|
list.add(clickGuiModulesHints);
|
|
list.add(clickGuiHudEditorHints);
|
|
list.add(inventorySwapPolicy);
|
|
list.add(inventorySwapScope);
|
|
list.add(inventorySwapVisibility);
|
|
list.add(inventorySwapRestore);
|
|
list.add(inventorySwapPreferHotbar);
|
|
list.add(inventorySwapLegitWaitTicks);
|
|
list.add(inventorySwapStrictInventoryWaitTicks);
|
|
list.add(inventorySwapStrictMovementLockTicks);
|
|
list.add(disableNarrator);
|
|
list.add(backdoorProtection);
|
|
list.add(backdoorTranslationFilter);
|
|
list.add(backdoorKeybindFilter);
|
|
list.add(backdoorLocalHttpGuard);
|
|
list.add(backdoorPackCacheIsolation);
|
|
list.add(backdoorAllowLocalHttpWhenServerLocal);
|
|
list.add(backdoorAllowedTranslationPacks);
|
|
list.add(backdoorAllowedKeybinds);
|
|
return list;
|
|
}
|
|
|
|
private void saveAndApplyInventorySwapSettings() {
|
|
applyInventorySwapSettings();
|
|
ConfigSerializer.requestSave(this);
|
|
}
|
|
|
|
private void applyInventorySwapSettings() {
|
|
InventorySwap swap = InventorySwap.INSTANCE;
|
|
swap.setDefaultPolicy(inventorySwapPolicy.get());
|
|
swap.setDefaultScope(inventorySwapScope.get());
|
|
swap.setDefaultVisibility(inventorySwapVisibility.get());
|
|
swap.setRestoreByDefault(inventorySwapRestore.get());
|
|
swap.setPreferHotbar(inventorySwapPreferHotbar.get());
|
|
swap.setLegitWaitTicks(inventorySwapLegitWaitTicks.get());
|
|
swap.setStrictInventoryWaitTicks(inventorySwapStrictInventoryWaitTicks.get());
|
|
swap.setStrictMovementLockTicks(inventorySwapStrictMovementLockTicks.get());
|
|
}
|
|
}
|