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. -CurseForge Project -CurseForge Project -Modrinth +
+ CurseForge Project + CurseForge Project +
+ +
+ Modrinth + Modrinth +
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