diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ee24c4d..992f809c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,29 @@
+> ### DynamicSurroundings-1.21.1-0.4.1
+**All Loaders**
+* JAVA 21+
+* Architectury 13.0.8+
+
+**Fabric**
+* Fabric Loader >= 0.16.9
+* Fabric API >= 0.110.0+1.21.
+
+**NeoForge**
+* NeoForge 21.1.84+
+
+**What's New**
+* Added capability to pause/unpause music manager using the /dsmm command.
+* Fog effects - Several different types of fog
+ * Morning fog Occurs early in the AM and eventually burns off
+ * Weather fog when raining
+ * Biome fog rendered in the fog color of the biome
+* Turtledove sound effect for most forests
+* Silent forest biome sound for forests that are snowy/cold (like snowy taiga). It's fairly quiet - light wind blowing through.
+* Powered redstone has a chance of emitting an electric arc sound effect.
+
+**Fixes**
+* Individual Sound Configuration menu crash when rendering sounds from resource pack.
+* Badlands have sound again. (Mesa -> Badlands transition had some challenges.)
+
> ### DynamicSurroundings-1.21.1-0.4.0
**All Loaders**
* JAVA 21+
diff --git a/CREDITS.md b/CREDITS.md
index b92aff6d..93fe8ad2 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -203,3 +203,15 @@ whether LPs can be monetized on the various streaming services.
+
+*dsurround:turtledove*
+
+
+
+*dsurround:biome.forest.silent*
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 4fbf5245..a9602bc9 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,15 @@
> # Dynamic Surroundings for Fabric and NeoForge
A Minecraft Mod that alters the fabric of Minecraft experience by weaving a tapestry of sound and visual effects.
-
-
-
+
+
+
+
+
+
+
+
+
This mod is a successor to the Forge-based Dynamic Surroundings series.
Though a lot of the functionality is similar, the ultimate feature set will be different.
@@ -15,6 +21,10 @@ The mod is 100% client side. You can add to any mod pack, whether you play stand
Starting with Minecraft 1.21.1, Dynamic Surroundings is supported on Fabric and NeoForge.
+Online documentation: https://dynamic-surroundings.readthedocs.io/en/latest/index.html
+
+Documentation repository: https://github.com/OreCruncher/DynamicSurroundingsDocs
+
### Minecraft 1.21.1 Requirements
* JAVA 21+
* Architectury 13.0.8+
diff --git a/common/src/main/java/org/orecruncher/dsurround/Client.java b/common/src/main/java/org/orecruncher/dsurround/Client.java
index a4eec99f..d71bd8f2 100644
--- a/common/src/main/java/org/orecruncher/dsurround/Client.java
+++ b/common/src/main/java/org/orecruncher/dsurround/Client.java
@@ -28,6 +28,7 @@
import org.orecruncher.dsurround.lib.version.VersionChecker;
import org.orecruncher.dsurround.lib.version.VersionResult;
import org.orecruncher.dsurround.processing.Handlers;
+import org.orecruncher.dsurround.processing.fog.HolisticFogRangeCalculator;
import org.orecruncher.dsurround.runtime.ConditionEvaluator;
import org.orecruncher.dsurround.runtime.IConditionEvaluator;
import org.orecruncher.dsurround.sound.AudioPlayerDebug;
@@ -119,6 +120,7 @@ public void initializeClient() {
.registerSingleton(Config.footstepAccents)
.registerSingleton(Config.particleTweaks)
.registerSingleton(Config.compassAndClockOptions)
+ .registerSingleton(Config.fogOptions)
.registerSingleton(Config.otherOptions)
.registerSingleton(IConditionEvaluator.class, ConditionEvaluator.class)
.registerSingleton(IVersionChecker.class, VersionChecker.class)
@@ -170,6 +172,10 @@ public void onComplete(Minecraft client) {
AssetLibraryEvent.RELOAD.raise().onReload(resourceUtilities, IReloadEvent.Scope.TAGS);
}, HandlerPriority.VERY_HIGH);
+ // Add our fog handler
+ container.registerSingleton(HolisticFogRangeCalculator.class);
+ ContainerManager.resolve(HolisticFogRangeCalculator.class);
+
// Force instantiation of the core Handler. This should cause the rest
// of the dependencies to be initialized.
container.resolve(Handlers.class);
diff --git a/common/src/main/java/org/orecruncher/dsurround/Configuration.java b/common/src/main/java/org/orecruncher/dsurround/Configuration.java
index aff2ce1b..f8cf16cc 100644
--- a/common/src/main/java/org/orecruncher/dsurround/Configuration.java
+++ b/common/src/main/java/org/orecruncher/dsurround/Configuration.java
@@ -45,6 +45,10 @@ public class Configuration extends ConfigurationData {
@Comment("Configuration options for the compass and clock overlay")
public final CompassAndClockOptions compassAndClockOptions = new CompassAndClockOptions();
+ @Property
+ @Comment("Configuration options for fog effects")
+ public final FogOptions fogOptions = new FogOptions();
+
@Property
@Comment("Configuration options for other things")
public final OtherOptions otherOptions = new OtherOptions();
@@ -287,6 +291,24 @@ public static class CompassAndClockOptions {
public double scale = 1D;
}
+ public static class FogOptions {
+ @Property
+ @Comment("Enable/disable fog effects")
+ public boolean enableFogEffects = true;
+
+ @Property
+ @Comment("Enable/disable morning fog effect")
+ public boolean enableMorningFog = true;
+
+ @Property
+ @Comment("Enable/disable biome fog effect")
+ public boolean enableBiomeFog = true;
+
+ @Property
+ @Comment("Enable/disable weather fog effect")
+ public boolean enableWeatherFog = true;
+ }
+
public static class OtherOptions {
@Property
@Comment("Enable/disable playing random sound at the Minecraft finish loading to main screen")
diff --git a/common/src/main/java/org/orecruncher/dsurround/commands/MusicManagerCommand.java b/common/src/main/java/org/orecruncher/dsurround/commands/MusicManagerCommand.java
index c389453a..e8f7ff43 100644
--- a/common/src/main/java/org/orecruncher/dsurround/commands/MusicManagerCommand.java
+++ b/common/src/main/java/org/orecruncher/dsurround/commands/MusicManagerCommand.java
@@ -8,10 +8,14 @@
public class MusicManagerCommand extends AbstractClientCommand {
private static final String COMMAND = "dsmm";
private static final String RESET = "reset";
+ private static final String PAUSE = "pause";
+ private static final String UNPAUSE = "unpause";
@Override
public void register(CommandDispatcher dispatcher, CommandBuildContext registryAccess) {
dispatcher.register(ClientCommandRegistrationEvent.literal(COMMAND)
- .then(subCommand(RESET, MusicManagerCommandHandler::reset)));
+ .then(subCommand(RESET, MusicManagerCommandHandler::reset))
+ .then(subCommand(PAUSE, MusicManagerCommandHandler::pause))
+ .then(subCommand(UNPAUSE, MusicManagerCommandHandler::unpause)));
}
}
diff --git a/common/src/main/java/org/orecruncher/dsurround/commands/handlers/MusicManagerCommandHandler.java b/common/src/main/java/org/orecruncher/dsurround/commands/handlers/MusicManagerCommandHandler.java
index 73ee7361..bf7f7f17 100644
--- a/common/src/main/java/org/orecruncher/dsurround/commands/handlers/MusicManagerCommandHandler.java
+++ b/common/src/main/java/org/orecruncher/dsurround/commands/handlers/MusicManagerCommandHandler.java
@@ -8,10 +8,28 @@ public class MusicManagerCommandHandler {
public static Component reset() {
try {
- ((IMusicManager)(GameUtils.getMC().getMusicManager())).dsurround_reset();
+ ((IMusicManager)(GameUtils.getMC().getMusicManager())).dsurround_doCommand("reset");
return Component.translatable("dsurround.command.dsmm.reset.success");
} catch (Throwable t) {
return Component.translatable("dsurround.command.dsmm.reset.failure", t.getMessage());
}
}
+
+ public static Component unpause() {
+ try {
+ ((IMusicManager)(GameUtils.getMC().getMusicManager())).dsurround_doCommand("unpause");
+ return Component.translatable("dsurround.command.dsmm.unpause.success");
+ } catch (Throwable t) {
+ return Component.translatable("dsurround.command.dsmm.unpause.failure", t.getMessage());
+ }
+ }
+
+ public static Component pause() {
+ try {
+ ((IMusicManager)(GameUtils.getMC().getMusicManager())).dsurround_doCommand("pause");
+ return Component.translatable("dsurround.command.dsmm.pause.success");
+ } catch (Throwable t) {
+ return Component.translatable("dsurround.command.dsmm.pause.failure", t.getMessage());
+ }
+ }
}
diff --git a/common/src/main/java/org/orecruncher/dsurround/config/biome/AcousticEntry.java b/common/src/main/java/org/orecruncher/dsurround/config/AcousticEntry.java
similarity index 81%
rename from common/src/main/java/org/orecruncher/dsurround/config/biome/AcousticEntry.java
rename to common/src/main/java/org/orecruncher/dsurround/config/AcousticEntry.java
index 0b635901..61018fac 100644
--- a/common/src/main/java/org/orecruncher/dsurround/config/biome/AcousticEntry.java
+++ b/common/src/main/java/org/orecruncher/dsurround/config/AcousticEntry.java
@@ -1,4 +1,4 @@
-package org.orecruncher.dsurround.config.biome;
+package org.orecruncher.dsurround.config;
import com.google.common.base.MoreObjects;
import org.jetbrains.annotations.Nullable;
@@ -53,6 +53,19 @@ protected Script getConditionsForLogging() {
return getConditions();
}
+ @Override
+ public int hashCode() {
+ return this.conditions.hashCode() * 31 + this.acoustic.getLocation().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof AcousticEntry ae) {
+ return ae.conditions.equals(this.conditions) && ae.acoustic.getLocation().equals(this.acoustic.getLocation());
+ }
+ return false;
+ }
+
public String toString() {
return MoreObjects.toStringHelper(this)
.addValue(getWeight())
diff --git a/common/src/main/java/org/orecruncher/dsurround/config/AcousticEntryCollection.java b/common/src/main/java/org/orecruncher/dsurround/config/AcousticEntryCollection.java
new file mode 100644
index 00000000..ae84912c
--- /dev/null
+++ b/common/src/main/java/org/orecruncher/dsurround/config/AcousticEntryCollection.java
@@ -0,0 +1,14 @@
+package org.orecruncher.dsurround.config;
+
+import org.orecruncher.dsurround.lib.collections.ObjectArray;
+
+public class AcousticEntryCollection extends ObjectArray {
+
+ @Override
+ public boolean add(AcousticEntry entry) {
+ if (this.contains(entry))
+ return false;
+
+ return super.add(entry);
+ }
+}
diff --git a/common/src/main/java/org/orecruncher/dsurround/config/biome/BiomeInfo.java b/common/src/main/java/org/orecruncher/dsurround/config/biome/BiomeInfo.java
index c57a1104..22862de6 100644
--- a/common/src/main/java/org/orecruncher/dsurround/config/biome/BiomeInfo.java
+++ b/common/src/main/java/org/orecruncher/dsurround/config/biome/BiomeInfo.java
@@ -8,6 +8,8 @@
import net.minecraft.world.level.biome.Biome;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
+import org.orecruncher.dsurround.config.AcousticEntry;
+import org.orecruncher.dsurround.config.AcousticEntryCollection;
import org.orecruncher.dsurround.config.data.AcousticConfig;
import org.orecruncher.dsurround.config.libraries.ISoundLibrary;
import org.orecruncher.dsurround.config.libraries.ITagLibrary;
@@ -24,6 +26,7 @@
import org.orecruncher.dsurround.lib.logging.IModLog;
import org.orecruncher.dsurround.lib.scripting.Script;
import org.orecruncher.dsurround.mixinutils.IBiomeExtended;
+import org.orecruncher.dsurround.processing.fog.FogDensity;
import org.orecruncher.dsurround.runtime.IConditionEvaluator;
import org.orecruncher.dsurround.sound.ISoundFactory;
@@ -33,8 +36,7 @@
public final class BiomeInfo implements Comparable, IBiomeSoundProvider {
- public static final int DEFAULT_ADDITIONAL_SOUND_CHANCE = 1000 / 4;
- public static final Script DEFAULT_SOUND_CHANCE = new Script(String.valueOf(1D / DEFAULT_ADDITIONAL_SOUND_CHANCE));
+ public static final Script DEFAULT_SOUND_CHANCE = new Script("0.008");
private static final IModLog LOGGER = ModLog.createChild(ContainerManager.resolve(IModLog.class), "BiomeInfo");
private static final ISoundLibrary SOUND_LIBRARY = ContainerManager.resolve(ISoundLibrary.class);
private static final ITagLibrary TAG_LIBRARY = ContainerManager.resolve(ITagLibrary.class);
@@ -49,12 +51,13 @@ public final class BiomeInfo implements Comparable, IBiomeSoundProvid
private final boolean isOcean;
private final boolean isDeepOcean;
private final boolean isCave;
- private Collection loopSounds = new ObjectArray<>();
- private Collection moodSounds = new ObjectArray<>();
- private Collection additionalSounds = new ObjectArray<>();
- private Collection musicSounds = new ObjectArray<>();
+ private Collection loopSounds = new AcousticEntryCollection();
+ private Collection moodSounds = new AcousticEntryCollection();
+ private Collection additionalSounds = new AcousticEntryCollection();
+ private Collection musicSounds = new AcousticEntryCollection();
private Collection comments = new ObjectArray<>();
private TextColor fogColor;
+ private FogDensity fogDensity;
private Script additionalSoundChance = DEFAULT_SOUND_CHANCE;
private Script moodSoundChance = DEFAULT_SOUND_CHANCE;
@@ -74,6 +77,8 @@ public BiomeInfo(final int version, final ResourceLocation id, final String name
this.isDeepOcean = this.isOcean && this.traits.contains(BiomeTrait.DEEP);
this.isCave = this.traits.contains(BiomeTrait.CAVES);
+ this.fogDensity = FogDensity.NONE;
+
// Check to see if the biome has a soundtrack. If so, add it to
// the music list.
if (biome != null) {
@@ -129,6 +134,14 @@ void setFogColor(final TextColor color) {
this.fogColor = color;
}
+ public FogDensity getFogDensity() {
+ return this.fogDensity;
+ }
+
+ public void setFogDensity(final FogDensity density) {
+ this.fogDensity = density;
+ }
+
void setAdditionalSoundChance(final Script chance) {
this.additionalSoundChance = chance;
}
@@ -205,6 +218,7 @@ public void update(final BiomeConfigRule entry) {
entry.comment().ifPresent(this::addComment);
entry.fogColor().ifPresent(this::setFogColor);
+ entry.fogDensity().ifPresent(this::setFogDensity);
entry.additionalSoundChance().ifPresent(this::setAdditionalSoundChance);
entry.moodSoundChance().ifPresent(this::setMoodSoundChance);
@@ -219,23 +233,32 @@ public void update(final BiomeConfigRule entry) {
for (final AcousticConfig sr : entry.acoustics()) {
var factory = SOUND_LIBRARY.getSoundFactoryOrDefault(sr.factory());
+ Collection targetCollection = null;
+ AcousticEntry acousticEntry = null;
+
switch (sr.type()) {
case LOOP -> {
- final AcousticEntry acousticEntry = new AcousticEntry(factory, sr.conditions());
- this.loopSounds.add(acousticEntry);
+ acousticEntry = new AcousticEntry(factory, sr.conditions());
+ targetCollection = this.loopSounds;
}
case MUSIC, MOOD, ADDITION -> {
final int weight = sr.weight();
- final AcousticEntry acousticEntry = new AcousticEntry(factory, sr.conditions(), weight);
+ acousticEntry = new AcousticEntry(factory, sr.conditions(), weight);
if (sr.type() == SoundEventType.ADDITION)
- this.additionalSounds.add(acousticEntry);
+ targetCollection = this.additionalSounds;
else if (sr.type() == SoundEventType.MOOD)
- this.moodSounds.add(acousticEntry);
+ targetCollection = this.moodSounds;
else
- this.musicSounds.add(acousticEntry);
+ targetCollection = this.musicSounds;
}
- default -> LOGGER.warn("Unknown SoundEventType %s", sr.type());
+ default -> LOGGER.warn("[%s] Unknown SoundEventType %s", this.getBiomeName(), sr.type());
+ }
+
+ // Add if we have a target collection and it is not present
+ if (targetCollection != null) {
+ if (!targetCollection.add(acousticEntry))
+ LOGGER.warn("[%s] Duplicate acoustic entry: %s", this.getBiomeName(), sr.toString());
}
}
}
@@ -269,14 +292,18 @@ public String toString() {
builder.append("\nTags: ").append(tags);
builder.append("\n").append(getTraits().toString());
+ builder.append("\nfogDensity: ").append(this.fogDensity.getName());
+
if (this.fogColor != null) {
- builder.append("\nfogColor: ").append(this.fogColor.formatValue());
+ builder.append(", fogColor: ").append(this.fogColor.formatValue());
}
if (!this.loopSounds.isEmpty()) {
builder.append("\nLOOP sounds [\n");
builder.append(this.loopSounds.stream().map(c -> indent + c.toString()).collect(Collectors.joining("\n")));
builder.append("\n]");
+ } else {
+ builder.append("\nLOOP sounds [NONE]");
}
if (!this.musicSounds.isEmpty()) {
diff --git a/common/src/main/java/org/orecruncher/dsurround/config/block/BlockInfo.java b/common/src/main/java/org/orecruncher/dsurround/config/block/BlockInfo.java
index fec3ea1e..659a1b32 100644
--- a/common/src/main/java/org/orecruncher/dsurround/config/block/BlockInfo.java
+++ b/common/src/main/java/org/orecruncher/dsurround/config/block/BlockInfo.java
@@ -3,15 +3,18 @@
import com.google.common.collect.ImmutableList;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.state.BlockState;
+import org.orecruncher.dsurround.config.AcousticEntryCollection;
import org.orecruncher.dsurround.config.data.AcousticConfig;
import org.orecruncher.dsurround.config.libraries.ISoundLibrary;
-import org.orecruncher.dsurround.config.biome.AcousticEntry;
+import org.orecruncher.dsurround.config.AcousticEntry;
import org.orecruncher.dsurround.config.data.BlockConfigRule;
import org.orecruncher.dsurround.config.libraries.ITagLibrary;
import org.orecruncher.dsurround.effects.IBlockEffectProducer;
import org.orecruncher.dsurround.lib.WeightTable;
import org.orecruncher.dsurround.lib.collections.ObjectArray;
import org.orecruncher.dsurround.lib.di.ContainerManager;
+import org.orecruncher.dsurround.lib.logging.IModLog;
+import org.orecruncher.dsurround.lib.logging.ModLog;
import org.orecruncher.dsurround.lib.random.IRandomizer;
import org.orecruncher.dsurround.lib.scripting.Script;
import org.orecruncher.dsurround.runtime.IConditionEvaluator;
@@ -25,6 +28,7 @@
public class BlockInfo {
+ private static final IModLog LOGGER = ModLog.createChild(ContainerManager.resolve(IModLog.class), "BlockInfo");
private static final IConditionEvaluator CONDITION_EVALUATOR = ContainerManager.resolve(IConditionEvaluator.class);
private static class Occlusion {
@@ -56,7 +60,7 @@ private static class Reflectance {
private static final ITagLibrary TAG_LIBRARY = ContainerManager.resolve(ITagLibrary.class);
protected final int version;
- protected Collection sounds = new ObjectArray<>();
+ protected Collection sounds = new AcousticEntryCollection();
protected Collection blockEffects = new ObjectArray<>();
protected Script soundChance = new Script("0.01");
@@ -92,10 +96,6 @@ public float getSoundOcclusion() {
return this.soundOcclusion;
}
- private void addToSounds(AcousticEntry entry) {
- this.sounds.add(entry);
- }
-
private void addToBlockEffects(IBlockEffectProducer effect) {
this.blockEffects.add(effect);
}
@@ -111,7 +111,8 @@ public void update(BlockConfigRule config) {
for (final AcousticConfig sr : config.acoustics()) {
var factory = SOUND_LIBRARY.getSoundFactoryOrDefault(sr.factory());
final AcousticEntry acousticEntry = new AcousticEntry(factory, sr.conditions(), sr.weight());
- this.addToSounds(acousticEntry);
+ if (!this.sounds.add(acousticEntry))
+ LOGGER.warn("[BlockInfo] Duplicate acoustic entry: %s", sr.toString());
}
for (var e : config.effects()) {
diff --git a/common/src/main/java/org/orecruncher/dsurround/config/data/BiomeConfigRule.java b/common/src/main/java/org/orecruncher/dsurround/config/data/BiomeConfigRule.java
index e8ddcef9..c1ac75de 100644
--- a/common/src/main/java/org/orecruncher/dsurround/config/data/BiomeConfigRule.java
+++ b/common/src/main/java/org/orecruncher/dsurround/config/data/BiomeConfigRule.java
@@ -6,6 +6,7 @@
import net.minecraft.network.chat.TextColor;
import org.orecruncher.dsurround.config.BiomeTrait;
import org.orecruncher.dsurround.lib.scripting.Script;
+import org.orecruncher.dsurround.processing.fog.FogDensity;
import java.util.List;
import java.util.Optional;
@@ -17,6 +18,7 @@ public record BiomeConfigRule(
List traits,
boolean clearSounds,
Optional fogColor,
+ Optional fogDensity,
Optional