diff --git a/src/main/java/com/tiedup/remake/client/ModKeybindings.java b/src/main/java/com/tiedup/remake/client/ModKeybindings.java
index 11e60d5..751405c 100644
--- a/src/main/java/com/tiedup/remake/client/ModKeybindings.java
+++ b/src/main/java/com/tiedup/remake/client/ModKeybindings.java
@@ -3,7 +3,7 @@ package com.tiedup.remake.client;
import com.mojang.blaze3d.platform.InputConstants;
import com.tiedup.remake.client.gui.screens.AdjustmentScreen;
import com.tiedup.remake.client.gui.screens.UnifiedBondageScreen;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.ILockable;
import com.tiedup.remake.v2.bondage.CollarHelper;
@@ -315,7 +315,7 @@ public class ModKeybindings {
// Check if player has bind equipped
if (state.isTiedUp()) {
// Has bind - struggle against it
- if (ModConfig.SERVER.struggleMiniGameEnabled.get()) {
+ if (SettingsAccessor.isStruggleMiniGameEnabled()) {
// New: Start struggle mini-game
ModNetwork.sendToServer(
new PacketV2StruggleStart(BodyRegionV2.ARMS)
diff --git a/src/main/java/com/tiedup/remake/core/SettingsAccessor.java b/src/main/java/com/tiedup/remake/core/SettingsAccessor.java
index 089c14d..047c737 100644
--- a/src/main/java/com/tiedup/remake/core/SettingsAccessor.java
+++ b/src/main/java/com/tiedup/remake/core/SettingsAccessor.java
@@ -9,16 +9,32 @@ import net.minecraftforge.common.ForgeConfigSpec;
import org.jetbrains.annotations.Nullable;
/**
- * Centralized accessor for mod settings that resolves the GameRules vs ModConfig priority.
+ * Centralized accessor for all TiedUp! mod settings.
*
- * Priority order:
- * 1. GameRules (if a world is loaded and rules are available) - these are per-world overrides
- * 2. ModConfig (if config is loaded) - these are the user's intended defaults
- * 3. Hardcoded fallback - safe defaults if neither system is available yet
+ *
Three-Tier Resolution
+ *
+ * - Tier 1 — GameRules (per-world, overridable via {@code /gamerule}): ~24 settings.
+ * These take priority when a world is loaded and {@code GameRules} is available.
+ * - Tier 2 — ModConfig (server {@code .toml} defaults): ~78+ settings.
+ * Read via {@link #safeGet} to tolerate early access before the config spec is loaded.
+ * - Tier 3 — Hardcoded fallbacks: safe defaults returned when neither Tier 1
+ * nor Tier 2 is available (e.g., during mod construction).
+ *
*
- * This class exists because GameRules defaults (set at registration time before config loads)
- * can diverge from ModConfig defaults. Without this accessor, ModConfig spawn rate values
- * were completely ignored (BUG-001).
+ * Rule
+ * All game code should read settings through this class, never directly from
+ * {@link ModConfig} or {@link ModGameRules}. This ensures a single choke-point
+ * for defaults, null-safety, and future GameRule promotion of any setting.
+ *
+ * Settings that only exist in ModConfig (no GameRule equivalent) use parameterless
+ * getters. Settings that have a GameRule override accept a {@code @Nullable GameRules}
+ * parameter.
+ *
+ * Client-side config ({@code ModConfig.CLIENT.*}) is excluded — it is read-only
+ * and single-source, so no accessor is needed.
+ *
+ * @see ModConfig.ServerConfig
+ * @see ModGameRules
*/
public class SettingsAccessor {
@@ -531,6 +547,377 @@ public class SettingsAccessor {
);
}
+ // ==================== Minigame Toggles ====================
+
+ /**
+ * Check if the struggle mini-game is enabled.
+ * When disabled, struggle actions are rejected or use instant logic.
+ *
+ * @return true if the struggle mini-game is enabled (default true)
+ */
+ public static boolean isStruggleMiniGameEnabled() {
+ return safeGet(() -> ModConfig.SERVER.struggleMiniGameEnabled.get(), true);
+ }
+
+ /**
+ * Check if the lockpick mini-game is enabled.
+ * When disabled, lockpick actions are rejected or use instant logic.
+ *
+ * @return true if the lockpick mini-game is enabled (default true)
+ */
+ public static boolean isLockpickMiniGameEnabled() {
+ return safeGet(() -> ModConfig.SERVER.lockpickMiniGameEnabled.get(), true);
+ }
+
+ // ==================== Combat & Weapons ====================
+
+ /**
+ * Get the whip damage amount.
+ *
+ * @return Damage as float (default 2.0)
+ */
+ public static float getWhipDamage() {
+ return safeGet(() -> ModConfig.SERVER.whipDamage.get(), 2.0).floatValue();
+ }
+
+ /**
+ * Get the resistance decrease per whip hit.
+ *
+ * @return Resistance decrease amount (default 15)
+ */
+ public static int getWhipResistanceDecrease() {
+ return safeGet(() -> ModConfig.SERVER.whipResistanceDecrease.get(), 15);
+ }
+
+ /**
+ * Get the taser stun effect duration in ticks.
+ *
+ * @return Duration in ticks (default 100 = 5 seconds)
+ */
+ public static int getTaserStunDuration() {
+ return safeGet(() -> ModConfig.SERVER.taserStunDuration.get(), 100);
+ }
+
+ /**
+ * Get the swim speed multiplier applied to tied players.
+ *
+ * @return Multiplier (0.0-1.0, default 0.5)
+ */
+ public static double getTiedSwimSpeedMultiplier() {
+ return safeGet(() -> ModConfig.SERVER.tiedSwimSpeedMultiplier.get(), 0.5);
+ }
+
+ // ==================== Lockpick ====================
+
+ /**
+ * Get the lockpick success chance (0-100).
+ *
+ * @return Success chance percentage (default 25)
+ */
+ public static int getLockpickSuccessChance() {
+ return safeGet(() -> ModConfig.SERVER.lockpickSuccessChance.get(), 25);
+ }
+
+ /**
+ * Get the lockpick jam chance (0.0-100.0).
+ *
+ * @return Jam chance percentage as double (default 2.5)
+ */
+ public static double getLockpickJamChance() {
+ return safeGet(() -> ModConfig.SERVER.lockpickJamChance.get(), 2.5);
+ }
+
+ /**
+ * Get the lockpick break chance (0-100).
+ *
+ * @return Break chance percentage (default 15)
+ */
+ public static int getLockpickBreakChance() {
+ return safeGet(() -> ModConfig.SERVER.lockpickBreakChance.get(), 15);
+ }
+
+ // ==================== Rag ====================
+
+ /**
+ * Get the default rag wet time in ticks.
+ *
+ * @return Wet time in ticks (default 6000 = 5 minutes)
+ */
+ public static int getRagWetTime() {
+ return safeGet(() -> ModConfig.SERVER.ragWetTime.get(), 6000);
+ }
+
+ // ==================== Arrows ====================
+
+ /**
+ * Get the rope arrow bind chance for non-archer shooters (0-100).
+ *
+ * @return Bind chance percentage (default 50)
+ */
+ public static int getRopeArrowBindChance() {
+ return safeGet(() -> ModConfig.SERVER.ropeArrowBindChance.get(), 50);
+ }
+
+ /**
+ * Get the archer's base bind chance per arrow hit (0-100).
+ *
+ * @return Base bind chance percentage (default 10)
+ */
+ public static int getArcherArrowBindChanceBase() {
+ return safeGet(() -> ModConfig.SERVER.archerArrowBindChanceBase.get(), 10);
+ }
+
+ /**
+ * Get the additional bind chance per previous hit for archers (0-100).
+ *
+ * @return Per-hit chance increase percentage (default 10)
+ */
+ public static int getArcherArrowBindChancePerHit() {
+ return safeGet(() -> ModConfig.SERVER.archerArrowBindChancePerHit.get(), 10);
+ }
+
+ // ==================== Kidnap Bomb ====================
+
+ /**
+ * Get the kidnap bomb fuse duration in ticks.
+ *
+ * @return Fuse in ticks (default 80 = 4 seconds)
+ */
+ public static int getKidnapBombFuse() {
+ return safeGet(() -> ModConfig.SERVER.kidnapBombFuse.get(), 80);
+ }
+
+ // ==================== Merchant ====================
+
+ /**
+ * Get the merchant hostile cooldown duration in ticks.
+ *
+ * @return Duration in ticks (default 6000 = 5 minutes)
+ */
+ public static int getMerchantHostileDuration() {
+ return safeGet(() -> ModConfig.SERVER.merchantHostileDuration.get(), 6000);
+ }
+
+ /**
+ * Get the minimum number of random trades a merchant generates.
+ *
+ * @return Minimum trade count (default 8)
+ */
+ public static int getMerchantMinTrades() {
+ return safeGet(() -> ModConfig.SERVER.merchantMinTrades.get(), 8);
+ }
+
+ /**
+ * Get the maximum number of random trades a merchant generates.
+ *
+ * @return Maximum trade count (default 12)
+ */
+ public static int getMerchantMaxTrades() {
+ return safeGet(() -> ModConfig.SERVER.merchantMaxTrades.get(), 12);
+ }
+
+ /**
+ * Get the tier 1 minimum price in nuggets.
+ * @return Min price (default 9)
+ */
+ public static int getTier1PriceMin() {
+ return safeGet(() -> ModConfig.SERVER.tier1PriceMin.get(), 9);
+ }
+
+ /**
+ * Get the tier 1 maximum price in nuggets.
+ * @return Max price (default 18)
+ */
+ public static int getTier1PriceMax() {
+ return safeGet(() -> ModConfig.SERVER.tier1PriceMax.get(), 18);
+ }
+
+ /**
+ * Get the tier 2 minimum price in nuggets.
+ * @return Min price (default 27)
+ */
+ public static int getTier2PriceMin() {
+ return safeGet(() -> ModConfig.SERVER.tier2PriceMin.get(), 27);
+ }
+
+ /**
+ * Get the tier 2 maximum price in nuggets.
+ * @return Max price (default 45)
+ */
+ public static int getTier2PriceMax() {
+ return safeGet(() -> ModConfig.SERVER.tier2PriceMax.get(), 45);
+ }
+
+ /**
+ * Get the tier 3 minimum price in nuggets.
+ * @return Min price (default 54)
+ */
+ public static int getTier3PriceMin() {
+ return safeGet(() -> ModConfig.SERVER.tier3PriceMin.get(), 54);
+ }
+
+ /**
+ * Get the tier 3 maximum price in nuggets.
+ * @return Max price (default 90)
+ */
+ public static int getTier3PriceMax() {
+ return safeGet(() -> ModConfig.SERVER.tier3PriceMax.get(), 90);
+ }
+
+ /**
+ * Get the tier 4 minimum price in nuggets.
+ * @return Min price (default 90)
+ */
+ public static int getTier4PriceMin() {
+ return safeGet(() -> ModConfig.SERVER.tier4PriceMin.get(), 90);
+ }
+
+ /**
+ * Get the tier 4 maximum price in nuggets.
+ * @return Max price (default 180)
+ */
+ public static int getTier4PriceMax() {
+ return safeGet(() -> ModConfig.SERVER.tier4PriceMax.get(), 180);
+ }
+
+ // ==================== Dialogue ====================
+
+ /**
+ * Get the dialogue broadcast radius in blocks.
+ *
+ * @return Radius in blocks (default 20)
+ */
+ public static int getDialogueRadius() {
+ return safeGet(() -> ModConfig.SERVER.dialogueRadius.get(), 20);
+ }
+
+ /**
+ * Get the dialogue cooldown in ticks.
+ *
+ * @return Cooldown in ticks (default 100 = 5 seconds)
+ */
+ public static int getDialogueCooldown() {
+ return safeGet(() -> ModConfig.SERVER.dialogueCooldown.get(), 100);
+ }
+
+ // ==================== Labor ====================
+
+ /**
+ * Get the labor rest duration in seconds.
+ *
+ * @return Rest duration in seconds (default 120)
+ */
+ public static int getLaborRestSeconds() {
+ return safeGet(() -> ModConfig.SERVER.laborRestSeconds.get(), 120);
+ }
+
+ // ==================== Solo Mode / Master Spawn ====================
+
+ /**
+ * Check if Master NPC spawning is enabled.
+ *
+ * @return true if Master can spawn (default true)
+ */
+ public static boolean isEnableMasterSpawn() {
+ return safeGet(() -> ModConfig.SERVER.enableMasterSpawn.get(), true);
+ }
+
+ /**
+ * Check if solo mode fallback behavior is enabled.
+ * When enabled, kidnappers in solo worlds use alternative captive handling.
+ *
+ * @return true if solo fallback is enabled (default true)
+ */
+ public static boolean isEnableSoloFallback() {
+ return safeGet(() -> ModConfig.SERVER.enableSoloFallback.get(), true);
+ }
+
+ /**
+ * Get the solo mode timeout in seconds before the kidnapper gives up waiting.
+ *
+ * @return Timeout in seconds (default 120)
+ */
+ public static int getSoloTimeoutSeconds() {
+ return safeGet(() -> ModConfig.SERVER.soloTimeoutSeconds.get(), 120);
+ }
+
+ /**
+ * Get the probability (0.0-1.0) that a kidnapper keeps the captive in solo mode.
+ *
+ * @return Keep chance (default 0.6)
+ */
+ public static double getSoloKeepChance() {
+ return safeGet(() -> ModConfig.SERVER.soloKeepChance.get(), 0.6);
+ }
+
+ // ==================== Abandon Behavior ====================
+
+ /**
+ * Check if kidnapper abandonment keeps the blindfold on the captive.
+ *
+ * @return true if blindfold is kept (default true)
+ */
+ public static boolean isAbandonKeepsBlindfold() {
+ return safeGet(() -> ModConfig.SERVER.abandonKeepsBlindfold.get(), true);
+ }
+
+ /**
+ * Check if kidnapper abandonment keeps binds on the captive.
+ *
+ * @return true if binds are kept (default true)
+ */
+ public static boolean isAbandonKeepsBinds() {
+ return safeGet(() -> ModConfig.SERVER.abandonKeepsBinds.get(), true);
+ }
+
+ // ==================== Gag Settings ====================
+
+ /**
+ * Get the configured comprehension factor for a gag material.
+ * Falls back to the material's hardcoded default if the config key is missing.
+ *
+ * @param materialKey Lowercase gag material name (e.g., "cloth", "ball")
+ * @param defaultValue The material's built-in default comprehension
+ * @return Comprehension factor as float
+ */
+ public static float getGagComprehension(String materialKey, float defaultValue) {
+ return safeGet(
+ () -> {
+ if (ModConfig.SERVER == null) return defaultValue;
+ Map map =
+ ModConfig.SERVER.gagComprehension;
+ if (map != null && map.containsKey(materialKey)) {
+ return map.get(materialKey).get().floatValue();
+ }
+ return defaultValue;
+ },
+ defaultValue
+ );
+ }
+
+ /**
+ * Get the configured talk range for a gag material.
+ * Falls back to the material's hardcoded default if the config key is missing.
+ *
+ * @param materialKey Lowercase gag material name (e.g., "cloth", "ball")
+ * @param defaultValue The material's built-in default talk range
+ * @return Talk range as double
+ */
+ public static double getGagTalkRange(String materialKey, double defaultValue) {
+ return safeGet(
+ () -> {
+ if (ModConfig.SERVER == null) return defaultValue;
+ Map map =
+ ModConfig.SERVER.gagRange;
+ if (map != null && map.containsKey(materialKey)) {
+ return map.get(materialKey).get();
+ }
+ return defaultValue;
+ },
+ defaultValue
+ );
+ }
+
// ==================== Helpers ====================
/**
diff --git a/src/main/java/com/tiedup/remake/entities/DamselRewardTracker.java b/src/main/java/com/tiedup/remake/entities/DamselRewardTracker.java
index 0bf8a97..1eca9c8 100644
--- a/src/main/java/com/tiedup/remake/entities/DamselRewardTracker.java
+++ b/src/main/java/com/tiedup/remake/entities/DamselRewardTracker.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.entities;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.EntityDialogueManager;
import java.util.UUID;
@@ -179,7 +179,7 @@ public class DamselRewardTracker {
// Thank the savior via dialogue
damsel.talkToPlayersInRadius(
EntityDialogueManager.DialogueCategory.DAMSEL_FREED,
- ModConfig.SERVER.dialogueRadius.get()
+ SettingsAccessor.getDialogueRadius()
);
TiedUpMod.LOGGER.info(
diff --git a/src/main/java/com/tiedup/remake/entities/EntityKidnapBomb.java b/src/main/java/com/tiedup/remake/entities/EntityKidnapBomb.java
index bb651b1..6e86210 100644
--- a/src/main/java/com/tiedup/remake/entities/EntityKidnapBomb.java
+++ b/src/main/java/com/tiedup/remake/entities/EntityKidnapBomb.java
@@ -1,7 +1,6 @@
package com.tiedup.remake.entities;
import com.tiedup.remake.blocks.entity.KidnapBombBlockEntity;
-import com.tiedup.remake.core.ModConfig;
import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.util.KidnapExplosion;
import javax.annotation.Nullable;
@@ -56,7 +55,7 @@ public class EntityKidnapBomb extends PrimedTnt {
this.setPos(x, y, z);
double d0 = level.random.nextDouble() * (Math.PI * 2);
this.setDeltaMovement(-Math.sin(d0) * 0.02, 0.2, -Math.cos(d0) * 0.02);
- this.setFuse(ModConfig.SERVER.kidnapBombFuse.get());
+ this.setFuse(SettingsAccessor.getKidnapBombFuse());
this.xo = x;
this.yo = y;
diff --git a/src/main/java/com/tiedup/remake/entities/EntityKidnapperArcher.java b/src/main/java/com/tiedup/remake/entities/EntityKidnapperArcher.java
index 34b0dde..35c3981 100644
--- a/src/main/java/com/tiedup/remake/entities/EntityKidnapperArcher.java
+++ b/src/main/java/com/tiedup/remake/entities/EntityKidnapperArcher.java
@@ -335,9 +335,9 @@ public class EntityKidnapperArcher
public int getBindChanceForTarget(UUID targetUUID) {
int hitCount = targetHitCounts.getOrDefault(targetUUID, 0);
int baseChance =
- com.tiedup.remake.core.ModConfig.SERVER.archerArrowBindChanceBase.get();
+ SettingsAccessor.getArcherArrowBindChanceBase();
int perHitChance =
- com.tiedup.remake.core.ModConfig.SERVER.archerArrowBindChancePerHit.get();
+ SettingsAccessor.getArcherArrowBindChancePerHit();
int chance = baseChance + (hitCount * perHitChance);
return Math.min(chance, ARCHER_MAX_BIND_CHANCE);
diff --git a/src/main/java/com/tiedup/remake/entities/EntityKidnapperMerchant.java b/src/main/java/com/tiedup/remake/entities/EntityKidnapperMerchant.java
index 50c4e62..72c1ea8 100644
--- a/src/main/java/com/tiedup/remake/entities/EntityKidnapperMerchant.java
+++ b/src/main/java/com/tiedup/remake/entities/EntityKidnapperMerchant.java
@@ -2,7 +2,6 @@ package com.tiedup.remake.entities;
import static com.tiedup.remake.util.GameConstants.*;
-import com.tiedup.remake.core.ModConfig;
import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.SpeakerType;
@@ -356,7 +355,7 @@ public class EntityKidnapperMerchant extends EntityKidnapperElite {
private void transitionToHostile(LivingEntity attacker) {
currentState = MerchantState.HOSTILE;
attackerUUID = attacker.getUUID();
- hostileCooldownTicks = ModConfig.SERVER.merchantHostileDuration.get();
+ hostileCooldownTicks = SettingsAccessor.getMerchantHostileDuration();
entityData.set(DATA_MERCHANT_STATE, MerchantState.HOSTILE.getId());
// Equip kidnapper items
@@ -536,8 +535,8 @@ public class EntityKidnapperMerchant extends EntityKidnapperElite {
addGuaranteedUtilities();
// RANDOM TRADES
- int min = ModConfig.SERVER.merchantMinTrades.get();
- int max = ModConfig.SERVER.merchantMaxTrades.get();
+ int min = SettingsAccessor.getMerchantMinTrades();
+ int max = SettingsAccessor.getMerchantMaxTrades();
int count = min + this.random.nextInt(Math.max(1, max - min + 1));
// Collect all mod items
@@ -644,21 +643,21 @@ public class EntityKidnapperMerchant extends EntityKidnapperElite {
int minPrice, maxPrice;
switch (tier) {
case 4:
- minPrice = ModConfig.SERVER.tier4PriceMin.get();
- maxPrice = ModConfig.SERVER.tier4PriceMax.get();
+ minPrice = SettingsAccessor.getTier4PriceMin();
+ maxPrice = SettingsAccessor.getTier4PriceMax();
break;
case 3:
- minPrice = ModConfig.SERVER.tier3PriceMin.get();
- maxPrice = ModConfig.SERVER.tier3PriceMax.get();
+ minPrice = SettingsAccessor.getTier3PriceMin();
+ maxPrice = SettingsAccessor.getTier3PriceMax();
break;
case 2:
- minPrice = ModConfig.SERVER.tier2PriceMin.get();
- maxPrice = ModConfig.SERVER.tier2PriceMax.get();
+ minPrice = SettingsAccessor.getTier2PriceMin();
+ maxPrice = SettingsAccessor.getTier2PriceMax();
break;
case 1:
default:
- minPrice = ModConfig.SERVER.tier1PriceMin.get();
- maxPrice = ModConfig.SERVER.tier1PriceMax.get();
+ minPrice = SettingsAccessor.getTier1PriceMin();
+ maxPrice = SettingsAccessor.getTier1PriceMax();
break;
}
diff --git a/src/main/java/com/tiedup/remake/entities/EntityRopeArrow.java b/src/main/java/com/tiedup/remake/entities/EntityRopeArrow.java
index d9410af..6f9e252 100644
--- a/src/main/java/com/tiedup/remake/entities/EntityRopeArrow.java
+++ b/src/main/java/com/tiedup/remake/entities/EntityRopeArrow.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.entities;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.ModItems;
import com.tiedup.remake.state.IBondageState;
@@ -87,7 +87,7 @@ public class EntityRopeArrow extends AbstractArrow {
bindChance = archer.getBindChanceForTarget(target.getUUID());
} else {
// Other shooters: default 50% chance
- bindChance = ModConfig.SERVER.ropeArrowBindChance.get();
+ bindChance = SettingsAccessor.getRopeArrowBindChance();
}
// Roll for bind chance
diff --git a/src/main/java/com/tiedup/remake/entities/ai/kidnapper/KidnapperWaitForBuyerGoal.java b/src/main/java/com/tiedup/remake/entities/ai/kidnapper/KidnapperWaitForBuyerGoal.java
index 97f892e..7a35d25 100644
--- a/src/main/java/com/tiedup/remake/entities/ai/kidnapper/KidnapperWaitForBuyerGoal.java
+++ b/src/main/java/com/tiedup/remake/entities/ai/kidnapper/KidnapperWaitForBuyerGoal.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.entities.ai.kidnapper;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.EntityDialogueManager;
import com.tiedup.remake.dialogue.EntityDialogueManager.DialogueCategory;
@@ -155,7 +155,7 @@ public class KidnapperWaitForBuyerGoal extends Goal {
// Check if Master should spawn immediately for solo player
IRestrainable captive = this.kidnapper.getCaptive();
- boolean isMasterEnabled = ModConfig.SERVER.enableMasterSpawn.get();
+ boolean isMasterEnabled = SettingsAccessor.isEnableMasterSpawn();
boolean isPlayer =
captive != null && captive.asLivingEntity() instanceof Player;
@@ -171,12 +171,12 @@ public class KidnapperWaitForBuyerGoal extends Goal {
// Don't return - let the goal continue so kidnapper waits for Master
// The wait duration is set to allow Master to arrive
this.waitDuration = 6000; // 5 minutes max wait for Master to arrive
- } else if (this.soloMode && ModConfig.SERVER.enableSoloFallback.get()) {
+ } else if (this.soloMode && SettingsAccessor.isEnableSoloFallback()) {
// Solo mode (non-player captive): use config timeout
- this.waitDuration = ModConfig.SERVER.soloTimeoutSeconds.get() * 20;
+ this.waitDuration = SettingsAccessor.getSoloTimeoutSeconds() * 20;
TiedUpMod.LOGGER.debug(
"[KidnapperWaitForBuyerGoal] Solo mode detected, using {}s timeout",
- ModConfig.SERVER.soloTimeoutSeconds.get()
+ SettingsAccessor.getSoloTimeoutSeconds()
);
} else {
// Normal mode: random 5-8 minutes
@@ -426,7 +426,7 @@ public class KidnapperWaitForBuyerGoal extends Goal {
}
// Handle solo mode fallback
- if (this.soloMode && ModConfig.SERVER.enableSoloFallback.get()) {
+ if (this.soloMode && SettingsAccessor.isEnableSoloFallback()) {
handleSoloModeFallback(captive);
} else {
// Normal multiplayer mode: just flee
@@ -450,7 +450,7 @@ public class KidnapperWaitForBuyerGoal extends Goal {
}
// Check if Master spawn is enabled and captive is a player
- boolean isMasterEnabled = ModConfig.SERVER.enableMasterSpawn.get();
+ boolean isMasterEnabled = SettingsAccessor.isEnableMasterSpawn();
boolean isPlayer = captive.asLivingEntity() instanceof Player;
if (isMasterEnabled && isPlayer) {
@@ -460,7 +460,7 @@ public class KidnapperWaitForBuyerGoal extends Goal {
}
// Fallback to original behavior
- double keepChance = ModConfig.SERVER.soloKeepChance.get();
+ double keepChance = SettingsAccessor.getSoloKeepChance();
double roll = this.kidnapper.getRandom().nextDouble();
TiedUpMod.LOGGER.debug(
diff --git a/src/main/java/com/tiedup/remake/entities/ai/maid/goals/MaidAssignTaskGoal.java b/src/main/java/com/tiedup/remake/entities/ai/maid/goals/MaidAssignTaskGoal.java
index e245de4..0d36922 100644
--- a/src/main/java/com/tiedup/remake/entities/ai/maid/goals/MaidAssignTaskGoal.java
+++ b/src/main/java/com/tiedup/remake/entities/ai/maid/goals/MaidAssignTaskGoal.java
@@ -2,7 +2,7 @@ package com.tiedup.remake.entities.ai.maid.goals;
import com.tiedup.remake.cells.CellDataV2;
import com.tiedup.remake.cells.CellRegistryV2;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityMaid;
import com.tiedup.remake.labor.LaborTask;
@@ -87,7 +87,7 @@ public class MaidAssignTaskGoal extends Goal {
if (phase == LaborRecord.WorkPhase.RESTING) {
// Check if rest is complete (config: laborRestSeconds, default 120s)
- long restTicks = ModConfig.SERVER.laborRestSeconds.get() * 20L;
+ long restTicks = SettingsAccessor.getLaborRestSeconds() * 20L;
long elapsed = labor.getTimeInPhase(currentTime);
if (elapsed >= restTicks) {
labor.finishRest(currentTime);
diff --git a/src/main/java/com/tiedup/remake/entities/damsel/components/DamselAIController.java b/src/main/java/com/tiedup/remake/entities/damsel/components/DamselAIController.java
index d9fa23b..196ec6e 100644
--- a/src/main/java/com/tiedup/remake/entities/damsel/components/DamselAIController.java
+++ b/src/main/java/com/tiedup/remake/entities/damsel/components/DamselAIController.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.entities.damsel.components;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.entities.ai.damsel.*;
@@ -223,7 +223,7 @@ public class DamselAIController {
Player.class,
host
.getBoundingBox()
- .inflate(ModConfig.SERVER.dialogueRadius.get())
+ .inflate(SettingsAccessor.getDialogueRadius())
);
// Get captor entity for comparison
@@ -258,7 +258,7 @@ public class DamselAIController {
}
// Reset cooldown
- int baseCooldown = ModConfig.SERVER.dialogueCooldown.get();
+ int baseCooldown = SettingsAccessor.getDialogueCooldown();
if (foundTarget) {
// Full cooldown if we talked
this.callForHelpCooldown =
diff --git a/src/main/java/com/tiedup/remake/entities/damsel/components/DamselDialogueHandler.java b/src/main/java/com/tiedup/remake/entities/damsel/components/DamselDialogueHandler.java
index eaf8955..e04492a 100644
--- a/src/main/java/com/tiedup/remake/entities/damsel/components/DamselDialogueHandler.java
+++ b/src/main/java/com/tiedup/remake/entities/damsel/components/DamselDialogueHandler.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.entities.damsel.components;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.dialogue.EntityDialogueManager;
import com.tiedup.remake.dialogue.EntityDialogueManager.DialogueCategory;
import java.util.HashMap;
@@ -101,7 +101,7 @@ public class DamselDialogueHandler {
if (
lastUsed != null &&
- (currentTick - lastUsed) < ModConfig.SERVER.dialogueCooldown.get()
+ (currentTick - lastUsed) < SettingsAccessor.getDialogueCooldown()
) {
return false; // Still on cooldown
}
diff --git a/src/main/java/com/tiedup/remake/entities/damsel/components/NpcCaptivityManager.java b/src/main/java/com/tiedup/remake/entities/damsel/components/NpcCaptivityManager.java
index 5b8bc8c..53d4ded 100644
--- a/src/main/java/com/tiedup/remake/entities/damsel/components/NpcCaptivityManager.java
+++ b/src/main/java/com/tiedup/remake/entities/damsel/components/NpcCaptivityManager.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.entities.damsel.components;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.AbstractTiedUpNpc;
import com.tiedup.remake.state.ICaptor;
@@ -137,7 +137,7 @@ public class NpcCaptivityManager {
if (!entity.level().isClientSide()) {
host.talkToPlayersInRadius(
com.tiedup.remake.dialogue.EntityDialogueManager.DialogueCategory.DAMSEL_FREED,
- ModConfig.SERVER.dialogueRadius.get()
+ SettingsAccessor.getDialogueRadius()
);
}
} else {
diff --git a/src/main/java/com/tiedup/remake/entities/damsel/components/NpcEquipmentManager.java b/src/main/java/com/tiedup/remake/entities/damsel/components/NpcEquipmentManager.java
index ee0b986..8d1e07d 100644
--- a/src/main/java/com/tiedup/remake/entities/damsel/components/NpcEquipmentManager.java
+++ b/src/main/java/com/tiedup/remake/entities/damsel/components/NpcEquipmentManager.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.entities.damsel.components;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.AbstractTiedUpNpc;
import com.tiedup.remake.items.base.ILockable;
@@ -206,7 +206,7 @@ public class NpcEquipmentManager {
if (!wasAlreadyTied && !entity.level().isClientSide()) {
host.talkToPlayersInRadius(
com.tiedup.remake.dialogue.EntityDialogueManager.DialogueCategory.DAMSEL_CAPTURED,
- ModConfig.SERVER.dialogueRadius.get()
+ SettingsAccessor.getDialogueRadius()
);
}
diff --git a/src/main/java/com/tiedup/remake/entities/kidnapper/components/KidnapperCaptiveManager.java b/src/main/java/com/tiedup/remake/entities/kidnapper/components/KidnapperCaptiveManager.java
index 925e247..e9dc8c0 100644
--- a/src/main/java/com/tiedup/remake/entities/kidnapper/components/KidnapperCaptiveManager.java
+++ b/src/main/java/com/tiedup/remake/entities/kidnapper/components/KidnapperCaptiveManager.java
@@ -1,7 +1,7 @@
package com.tiedup.remake.entities.kidnapper.components;
import com.tiedup.remake.cells.CellDataV2;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.EntityDialogueManager;
import com.tiedup.remake.entities.EntityKidnapper;
@@ -628,7 +628,7 @@ public class KidnapperCaptiveManager {
// Apply blindfold if enabled in config
if (
- com.tiedup.remake.core.ModConfig.SERVER.abandonKeepsBlindfold.get()
+ SettingsAccessor.isAbandonKeepsBlindfold()
) {
net.minecraft.world.item.ItemStack blindfold = getBlindfoldItem();
if (
@@ -652,7 +652,7 @@ public class KidnapperCaptiveManager {
// Remove restraints if NOT configured to keep them
boolean keepBinds =
- com.tiedup.remake.core.ModConfig.SERVER.abandonKeepsBinds.get();
+ SettingsAccessor.isAbandonKeepsBinds();
if (!keepBinds) {
// Full release including binds
this.currentCaptive.untie(true);
diff --git a/src/main/java/com/tiedup/remake/events/restriction/BondageItemRestrictionHandler.java b/src/main/java/com/tiedup/remake/events/restriction/BondageItemRestrictionHandler.java
index 7e28925..a999de1 100644
--- a/src/main/java/com/tiedup/remake/events/restriction/BondageItemRestrictionHandler.java
+++ b/src/main/java/com/tiedup/remake/events/restriction/BondageItemRestrictionHandler.java
@@ -1,5 +1,6 @@
package com.tiedup.remake.events.restriction;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.SystemMessageManager.MessageCategory;
import com.tiedup.remake.core.TiedUpMod;
@@ -134,7 +135,7 @@ public class BondageItemRestrictionHandler {
Vec3 motion = player.getDeltaMovement();
player.setDeltaMovement(
motion.scale(
- com.tiedup.remake.core.ModConfig.SERVER.tiedSwimSpeedMultiplier.get()
+ SettingsAccessor.getTiedSwimSpeedMultiplier()
)
);
}
diff --git a/src/main/java/com/tiedup/remake/items/ItemChloroformBottle.java b/src/main/java/com/tiedup/remake/items/ItemChloroformBottle.java
index f188ae5..080481c 100644
--- a/src/main/java/com/tiedup/remake/items/ItemChloroformBottle.java
+++ b/src/main/java/com/tiedup/remake/items/ItemChloroformBottle.java
@@ -1,6 +1,5 @@
package com.tiedup.remake.items;
-import com.tiedup.remake.core.ModConfig;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.TiedUpMod;
import net.minecraft.network.chat.Component;
diff --git a/src/main/java/com/tiedup/remake/items/ItemLockpick.java b/src/main/java/com/tiedup/remake/items/ItemLockpick.java
index e7c7d62..ab12fd2 100644
--- a/src/main/java/com/tiedup/remake/items/ItemLockpick.java
+++ b/src/main/java/com/tiedup/remake/items/ItemLockpick.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.items;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.ILockable;
@@ -208,7 +208,7 @@ public class ItemLockpick extends Item {
// Roll for success
boolean success =
- random.nextInt(100) < ModConfig.SERVER.lockpickSuccessChance.get();
+ random.nextInt(100) < SettingsAccessor.getLockpickSuccessChance();
if (success) {
// SUCCESS: Unlock the item, PRESERVE the padlock
@@ -241,7 +241,7 @@ public class ItemLockpick extends Item {
// 2. Check for jam
boolean jammed =
random.nextDouble() * 100 <
- ModConfig.SERVER.lockpickJamChance.get();
+ SettingsAccessor.getLockpickJamChance();
if (jammed) {
lockable.setJammed(targetStack, true);
SystemMessageManager.sendToPlayer(
@@ -265,7 +265,7 @@ public class ItemLockpick extends Item {
// 3. Check for break
boolean broke =
random.nextInt(100) <
- ModConfig.SERVER.lockpickBreakChance.get();
+ SettingsAccessor.getLockpickBreakChance();
if (broke) {
lockpickStack.shrink(1);
SystemMessageManager.sendToPlayer(
diff --git a/src/main/java/com/tiedup/remake/items/ItemRag.java b/src/main/java/com/tiedup/remake/items/ItemRag.java
index 0ceb94b..ea0ede0 100644
--- a/src/main/java/com/tiedup/remake/items/ItemRag.java
+++ b/src/main/java/com/tiedup/remake/items/ItemRag.java
@@ -1,6 +1,5 @@
package com.tiedup.remake.items;
-import com.tiedup.remake.core.ModConfig;
import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.TiedUpMod;
@@ -280,6 +279,6 @@ public class ItemRag extends Item {
* @return Default wet time in ticks
*/
public static int getDefaultWetTime() {
- return ModConfig.SERVER.ragWetTime.get();
+ return SettingsAccessor.getRagWetTime();
}
}
diff --git a/src/main/java/com/tiedup/remake/items/ItemTaser.java b/src/main/java/com/tiedup/remake/items/ItemTaser.java
index 6c48c79..6c716db 100644
--- a/src/main/java/com/tiedup/remake/items/ItemTaser.java
+++ b/src/main/java/com/tiedup/remake/items/ItemTaser.java
@@ -2,7 +2,7 @@ package com.tiedup.remake.items;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.ModSounds;
import java.util.UUID;
import net.minecraft.sounds.SoundSource;
@@ -74,7 +74,7 @@ public class ItemTaser extends Item {
1.0f
);
- int duration = ModConfig.SERVER.taserStunDuration.get();
+ int duration = SettingsAccessor.getTaserStunDuration();
// Apply Slowness I
target.addEffect(
diff --git a/src/main/java/com/tiedup/remake/items/ItemWhip.java b/src/main/java/com/tiedup/remake/items/ItemWhip.java
index 1f952a3..143006a 100644
--- a/src/main/java/com/tiedup/remake/items/ItemWhip.java
+++ b/src/main/java/com/tiedup/remake/items/ItemWhip.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.items;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.entities.EntityKidnapper;
@@ -92,8 +92,8 @@ public class ItemWhip extends Item {
return InteractionResult.PASS;
}
- float damage = ModConfig.SERVER.whipDamage.get().floatValue();
- int resistanceDecrease = ModConfig.SERVER.whipResistanceDecrease.get();
+ float damage = SettingsAccessor.getWhipDamage();
+ int resistanceDecrease = SettingsAccessor.getWhipResistanceDecrease();
// 1. Play whip sound
TiedUpSounds.playWhipSound(target);
diff --git a/src/main/java/com/tiedup/remake/util/GagMaterial.java b/src/main/java/com/tiedup/remake/util/GagMaterial.java
index 4b5a688..f5e3695 100644
--- a/src/main/java/com/tiedup/remake/util/GagMaterial.java
+++ b/src/main/java/com/tiedup/remake/util/GagMaterial.java
@@ -1,6 +1,6 @@
package com.tiedup.remake.util;
-import com.tiedup.remake.core.ModConfig;
+import com.tiedup.remake.core.SettingsAccessor;
/**
* GagMaterial DNA - Defines the "sound" and behavior of different gag materials.
@@ -180,28 +180,15 @@ public enum GagMaterial {
}
public float getComprehension() {
- String key = this.name().toLowerCase();
- if (
- ModConfig.SERVER != null &&
- ModConfig.SERVER.gagComprehension.containsKey(key)
- ) {
- return ModConfig.SERVER.gagComprehension
- .get(key)
- .get()
- .floatValue();
- }
- return defaultComprehension;
+ return SettingsAccessor.getGagComprehension(
+ this.name().toLowerCase(), defaultComprehension
+ );
}
public double getTalkRange() {
- String key = this.name().toLowerCase();
- if (
- ModConfig.SERVER != null &&
- ModConfig.SERVER.gagRange.containsKey(key)
- ) {
- return ModConfig.SERVER.gagRange.get(key).get();
- }
- return defaultTalkRange;
+ return SettingsAccessor.getGagTalkRange(
+ this.name().toLowerCase(), defaultTalkRange
+ );
}
/**
diff --git a/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2StruggleStart.java b/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2StruggleStart.java
index 66bd586..f554187 100644
--- a/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2StruggleStart.java
+++ b/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2StruggleStart.java
@@ -1,5 +1,6 @@
package com.tiedup.remake.v2.bondage.network;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.items.base.IHasResistance;
import com.tiedup.remake.items.base.ILockable;
import com.tiedup.remake.minigame.ContinuousStruggleMiniGameState;
@@ -76,7 +77,7 @@ public class PacketV2StruggleStart {
// RISK-002 fix: respect server config
if (
- !com.tiedup.remake.core.ModConfig.SERVER.struggleMiniGameEnabled.get()
+ !SettingsAccessor.isStruggleMiniGameEnabled()
) return;
int resistance = resistanceItem.getCurrentResistance(stack, player);
diff --git a/src/main/java/com/tiedup/remake/v2/furniture/network/PacketFurnitureEscape.java b/src/main/java/com/tiedup/remake/v2/furniture/network/PacketFurnitureEscape.java
index aed9e83..b5af9d0 100644
--- a/src/main/java/com/tiedup/remake/v2/furniture/network/PacketFurnitureEscape.java
+++ b/src/main/java/com/tiedup/remake/v2/furniture/network/PacketFurnitureEscape.java
@@ -1,5 +1,6 @@
package com.tiedup.remake.v2.furniture.network;
+import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.ItemLockpick;
import com.tiedup.remake.minigame.ContinuousStruggleMiniGameState;
@@ -203,7 +204,7 @@ public class PacketFurnitureEscape {
// Respect server config: if struggle minigame is disabled, skip
if (
- !com.tiedup.remake.core.ModConfig.SERVER.struggleMiniGameEnabled.get()
+ !SettingsAccessor.isStruggleMiniGameEnabled()
) {
TiedUpMod.LOGGER.debug(
"[PacketFurnitureEscape] Struggle minigame disabled by server config"
@@ -333,7 +334,7 @@ public class PacketFurnitureEscape {
// Respect server config: if lockpick minigame is disabled, skip
if (
- !com.tiedup.remake.core.ModConfig.SERVER.lockpickMiniGameEnabled.get()
+ !SettingsAccessor.isLockpickMiniGameEnabled()
) {
TiedUpMod.LOGGER.debug(
"[PacketFurnitureEscape] Lockpick minigame disabled by server config"