Skip to content

Commit 9ad3eb7

Browse files
committed
new: Add Greenlight-backed protected fog controls
1 parent 937c07c commit 9ad3eb7

17 files changed

Lines changed: 343 additions & 32 deletions

File tree

.github/workflows/publish.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
loaders: neoforge
4545
dependencies: |
4646
sodium
47+
greenlight(optional)
4748
reeses-sodium-options(optional)
4849
irisshaders(optional)
4950
iris(optional)
@@ -65,6 +66,7 @@ jobs:
6566
loaders: fabric
6667
dependencies: |
6768
sodium
69+
greenlight(optional)
6870
reeses-sodium-options(optional)
6971
irisshaders(optional)
7072
iris(optional)

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@
99

1010
Features that shouldn't be in Sodium.
1111

12+
## Protected gameplay fog
13+
Protected Gameplay Fog changes blindness, darkness, lava, powder snow, and water fog.
14+
On normal multiplayer servers it stays vanilla unless the server authorizes it through
15+
[Greenlight](https://modrinth.com/mod/greenlight) and you have it installed. See
16+
[Protected Gameplay Fog](https://github.com/FlashyReese/sodium-extra/wiki/Protected-Gameplay-Fog) for the player-facing behavior.
17+
18+
## Server policies
19+
Server owners can authorize Sodium Extra's protected gameplay fog controls with a
20+
a server resource pack and the [Greenlight](https://modrinth.com/mod/greenlight) client mod. See
21+
[Server Policies](https://github.com/FlashyReese/sodium-extra/wiki/Server-Policies) for the policy schema and examples.
22+
1223
## Building from source
1324
### Prerequisites
1425
- Java Development Kit 17 or above

build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ val MAVEN_GROUP by extra { "me.flashyreese.mods" }
1313
val ARCHIVE_NAME by extra { "sodium-extra" }
1414
val MOD_VERSION by extra { "0.9.1" }
1515
val SODIUM_VERSION by extra { "0.9.0+mc26.2" }
16+
val GREENLIGHT_VERSION by extra { "0.1.0+mc26.2" }
1617

1718
allprojects {
1819
apply(plugin = "java")
@@ -36,6 +37,8 @@ subprojects {
3637
maven("https://maven.caffeinemc.net/snapshots")
3738
maven("https://api.modrinth.com/maven")
3839
maven("https://libraries.minecraft.net")
40+
maven("https://maven.flashyreese.me/releases")
41+
maven("https://maven.flashyreese.me/snapshots")
3942
}
4043

4144
base {

common/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ val FABRIC_LOADER_VERSION: String by rootProject.extra
1212
val FABRIC_API_VERSION: String by rootProject.extra
1313

1414
val SODIUM_VERSION: String by rootProject.extra
15+
val GREENLIGHT_VERSION: String by rootProject.extra
1516

1617
dependencies {
1718
minecraft("com.mojang:minecraft:$MINECRAFT_VERSION")
@@ -30,6 +31,7 @@ dependencies {
3031
addDependentFabricModule("fabric-rendering-v1")
3132

3233
implementation("net.caffeinemc:sodium-fabric:$SODIUM_VERSION")
34+
compileOnly("me.flashyreese.mods:greenlight-api:$GREENLIGHT_VERSION")
3335
}
3436

3537
tasks.withType<AbstractRemapJarTask>().forEach {

common/src/main/java/me/flashyreese/mods/sodiumextra/client/config/SodiumExtraGameOptions.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,6 @@ public void sanitize() {
397397
if (this.protectedGameplay == null) {
398398
this.protectedGameplay = new ProtectedFogSettings();
399399
}
400-
this.protectedGameplay.sanitize();
401400
}
402401

403402
public AtmosphericFogSettings getAtmospheric(Identifier dimensionId) {
@@ -448,7 +447,6 @@ public AtmosphericFogSettings() {
448447
}
449448

450449
public void sanitize() {
451-
this.distanceChunks = FogDistanceHelper.normalizeFogDistance(this.distanceChunks);
452450
this.startPercent = Math.clamp(this.startPercent, 0, 100);
453451

454452
if (this.shapeMode == null) {
@@ -480,14 +478,6 @@ public ProtectedFogSettings() {
480478
this.powderSnowDistanceBlocks = FogDistanceHelper.FOG_DISTANCE_VANILLA;
481479
this.waterDistanceBlocks = FogDistanceHelper.FOG_DISTANCE_VANILLA;
482480
}
483-
484-
public void sanitize() {
485-
this.blindnessDistanceBlocks = FogDistanceHelper.normalizeFogDistance(this.blindnessDistanceBlocks);
486-
this.darknessDistanceBlocks = FogDistanceHelper.normalizeFogDistance(this.darknessDistanceBlocks);
487-
this.lavaDistanceBlocks = FogDistanceHelper.normalizeFogDistance(this.lavaDistanceBlocks);
488-
this.powderSnowDistanceBlocks = FogDistanceHelper.normalizeFogDistance(this.powderSnowDistanceBlocks);
489-
this.waterDistanceBlocks = FogDistanceHelper.normalizeFogDistance(this.waterDistanceBlocks);
490-
}
491481
}
492482

493483
public static class ExtraSettings {

common/src/main/java/me/flashyreese/mods/sodiumextra/client/fog/FogDistanceHelper.java

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package me.flashyreese.mods.sodiumextra.client.fog;
22

3+
import com.google.gson.JsonObject;
4+
import me.flashyreese.mods.greenlight.feature.ClientFeature;
5+
import me.flashyreese.mods.greenlight.feature.Greenlight;
36
import me.flashyreese.mods.sodiumextra.client.SodiumExtraClientMod;
47
import me.flashyreese.mods.sodiumextra.client.config.SodiumExtraGameOptions;
58
import me.flashyreese.mods.sodiumextra.mixin.fog.AccessorIntegratedServer;
@@ -16,28 +19,40 @@
1619
import net.minecraft.client.multiplayer.ClientLevel;
1720
import net.minecraft.client.renderer.fog.FogData;
1821
import net.minecraft.resources.Identifier;
22+
import net.minecraft.util.GsonHelper;
1923

2024
import java.lang.reflect.Field;
2125
import java.lang.reflect.Method;
26+
import java.util.EnumMap;
27+
import java.util.Map;
2228

2329
public final class FogDistanceHelper {
2430
public static final Identifier SODIUM_RENDER_DISTANCE_OPTION_ID = Identifier.parse("sodium:general.render_distance");
2531
public static final int FOG_DISTANCE_OFF = -1;
2632
public static final int FOG_DISTANCE_VANILLA = 0;
27-
private static final int LEGACY_FOG_DISTANCE_OFF = 33;
2833
private static final int VANILLA_MAX_FOG_DISTANCE = 32;
2934
private static final int PROTECTED_FOG_DISTANCE_MAX_BLOCKS = 256;
3035
// Shape sentinels decoded by FogShaderTransformer; keep values in sync with its GLSL constants.
3136
private static final float RADIAL_RENDER_DISTANCE_OFFSET = 1_048_576.0F;
3237
private static final float PLANAR_RENDER_DISTANCE_OFFSET = 2_097_152.0F;
3338
private static final float CHUNK_SIZE = 16F;
39+
private static final ClientFeature<ProtectedGameplayFogPolicy> PROTECTED_GAMEPLAY_FOG = Greenlight
40+
.feature(Identifier.fromNamespaceAndPath("sodium-extra", "protected_gameplay_fog"))
41+
.decoder(1, ProtectedGameplayFogPolicy::fromJson)
42+
.register();
3443

3544
public enum ProtectedFogType {
36-
BLINDNESS,
37-
DARKNESS,
38-
LAVA,
39-
POWDER_SNOW,
40-
WATER
45+
BLINDNESS("blindness"),
46+
DARKNESS("darkness"),
47+
LAVA("lava"),
48+
POWDER_SNOW("powder_snow"),
49+
WATER("water");
50+
51+
private final String policyKey;
52+
53+
ProtectedFogType(String policyKey) {
54+
this.policyKey = policyKey;
55+
}
4156
}
4257

4358
public static SodiumExtraGameOptions.AtmosphericFogSettings getAtmosphericSettings(ClientLevel level) {
@@ -53,10 +68,6 @@ public static int getFogDistance(ClientLevel level) {
5368
return getAtmosphericSettings(level).distanceChunks;
5469
}
5570

56-
public static int normalizeFogDistance(int fogDistance) {
57-
return fogDistance == LEGACY_FOG_DISTANCE_OFF ? FOG_DISTANCE_OFF : fogDistance;
58-
}
59-
6071
public static Range getFogDistanceRange(ConfigState state) {
6172
return new Range(FOG_DISTANCE_OFF, getMaxFogDistance(state), 1);
6273
}
@@ -89,9 +100,9 @@ public static int getMaxFogDistance(ConfigState state) {
89100
maxFogDistance = Math.max(maxFogDistance, getSodiumRenderDistanceMax(state, maxFogDistance));
90101

91102
SodiumExtraGameOptions.FogSettings fogSettings = getFogSettings();
92-
maxFogDistance = Math.max(maxFogDistance, normalizeFogDistance(fogSettings.atmospheric.distanceChunks));
103+
maxFogDistance = Math.max(maxFogDistance, fogSettings.atmospheric.distanceChunks);
93104
for (SodiumExtraGameOptions.AtmosphericFogSettings settings : fogSettings.dimensionOverrides.values()) {
94-
maxFogDistance = Math.max(maxFogDistance, normalizeFogDistance(settings.distanceChunks));
105+
maxFogDistance = Math.max(maxFogDistance, settings.distanceChunks);
95106
}
96107

97108
return maxFogDistance;
@@ -187,11 +198,28 @@ public static boolean isBossFogActive() {
187198

188199
public static boolean shouldModifyProtectedGameplayFog() {
189200
SodiumExtraGameOptions.FogSettings fogSettings = getFogSettings();
190-
return fogSettings.advanced && fogSettings.protectedGameplay.enabledWhenAllowed && isLocalWorldAllowedForProtectedGameplayFog();
201+
return fogSettings.advanced
202+
&& fogSettings.protectedGameplay.enabledWhenAllowed
203+
&& (isLocalWorldAllowedForProtectedGameplayFog() || PROTECTED_GAMEPLAY_FOG.policy().isPresent());
191204
}
192205

193206
public static int getProtectedGameplayFogDistance(ProtectedFogType type) {
194-
SodiumExtraGameOptions.ProtectedFogSettings settings = getFogSettings().protectedGameplay;
207+
SodiumExtraGameOptions.FogSettings fogSettings = getFogSettings();
208+
if (!fogSettings.advanced || !fogSettings.protectedGameplay.enabledWhenAllowed) {
209+
return FOG_DISTANCE_VANILLA;
210+
}
211+
212+
int distanceBlocks = getConfiguredProtectedGameplayFogDistance(fogSettings.protectedGameplay, type);
213+
if (isLocalWorldAllowedForProtectedGameplayFog()) {
214+
return distanceBlocks;
215+
}
216+
217+
return PROTECTED_GAMEPLAY_FOG.policy()
218+
.map(policy -> policy.clamp(type, distanceBlocks))
219+
.orElse(FOG_DISTANCE_VANILLA);
220+
}
221+
222+
private static int getConfiguredProtectedGameplayFogDistance(SodiumExtraGameOptions.ProtectedFogSettings settings, ProtectedFogType type) {
195223
return switch (type) {
196224
case BLINDNESS -> settings.blindnessDistanceBlocks;
197225
case DARKNESS -> settings.darknessDistanceBlocks;
@@ -202,7 +230,6 @@ public static int getProtectedGameplayFogDistance(ProtectedFogType type) {
202230
}
203231

204232
public static void applyProtectedGameplayFog(FogData fog, int distanceBlocks, float environmentalStartMultiplier, float skyEndMultiplier) {
205-
distanceBlocks = normalizeFogDistance(distanceBlocks);
206233
if (distanceBlocks == FOG_DISTANCE_VANILLA) {
207234
return;
208235
}
@@ -256,4 +283,44 @@ private static int getIntAccessor(Object object, String methodName, int fallback
256283
}
257284
}
258285

286+
private record ProtectedGameplayFogPolicy(Map<ProtectedFogType, ProtectedFogRule> rules) {
287+
private static ProtectedGameplayFogPolicy fromJson(JsonObject settings) {
288+
EnumMap<ProtectedFogType, ProtectedFogRule> rules = new EnumMap<>(ProtectedFogType.class);
289+
290+
for (ProtectedFogType type : ProtectedFogType.values()) {
291+
JsonObject rule = GsonHelper.getAsJsonObject(settings, type.policyKey, new JsonObject());
292+
boolean enabled = GsonHelper.getAsBoolean(rule, "enabled", false);
293+
int maxDistanceBlocks = Math.clamp(GsonHelper.getAsInt(rule, "max_distance_blocks", FOG_DISTANCE_VANILLA), FOG_DISTANCE_VANILLA, PROTECTED_FOG_DISTANCE_MAX_BLOCKS);
294+
boolean allowOff = GsonHelper.getAsBoolean(rule, "allow_off", false);
295+
296+
rules.put(type, new ProtectedFogRule(enabled, maxDistanceBlocks, allowOff));
297+
}
298+
299+
return new ProtectedGameplayFogPolicy(Map.copyOf(rules));
300+
}
301+
302+
private int clamp(ProtectedFogType type, int distanceBlocks) {
303+
ProtectedFogRule rule = this.rules.get(type);
304+
return rule != null ? rule.clamp(distanceBlocks) : FOG_DISTANCE_VANILLA;
305+
}
306+
}
307+
308+
private record ProtectedFogRule(boolean enabled, int maxDistanceBlocks, boolean allowOff) {
309+
private int clamp(int distanceBlocks) {
310+
if (!this.enabled) {
311+
return FOG_DISTANCE_VANILLA;
312+
}
313+
314+
if (distanceBlocks == FOG_DISTANCE_VANILLA) {
315+
return FOG_DISTANCE_VANILLA;
316+
}
317+
318+
if (disablesFog(distanceBlocks)) {
319+
return this.allowOff ? FOG_DISTANCE_OFF : this.maxDistanceBlocks;
320+
}
321+
322+
return Math.min(distanceBlocks, this.maxDistanceBlocks);
323+
}
324+
}
325+
259326
}

common/src/main/resources/assets/sodium-extra/lang/en_us.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -356,17 +356,17 @@
356356
"sodium-extra.option.prevent_shaders": "Prevent Shaders",
357357
"sodium-extra.option.prevent_shaders.tooltip": "Prevents vanilla shader effects from loading (e.g., spider-view distortion while spectating).",
358358
"sodium-extra.option.protected_gameplay_fog": "Protected Gameplay Fog",
359-
"sodium-extra.option.protected_gameplay_fog.tooltip": "Allows advanced fog distance changes for gameplay-affecting fog only in private singleplayer worlds or LAN worlds with cheats enabled. These controls use block distances and have no effect on normal multiplayer servers.",
359+
"sodium-extra.option.protected_gameplay_fog.tooltip": "Allows advanced fog distance changes for gameplay-affecting fog in private singleplayer worlds, LAN worlds with cheats enabled, or servers that authorize it through Greenlight. Multiplayer authorization requires Greenlight installed. These controls use block distances.",
360360
"sodium-extra.option.protected_gameplay_fog.blindness": "Blindness Fog",
361-
"sodium-extra.option.protected_gameplay_fog.blindness.tooltip": "Adjusts blindness fog in private singleplayer or LAN worlds with cheats enabled.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; full vanilla blindness is about 5 blocks\nOff: Disable this fog",
361+
"sodium-extra.option.protected_gameplay_fog.blindness.tooltip": "Adjusts blindness fog when local play allows it or the server authorizes it with Greenlight.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; full vanilla blindness is about 5 blocks\nOff: Disable this fog",
362362
"sodium-extra.option.protected_gameplay_fog.darkness": "Darkness Fog",
363-
"sodium-extra.option.protected_gameplay_fog.darkness.tooltip": "Adjusts darkness fog in private singleplayer or LAN worlds with cheats enabled.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; vanilla darkness trends toward about 15 blocks\nOff: Disable this fog",
363+
"sodium-extra.option.protected_gameplay_fog.darkness.tooltip": "Adjusts darkness fog when local play allows it or the server authorizes it with Greenlight.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; vanilla darkness trends toward about 15 blocks\nOff: Disable this fog",
364364
"sodium-extra.option.protected_gameplay_fog.lava": "Lava Fog",
365-
"sodium-extra.option.protected_gameplay_fog.lava.tooltip": "Adjusts lava fog in private singleplayer or LAN worlds with cheats enabled.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; vanilla lava is about 1 block, or 5 blocks with Fire Resistance\nOff: Disable this fog",
365+
"sodium-extra.option.protected_gameplay_fog.lava.tooltip": "Adjusts lava fog when local play allows it or the server authorizes it with Greenlight.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; vanilla lava is about 1 block, or 5 blocks with Fire Resistance\nOff: Disable this fog",
366366
"sodium-extra.option.protected_gameplay_fog.powder_snow": "Powder Snow Fog",
367-
"sodium-extra.option.protected_gameplay_fog.powder_snow.tooltip": "Adjusts powder snow fog in private singleplayer or LAN worlds with cheats enabled.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; vanilla powder snow is about 2 blocks\nOff: Disable this fog",
367+
"sodium-extra.option.protected_gameplay_fog.powder_snow.tooltip": "Adjusts powder snow fog when local play allows it or the server authorizes it with Greenlight.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; vanilla powder snow is about 2 blocks\nOff: Disable this fog",
368368
"sodium-extra.option.protected_gameplay_fog.water": "Water Fog",
369-
"sodium-extra.option.protected_gameplay_fog.water.tooltip": "Adjusts underwater fog in private singleplayer or LAN worlds with cheats enabled.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; vanilla water varies by biome and water vision\nOff: Disable this fog",
369+
"sodium-extra.option.protected_gameplay_fog.water.tooltip": "Adjusts underwater fog when local play allows it or the server authorizes it with Greenlight.\n0: Use vanilla fog settings\n1+: Set fog distance in blocks; vanilla water varies by biome and water vision\nOff: Disable this fog",
370370
"sodium-extra.option.rain_snow.tooltip": "Renders rain and snow.",
371371
"sodium-extra.option.rain_splash.tooltip": "Renders rain splash particles.",
372372
"sodium-extra.option.recipe_toast": "Recipe Toasts",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"protocol_version": 1,
3+
"feature": "sodium-extra:protected_gameplay_fog",
4+
"enabled": true,
5+
"settings_version": 1,
6+
"settings": {
7+
"blindness": {
8+
"enabled": false
9+
},
10+
"darkness": {
11+
"enabled": false
12+
},
13+
"lava": {
14+
"enabled": true,
15+
"max_distance_blocks": 256,
16+
"allow_off": true
17+
},
18+
"powder_snow": {
19+
"enabled": false
20+
},
21+
"water": {
22+
"enabled": false
23+
}
24+
}
25+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"pack": {
3+
"pack_format": 22,
4+
"description": "Sodium Extra lava fog Greenlight policy"
5+
}
6+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"protocol_version": 1,
3+
"feature": "sodium-extra:protected_gameplay_fog",
4+
"enabled": true,
5+
"settings_version": 1,
6+
"settings": {
7+
"blindness": {
8+
"enabled": false
9+
},
10+
"darkness": {
11+
"enabled": false
12+
},
13+
"lava": {
14+
"enabled": true,
15+
"max_distance_blocks": 256,
16+
"allow_off": true
17+
},
18+
"powder_snow": {
19+
"enabled": false
20+
},
21+
"water": {
22+
"enabled": false
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)