diff --git a/src/main/java/eu/ha3/presencefootsteps/PFDebugHud.java b/src/main/java/eu/ha3/presencefootsteps/PFDebugHud.java index 7afae3eb..92eeb875 100644 --- a/src/main/java/eu/ha3/presencefootsteps/PFDebugHud.java +++ b/src/main/java/eu/ha3/presencefootsteps/PFDebugHud.java @@ -5,8 +5,8 @@ import eu.ha3.presencefootsteps.api.DerivedBlock; import eu.ha3.presencefootsteps.sound.SoundEngine; import eu.ha3.presencefootsteps.sound.generator.Locomotion; -import eu.ha3.presencefootsteps.world.Emitter; import eu.ha3.presencefootsteps.world.PrimitiveLookup; +import eu.ha3.presencefootsteps.world.SoundsKey; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; @@ -109,7 +109,7 @@ private static void insertAt(List values, List destination, Stri values.clear(); } - private void renderSoundList(String title, Map sounds, List list) { + private void renderSoundList(String title, Map sounds, List list) { if (sounds.isEmpty()) { return; } @@ -124,7 +124,7 @@ private void renderSoundList(String title, Map sounds, List sounds, List { - list.add((key.isEmpty() ? "default" : key) + ": " + value); + list.add((key.isEmpty() ? "default" : key) + ": " + value.raw()); }); } } diff --git a/src/main/java/eu/ha3/presencefootsteps/sound/acoustics/AcousticLibrary.java b/src/main/java/eu/ha3/presencefootsteps/sound/acoustics/AcousticLibrary.java index 77e0d2c5..2242fd0a 100644 --- a/src/main/java/eu/ha3/presencefootsteps/sound/acoustics/AcousticLibrary.java +++ b/src/main/java/eu/ha3/presencefootsteps/sound/acoustics/AcousticLibrary.java @@ -2,7 +2,7 @@ import eu.ha3.presencefootsteps.sound.Options; import eu.ha3.presencefootsteps.sound.State; -import eu.ha3.presencefootsteps.world.Association; +import eu.ha3.presencefootsteps.world.SoundsKey; import net.minecraft.entity.LivingEntity; public interface AcousticLibrary { @@ -11,18 +11,5 @@ public interface AcousticLibrary { */ void addAcoustic(String name, Acoustic acoustic); - /** - * Plays an acoustic with additional options. - */ - default void playAcoustic(Association association, State event, Options options) { - playAcoustic(association.source(), association.acousticNames(), event, options); - if (Options.WET_VOLUME_OPTIONS.get("volume_percentage") > 0.1F) { - playAcoustic(association.source(), association.wetAcousticNames(), event, options.and(Options.WET_VOLUME_OPTIONS)); - } - if (Options.FOLIAGE_VOLUME_OPTIONS.get("volume_percentage") > 0.1F) { - playAcoustic(association.source(), association.foliageAcousticNames(), event, options.and(Options.FOLIAGE_VOLUME_OPTIONS)); - } - } - - void playAcoustic(LivingEntity location, String acousticName, State event, Options options); + void playAcoustic(LivingEntity location, SoundsKey acousticName, State event, Options options); } \ No newline at end of file diff --git a/src/main/java/eu/ha3/presencefootsteps/sound/acoustics/AcousticsPlayer.java b/src/main/java/eu/ha3/presencefootsteps/sound/acoustics/AcousticsPlayer.java index d11e3921..16d34528 100644 --- a/src/main/java/eu/ha3/presencefootsteps/sound/acoustics/AcousticsPlayer.java +++ b/src/main/java/eu/ha3/presencefootsteps/sound/acoustics/AcousticsPlayer.java @@ -1,16 +1,14 @@ package eu.ha3.presencefootsteps.sound.acoustics; -import com.google.common.base.Strings; import eu.ha3.presencefootsteps.PresenceFootsteps; import eu.ha3.presencefootsteps.sound.Options; import eu.ha3.presencefootsteps.sound.State; import eu.ha3.presencefootsteps.sound.player.SoundPlayer; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import eu.ha3.presencefootsteps.world.Emitter; +import eu.ha3.presencefootsteps.world.SoundsKey; import net.minecraft.entity.LivingEntity; import java.util.Map; -import java.util.stream.Stream; public class AcousticsPlayer implements AcousticLibrary { private final Map acoustics = new Object2ObjectOpenHashMap<>(); @@ -23,25 +21,20 @@ public AcousticsPlayer(SoundPlayer player) { @Override public void addAcoustic(String name, Acoustic acoustic) { - acoustics.put(name, acoustic); + if (acoustics.put(name, acoustic) != null) { + PresenceFootsteps.logger.info("Duplicate acoustic: " + name); + } } @Override - public void playAcoustic(LivingEntity location, String acousticName, State event, Options inputOptions) { - if (!Emitter.isEmitter(acousticName)) { - return; - } - - if (acousticName.contains(",")) { - Stream.of(acousticName.split(",")) - .map(Strings::nullToEmpty) - .filter(s -> !s.isEmpty()) - .distinct() - .forEach(fragment -> playAcoustic(location, fragment, event, inputOptions)); - } else if (!acoustics.containsKey(acousticName)) { - PresenceFootsteps.logger.warn("Tried to play a missing acoustic: " + acousticName); - } else { - acoustics.get(acousticName).playSound(player, location, event, inputOptions); + public void playAcoustic(LivingEntity location, SoundsKey sounds, State event, Options inputOptions) { + for (String acousticName : sounds.names()) { + Acoustic acoustic = acoustics.get(acousticName); + if (acoustic == null) { + PresenceFootsteps.logger.warn("Tried to play a missing acoustic: " + acousticName); + } else { + acoustic.playSound(player, location, event, inputOptions); + } } } } \ No newline at end of file diff --git a/src/main/java/eu/ha3/presencefootsteps/sound/generator/TerrestrialStepSoundGenerator.java b/src/main/java/eu/ha3/presencefootsteps/sound/generator/TerrestrialStepSoundGenerator.java index 008adf07..54fd3286 100644 --- a/src/main/java/eu/ha3/presencefootsteps/sound/generator/TerrestrialStepSoundGenerator.java +++ b/src/main/java/eu/ha3/presencefootsteps/sound/generator/TerrestrialStepSoundGenerator.java @@ -16,8 +16,8 @@ import eu.ha3.presencefootsteps.sound.SoundEngine; import eu.ha3.presencefootsteps.world.Association; import eu.ha3.presencefootsteps.world.AssociationPool; -import eu.ha3.presencefootsteps.world.Emitter; import eu.ha3.presencefootsteps.world.Solver; +import eu.ha3.presencefootsteps.world.SoundsKey; import eu.ha3.presencefootsteps.world.Substrates; class TerrestrialStepSoundGenerator implements StepSoundGenerator { @@ -80,7 +80,7 @@ protected void simulateStationary() { if (isImmobile && (entity.isOnGround() || !entity.isSubmergedInWater()) && playbackImmobile()) { Association assos = associations.findAssociation(0d, isRightFoot); - if (assos.hasAssociation() || !isImmobile) { + if (!assos.isSilent() || !isImmobile) { playStep(assos, State.STAND); } } @@ -215,7 +215,7 @@ public final void produceStep(@Nullable State event, double verticalOffsetAsMinu Options options = Options.singular("gliding_volume", volume); State state = entity.isSubmergedInWater() ? State.SWIM : event; - engine.getIsolator().acoustics().playAcoustic(entity, "_SWIM", state, options); + engine.getIsolator().acoustics().playAcoustic(entity, SoundsKey.SWIM, state, options); playStep(associations.findAssociation(entity.getBlockPos().down(), Solver.MESSY_FOLIAGE_STRATEGY), event); } else { @@ -313,7 +313,7 @@ private void simulateBrushes() { entity.getZ() ), Solver.MESSY_FOLIAGE_STRATEGY); - if (!assos.isNull()) { + if (!assos.isSilent()) { if (!isMessyFoliage) { isMessyFoliage = true; playStep(assos, State.WALK); @@ -327,8 +327,8 @@ protected void playStep(Association association, State eventType) { if (engine.getConfig().getEnabledFootwear()) { if (entity.getEquippedStack(EquipmentSlot.FEET).getItem() instanceof ArmorItem bootItem) { - String bootSound = engine.getIsolator().primitives().getAssociation(bootItem.getEquipSound(), Substrates.DEFAULT); - if (Emitter.isEmitter(bootSound)) { + SoundsKey bootSound = engine.getIsolator().primitives().getAssociation(bootItem.getEquipSound(), Substrates.DEFAULT); + if (bootSound.isEmitter()) { engine.getIsolator().stepPlayer().playStep(association, eventType, Options.singular("volume_percentage", 0.5F)); engine.getIsolator().acoustics().playAcoustic(entity, bootSound, eventType, Options.EMPTY); @@ -343,7 +343,7 @@ protected void playStep(Association association, State eventType) { protected void playSinglefoot(double verticalOffsetAsMinus, State eventType, boolean foot) { Association assos = associations.findAssociation(verticalOffsetAsMinus, isRightFoot); - if (assos.isNotEmitter()) { + if (!assos.isResult()) { assos = associations.findAssociation(verticalOffsetAsMinus + 1, isRightFoot); } @@ -355,7 +355,7 @@ protected void playMultifoot(double verticalOffsetAsMinus, State eventType) { Association leftFoot = associations.findAssociation(verticalOffsetAsMinus, false); Association rightFoot = associations.findAssociation(verticalOffsetAsMinus, true); - if (leftFoot.dataEquals(rightFoot)) { + if (leftFoot.isResult() && leftFoot.dataEquals(rightFoot)) { // If the two feet solve to the same sound, except NO_ASSOCIATION, only play the sound once if (isRightFoot) { leftFoot = Association.NOT_EMITTER; diff --git a/src/main/java/eu/ha3/presencefootsteps/sound/generator/WingedStepSoundGenerator.java b/src/main/java/eu/ha3/presencefootsteps/sound/generator/WingedStepSoundGenerator.java index 6f259721..f0c7c100 100644 --- a/src/main/java/eu/ha3/presencefootsteps/sound/generator/WingedStepSoundGenerator.java +++ b/src/main/java/eu/ha3/presencefootsteps/sound/generator/WingedStepSoundGenerator.java @@ -2,6 +2,7 @@ import eu.ha3.presencefootsteps.sound.State; import eu.ha3.presencefootsteps.util.MathUtil; +import eu.ha3.presencefootsteps.world.SoundsKey; import eu.ha3.presencefootsteps.config.Variator; import eu.ha3.presencefootsteps.sound.Options; import eu.ha3.presencefootsteps.sound.SoundEngine; @@ -9,7 +10,8 @@ import net.minecraft.util.math.Vec3d; class WingedStepSoundGenerator extends TerrestrialStepSoundGenerator { - + private static final SoundsKey SWIFT = SoundsKey.of("_SWIFT"); + private static final SoundsKey WING = SoundsKey.of("_WING"); protected boolean isFalling = false; protected FlightState state = FlightState.IDLE; @@ -93,9 +95,9 @@ protected void simulateJumpingLanding() { if (!isAirborne) { float volume = speedingJumpStateChange ? 2 : MathUtil.scalex(lastFallDistance, variator.HUGEFALL_LANDING_DISTANCE_MIN, variator.HUGEFALL_LANDING_DISTANCE_MAX); - engine.getIsolator().acoustics().playAcoustic(entity, "_SWIFT", State.LAND, Options.singular("gliding_volume", volume)); + engine.getIsolator().acoustics().playAcoustic(entity, SWIFT, State.LAND, Options.singular("gliding_volume", volume)); } else { - engine.getIsolator().acoustics().playAcoustic(entity, "_SWIFT", State.JUMP, Options.EMPTY); + engine.getIsolator().acoustics().playAcoustic(entity, SWIFT, State.JUMP, Options.EMPTY); } } @@ -127,7 +129,7 @@ protected void simulateFlying() { variator.WING_IMMOBILE_FADE_START + variator.WING_IMMOBILE_FADE_DURATION); } - engine.getIsolator().acoustics().playAcoustic(entity, "_WING", State.WALK, Options.singular("gliding_volume", volume)); + engine.getIsolator().acoustics().playAcoustic(entity, WING, State.WALK, Options.singular("gliding_volume", volume)); } } diff --git a/src/main/java/eu/ha3/presencefootsteps/sound/player/PFSoundPlayer.java b/src/main/java/eu/ha3/presencefootsteps/sound/player/PFSoundPlayer.java index e1895ef0..8e6bdd4f 100644 --- a/src/main/java/eu/ha3/presencefootsteps/sound/player/PFSoundPlayer.java +++ b/src/main/java/eu/ha3/presencefootsteps/sound/player/PFSoundPlayer.java @@ -5,6 +5,7 @@ import eu.ha3.presencefootsteps.sound.Options; import eu.ha3.presencefootsteps.sound.SoundEngine; import eu.ha3.presencefootsteps.sound.State; +import eu.ha3.presencefootsteps.sound.acoustics.AcousticLibrary; import eu.ha3.presencefootsteps.world.Association; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -35,22 +36,37 @@ public Random getRNG() { @SuppressWarnings("deprecation") @Override - public void playStep(Association assos, State eventType, Options options) { - if (assos.isNotEmitter()) { + public void playStep(Association association, State event, Options options) { + if (association.isSilent()) { return; } - if (assos.hasAssociation()) { - engine.getIsolator().acoustics().playAcoustic(assos, eventType, options); - } else if (!assos.state().isLiquid()) { - BlockSoundGroup soundType = assos.soundGroup(); - BlockState above = assos.source().getWorld().getBlockState(assos.pos().up()); + AcousticLibrary library = engine.getIsolator().acoustics(); + + if (association.dry().isResult()) { + library.playAcoustic(association.source(), association.dry(), event, options); + } else if (!association.state().isLiquid()) { + BlockSoundGroup soundType = association.state().getSoundGroup(); + BlockState above = association.source().getWorld().getBlockState(association.pos().up()); if (above.isOf(Blocks.SNOW)) { soundType = above.getSoundGroup(); } - immediatePlayer.playSound(assos.source(), soundType.getStepSound().getId().toString(), soundType.getVolume() * 0.15F, soundType.getPitch(), options); + immediatePlayer.playSound(association.source(), + soundType.getStepSound().getId().toString(), + soundType.getVolume() * 0.15F, + soundType.getPitch(), + options + ); + } + + if (association.wet().isEmitter() && Options.WET_VOLUME_OPTIONS.get("volume_percentage") > 0.1F) { + library.playAcoustic(association.source(), association.wet(), event, options.and(Options.WET_VOLUME_OPTIONS)); + } + + if (association.foliage().isEmitter() && Options.FOLIAGE_VOLUME_OPTIONS.get("volume_percentage") > 0.1F) { + library.playAcoustic(association.source(), association.foliage(), event, options.and(Options.FOLIAGE_VOLUME_OPTIONS)); } } diff --git a/src/main/java/eu/ha3/presencefootsteps/world/AbstractSubstrateLookup.java b/src/main/java/eu/ha3/presencefootsteps/world/AbstractSubstrateLookup.java index 8d3a1acb..1d13e161 100644 --- a/src/main/java/eu/ha3/presencefootsteps/world/AbstractSubstrateLookup.java +++ b/src/main/java/eu/ha3/presencefootsteps/world/AbstractSubstrateLookup.java @@ -9,19 +9,19 @@ import net.minecraft.util.Identifier; abstract class AbstractSubstrateLookup implements Lookup { - private final Map> substrates = new Object2ObjectLinkedOpenHashMap<>(); + private final Map> substrates = new Object2ObjectLinkedOpenHashMap<>(); protected abstract Identifier getId(T key); @Override - public String getAssociation(T key, String substrate) { + public SoundsKey getAssociation(T key, String substrate) { final Identifier id = getId(key); - return getSubstrateMap(id, substrate).getOrDefault(id, Emitter.UNASSIGNED); + return getSubstrateMap(id, substrate).getOrDefault(id, SoundsKey.UNASSIGNED); } @Nullable - protected Map getSubstrateMap(Identifier id, String substrate) { - Map primitives = substrates.get(substrate); + protected Map getSubstrateMap(Identifier id, String substrate) { + Map primitives = substrates.get(substrate); if (primitives != null) { return primitives; } @@ -50,7 +50,7 @@ public void add(String key, String value) { substrates .computeIfAbsent(substrate, s -> new Object2ObjectLinkedOpenHashMap<>()) - .put(new Identifier(primitive), value); + .put(new Identifier(primitive), SoundsKey.of(value)); } @Override diff --git a/src/main/java/eu/ha3/presencefootsteps/world/Association.java b/src/main/java/eu/ha3/presencefootsteps/world/Association.java index 18eecc67..5c860351 100644 --- a/src/main/java/eu/ha3/presencefootsteps/world/Association.java +++ b/src/main/java/eu/ha3/presencefootsteps/world/Association.java @@ -2,51 +2,40 @@ import java.util.Objects; +import org.jetbrains.annotations.Nullable; + import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.entity.LivingEntity; -import net.minecraft.sound.BlockSoundGroup; import net.minecraft.util.math.BlockPos; public record Association ( BlockState state, BlockPos pos, - LivingEntity source, + @Nullable LivingEntity source, - String acousticNames, - String wetAcousticNames, - String foliageAcousticNames + SoundsKey dry, + SoundsKey wet, + SoundsKey foliage ) { - public static final Association NOT_EMITTER = new Association(Blocks.AIR.getDefaultState(), BlockPos.ORIGIN, null, Emitter.NOT_EMITTER, Emitter.NOT_EMITTER, Emitter.NOT_EMITTER); + public static final Association NOT_EMITTER = new Association(Blocks.AIR.getDefaultState(), BlockPos.ORIGIN, null, SoundsKey.NON_EMITTER, SoundsKey.NON_EMITTER, SoundsKey.NON_EMITTER); - public static Association of(BlockState state, BlockPos pos, LivingEntity source, String dry, String wet, String foliage) { - if (Emitter.isResult(dry) || Emitter.isResult(wet) || Emitter.isResult(foliage)) { - return new Association(state, pos.toImmutable(), source, dry, wet, foliage); + public static Association of(BlockState state, BlockPos pos, LivingEntity source, SoundsKey dry, SoundsKey wet, SoundsKey foliage) { + if (dry.isSilent() && wet.isSilent() && foliage.isSilent()) { + return NOT_EMITTER; } - return NOT_EMITTER; - } - - public boolean isNull() { - return this == NOT_EMITTER; + return new Association(state, pos.toImmutable(), source, dry, wet, foliage); } - public boolean isNotEmitter() { - return isNull() || ( - Emitter.isNonEmitter(acousticNames) - && Emitter.isNonEmitter(wetAcousticNames) - && Emitter.isNonEmitter(foliageAcousticNames) - ); + public boolean isResult() { + return dry.isResult() || wet.isResult() || foliage.isResult(); } - public boolean hasAssociation() { - return !isNotEmitter(); - } - - public BlockSoundGroup soundGroup() { - return state.getSoundGroup(); + public boolean isSilent() { + return this == NOT_EMITTER; } public boolean dataEquals(Association other) { - return hasAssociation() && Objects.equals(acousticNames, other.acousticNames); + return Objects.equals(dry, other.dry); } } diff --git a/src/main/java/eu/ha3/presencefootsteps/world/AssociationPool.java b/src/main/java/eu/ha3/presencefootsteps/world/AssociationPool.java index 7609404d..40e2ddcf 100644 --- a/src/main/java/eu/ha3/presencefootsteps/world/AssociationPool.java +++ b/src/main/java/eu/ha3/presencefootsteps/world/AssociationPool.java @@ -24,7 +24,7 @@ public final class AssociationPool { private final Solver solver; private boolean wasGolem; - private String association; + private SoundsKey association; public AssociationPool(LivingEntity entity, SoundEngine engine) { this.entity = entity; @@ -64,11 +64,11 @@ public Association findAssociation(BlockPos pos, String strategy) { * @param substrate The substrate corresponding to the stage of lookup being performed. One of the values in {@link Substrates} * @return The matching acoustic names or {@link Emitter#UNASSIGNED} if no match could be determined. */ - public String get(BlockPos pos, BlockState state, String substrate) { + public SoundsKey get(BlockPos pos, BlockState state, String substrate) { for (Entity golem : entity.getWorld().getOtherEntities(entity, new Box(pos).expand(0.5, 0, 0.5), e -> { return !e.isCollidable() || e.getBoundingBox().maxY < entity.getY() + 0.2F; })) { - if (Emitter.isEmitter(association = engine.getIsolator().golems().getAssociation(golem.getType(), substrate))) { + if ((association = engine.getIsolator().golems().getAssociation(golem.getType(), substrate)).isEmitter()) { return association; } } @@ -86,15 +86,15 @@ public String get(BlockPos pos, BlockState state, String substrate) { return association; } - return Emitter.UNASSIGNED; + return SoundsKey.UNASSIGNED; } private boolean getForState(BlockState state, String substrate) { - return Emitter.isResult(association = engine.getIsolator().blocks().getAssociation(state, substrate)); + return (association = engine.getIsolator().blocks().getAssociation(state, substrate)).isResult(); } private boolean getForPrimitive(BlockState state) { BlockSoundGroup sounds = state.getSoundGroup(); - return Emitter.isResult(association = engine.getIsolator().primitives().getAssociation(sounds, PrimitiveLookup.getSubstrate(sounds))); + return (association = engine.getIsolator().primitives().getAssociation(sounds, PrimitiveLookup.getSubstrate(sounds))).isResult(); } } \ No newline at end of file diff --git a/src/main/java/eu/ha3/presencefootsteps/world/Emitter.java b/src/main/java/eu/ha3/presencefootsteps/world/Emitter.java deleted file mode 100644 index d0d471fe..00000000 --- a/src/main/java/eu/ha3/presencefootsteps/world/Emitter.java +++ /dev/null @@ -1,26 +0,0 @@ -package eu.ha3.presencefootsteps.world; - -public interface Emitter { - String UNASSIGNED = "UNASSIGNED"; - String NOT_EMITTER = "NOT_EMITTER"; - String MESSY_GROUND = "MESSY_GROUND"; - - static boolean isNonEmitter(String association) { - return NOT_EMITTER.equals(association); - } - - static boolean isResult(String association) { - return !UNASSIGNED.equals(association); - } - - static boolean isEmitter(String association) { - return isResult(association) && !isNonEmitter(association); - } - - static String combine(String a, String b) { - if (isEmitter(b)) { - return a + "," + b; - } - return a; - } -} diff --git a/src/main/java/eu/ha3/presencefootsteps/world/GolemLookup.java b/src/main/java/eu/ha3/presencefootsteps/world/GolemLookup.java index 4629852f..26515dde 100644 --- a/src/main/java/eu/ha3/presencefootsteps/world/GolemLookup.java +++ b/src/main/java/eu/ha3/presencefootsteps/world/GolemLookup.java @@ -11,8 +11,8 @@ public class GolemLookup extends AbstractSubstrateLookup> { @Override - public String getAssociation(EntityType key, String substrate) { - return getSubstrateMap(getId(key), substrate).getOrDefault(EntityType.getId(key), Emitter.UNASSIGNED); + public SoundsKey getAssociation(EntityType key, String substrate) { + return getSubstrateMap(getId(key), substrate).getOrDefault(EntityType.getId(key), SoundsKey.UNASSIGNED); } @Override @@ -28,9 +28,9 @@ public void writeToReport(boolean full, JsonObjectWriter writer, Map { getSubstrates().forEach(substrate -> { try { - String association = getAssociation(type, substrate); - if (Emitter.isResult(association)) { - writer.field(substrate, association); + SoundsKey association = getAssociation(type, substrate); + if (association.isResult()) { + writer.field(substrate, association.raw()); } } catch (IOException ignore) {} }); diff --git a/src/main/java/eu/ha3/presencefootsteps/world/Lookup.java b/src/main/java/eu/ha3/presencefootsteps/world/Lookup.java index f291e0b0..c58dbbba 100644 --- a/src/main/java/eu/ha3/presencefootsteps/world/Lookup.java +++ b/src/main/java/eu/ha3/presencefootsteps/world/Lookup.java @@ -15,7 +15,7 @@ public interface Lookup extends Loadable, Reportable { * Returns Emitter.UNASSIGNED when no mapping exists, * or Emitter.NOT_EMITTER if such a mapping exists and produces no sound. */ - String getAssociation(T state, String substrate); + SoundsKey getAssociation(T state, String substrate); /** * Gets a set of all the substrates this map contains entries for. @@ -25,13 +25,13 @@ public interface Lookup extends Loadable, Reportable { /** * Gets all the associations for the given state. */ - default Map getAssociations(T state) { - final Map result = new Object2ObjectOpenHashMap<>(); + default Map getAssociations(T state) { + final Map result = new Object2ObjectOpenHashMap<>(); for (String substrate : getSubstrates()) { - String association = getAssociation(state, substrate); + SoundsKey association = getAssociation(state, substrate); - if (Emitter.isResult(association)) { + if (association.isResult()) { result.put(substrate, association); } } diff --git a/src/main/java/eu/ha3/presencefootsteps/world/PFSolver.java b/src/main/java/eu/ha3/presencefootsteps/world/PFSolver.java index 917415ea..7d05d4ec 100644 --- a/src/main/java/eu/ha3/presencefootsteps/world/PFSolver.java +++ b/src/main/java/eu/ha3/presencefootsteps/world/PFSolver.java @@ -78,11 +78,11 @@ public Association findAssociation(AssociationPool associations, LivingEntity pl pos = pos.up(); BlockState above = getBlockStateAt(ply, pos); - String foliage = engine.getIsolator().blocks().getAssociation(above, Substrates.FOLIAGE); + SoundsKey foliage = engine.getIsolator().blocks().getAssociation(above, Substrates.FOLIAGE); // we discard the normal block association, and mark the foliage as detected - if (Emitter.isEmitter(foliage) && Emitter.MESSY_GROUND.equals(engine.getIsolator().blocks().getAssociation(above, Substrates.MESSY))) { - return Association.of(above, pos, ply, Emitter.NOT_EMITTER, Emitter.NOT_EMITTER, foliage); + if (foliage.isEmitter() && engine.getIsolator().blocks().getAssociation(above, Substrates.MESSY) == SoundsKey.MESSY_GROUND) { + return Association.of(above, pos, ply, SoundsKey.NON_EMITTER, SoundsKey.NON_EMITTER, foliage); } return Association.NOT_EMITTER; @@ -132,7 +132,7 @@ public Association findAssociation(AssociationPool associations, LivingEntity pl for (BlockPos underfootPos : BlockPos.iterateOutwards(footPos, (int)feetDistanceToCenter, 2, (int)feetDistanceToCenter)) { mutableFootPos.set(underfootPos); Association assos = findAssociation(associations, ply, collider, underfootPos, mutableFootPos); - if (assos.hasAssociation()) { + if (assos.isResult()) { associationCache.put(footPos.asLong(), assos); return assos; } @@ -145,7 +145,7 @@ public Association findAssociation(AssociationPool associations, LivingEntity pl } private Association findAssociation(AssociationPool associations, LivingEntity player, Box collider, BlockPos originalFootPos, BlockPos.Mutable pos) { - Association worked = findAssociation(associations, player, pos, collider); + Association association; // If it didn't work, the player has walked over the air on the border of a block. // ------ ------ --> z @@ -154,8 +154,8 @@ private Association findAssociation(AssociationPool associations, LivingEntity p // ------ ------ // | // V z - if (!worked.isNull()) { - return worked; + if ((association = findAssociation(associations, player, pos, collider)).isResult()) { + return association; } pos.set(originalFootPos); @@ -173,7 +173,7 @@ private Association findAssociation(AssociationPool associations, LivingEntity p // If the player is at the edge of that if (Math.max(Math.abs(xdang), Math.abs(zdang)) <= 0.2f) { - return worked; + return association; } // Find the maximum absolute value of X or Z boolean isXdangMax = Math.abs(xdang) > Math.abs(zdang); @@ -186,17 +186,15 @@ private Association findAssociation(AssociationPool associations, LivingEntity p // < maxofX- maxofX+ > // Take the maximum border to produce the sound // If we are in the positive border, add 1, else subtract 1 - worked = findAssociation(associations, player, isXdangMax + if ((association = findAssociation(associations, player, isXdangMax ? pos.move(Direction.EAST, xdang > 0 ? 1 : -1) - : pos.move(Direction.SOUTH, zdang > 0 ? 1 : -1), collider); + : pos.move(Direction.SOUTH, zdang > 0 ? 1 : -1), collider)).isResult()) { + return association; + } // If that didn't work, then maybe the footstep hit in the // direction of walking // Try with the other closest block - if (!worked.isNull()) { - return worked; - } - pos.set(originalFootPos); // Take the maximum direction and try with the orthogonal direction of it return findAssociation(associations, player, isXdangMax @@ -214,10 +212,11 @@ private Association findAssociation(AssociationPool associations, LivingEntity e BlockState carpet = getBlockStateAt(entity, pos); VoxelShape shape = carpet.getCollisionShape(entity.getWorld(), pos); boolean isValidCarpet = !shape.isEmpty() && (shape.getMax(Axis.Y) < 0.2F && shape.getMax(Axis.Y) < collider.getMin(Axis.Y) + 0.1F); - String association = Emitter.UNASSIGNED; - String foliage = Emitter.UNASSIGNED; + SoundsKey association = SoundsKey.UNASSIGNED; + SoundsKey foliage = SoundsKey.UNASSIGNED; + SoundsKey wetAssociation = SoundsKey.UNASSIGNED; - if (isValidCarpet && Emitter.isEmitter(association = associations.get(pos, carpet, Substrates.CARPET))) { + if (isValidCarpet && (association = associations.get(pos, carpet, Substrates.CARPET)).isEmitter()) { LOGGER.debug("Carpet detected: " + association); target = carpet; // reference frame moved up by 1 @@ -229,7 +228,7 @@ private Association findAssociation(AssociationPool associations, LivingEntity e pos.move(Direction.DOWN); BlockState fence = getBlockStateAt(entity, pos); - if (Emitter.isResult(association = associations.get(pos, fence, Substrates.FENCE))) { + if ((association = associations.get(pos, fence, Substrates.FENCE)).isResult()) { carpet = target; target = fence; // reference frame moved down by 1 @@ -238,15 +237,15 @@ private Association findAssociation(AssociationPool associations, LivingEntity e } } - if (!Emitter.isResult(association)) { + if (!association.isResult()) { association = associations.get(pos, target, Substrates.DEFAULT); } if (engine.getConfig().foliageSoundsVolume.get() > 0) { if (entity.getEquippedStack(EquipmentSlot.FEET).isEmpty() || entity.isSprinting()) { - if (Emitter.isEmitter(association) && carpet.getCollisionShape(entity.getWorld(), pos).isEmpty()) { + if (association.isEmitter() && carpet.getCollisionShape(entity.getWorld(), pos).isEmpty()) { // This condition implies that foliage over a NOT_EMITTER block CANNOT PLAY - // This block most not be executed if the association is a carpet + // This block must not be executed if the association is a carpet pos.move(Direction.UP); foliage = associations.get(pos, carpet, Substrates.FOLIAGE); pos.move(Direction.DOWN); @@ -256,13 +255,11 @@ private Association findAssociation(AssociationPool associations, LivingEntity e } // Check collision against small blocks - if (!checkCollision(entity.getWorld(), target, pos, collider)) { - association = Emitter.NOT_EMITTER; + if (association.isResult() && !checkCollision(entity.getWorld(), target, pos, collider)) { + association = SoundsKey.NON_EMITTER; } - String wetAssociation = Emitter.NOT_EMITTER; - - if (Emitter.isEmitter(association) && (hasRain + if (association.isEmitter() && (hasRain || (!associations.wasLastMatchGolem() && ( target.getFluidState().isIn(FluidTags.WATER) || carpet.getFluidState().isIn(FluidTags.WATER) @@ -274,7 +271,6 @@ private Association findAssociation(AssociationPool associations, LivingEntity e wetAssociation = associations.get(pos, target, Substrates.WET); } - // Player has stepped on a non-emitter block as defined in the blockmap return Association.of(target, pos, entity, association, wetAssociation, foliage); } } diff --git a/src/main/java/eu/ha3/presencefootsteps/world/PrimitiveLookup.java b/src/main/java/eu/ha3/presencefootsteps/world/PrimitiveLookup.java index eb9be8c0..0326e0e0 100644 --- a/src/main/java/eu/ha3/presencefootsteps/world/PrimitiveLookup.java +++ b/src/main/java/eu/ha3/presencefootsteps/world/PrimitiveLookup.java @@ -14,16 +14,16 @@ protected Identifier getId(BlockSoundGroup key) { return key.getStepSound().getId(); } - public String getAssociation(SoundEvent key, String substrate) { + public SoundsKey getAssociation(SoundEvent key, String substrate) { final Identifier id = key.getId(); - return getSubstrateMap(id, substrate).getOrDefault(id, Emitter.UNASSIGNED); + return getSubstrateMap(id, substrate).getOrDefault(id, SoundsKey.UNASSIGNED); } @Override public void writeToReport(boolean full, JsonObjectWriter writer, Map groups) throws IOException { writer.each(groups.values(), group -> { if (full || !contains(group)) { - writer.field(getKey(group), getAssociation(group, getSubstrate(group))); + writer.field(getKey(group), getAssociation(group, getSubstrate(group)).raw()); } }); } diff --git a/src/main/java/eu/ha3/presencefootsteps/world/SoundsKey.java b/src/main/java/eu/ha3/presencefootsteps/world/SoundsKey.java new file mode 100644 index 00000000..c9fed6d5 --- /dev/null +++ b/src/main/java/eu/ha3/presencefootsteps/world/SoundsKey.java @@ -0,0 +1,43 @@ +package eu.ha3.presencefootsteps.world; + +import java.util.stream.Stream; + +public record SoundsKey(String raw, String[] names) { + public static final SoundsKey UNASSIGNED = new SoundsKey("UNASSIGNED", new String[0]); + static final SoundsKey NON_EMITTER = new SoundsKey("NOT_EMITTER", new String[0]); + static final SoundsKey MESSY_GROUND = new SoundsKey("MESSY_GROUND", new String[0]); + + public static final SoundsKey SWIM = of("_SWIM"); + + public static SoundsKey of(String names) { + if (MESSY_GROUND.raw().equals(names)) { + return MESSY_GROUND; + } + if (UNASSIGNED.raw().equals(names)) { + return UNASSIGNED; + } + if (NON_EMITTER.raw().equals(names)) { + return NON_EMITTER; + } + return new SoundsKey(names); + } + + SoundsKey(String names) { + this(names, Stream.of(names.split(",")) + .filter(s -> !s.isEmpty()) + .distinct() + .toArray(String[]::new)); + } + + public boolean isResult() { + return this != UNASSIGNED; + } + + public boolean isSilent() { + return this == NON_EMITTER; + } + + public boolean isEmitter() { + return isResult() && !isSilent(); + } +} diff --git a/src/main/java/eu/ha3/presencefootsteps/world/StateLookup.java b/src/main/java/eu/ha3/presencefootsteps/world/StateLookup.java index 6da4437b..b552196f 100644 --- a/src/main/java/eu/ha3/presencefootsteps/world/StateLookup.java +++ b/src/main/java/eu/ha3/presencefootsteps/world/StateLookup.java @@ -34,18 +34,18 @@ public StateLookup() { } @Override - public String getAssociation(BlockState state, String substrate) { + public SoundsKey getAssociation(BlockState state, String substrate) { return substrates.getOrDefault(substrate, Bucket.EMPTY).get(state).value; } @Override public void add(String key, String value) { - if (!Emitter.isResult(value)) { - PresenceFootsteps.logger.info("Skipping non-result value " + key + "=" + value); + SoundsKey sound = SoundsKey.of(value); + if (!sound.isResult()) { return; } - Key k = Key.of(key, value); + Key k = Key.of(key, sound); substrates.computeIfAbsent(k.substrate, Bucket.Substrate::new).add(k); } @@ -85,9 +85,9 @@ public void writeToReport(boolean full, JsonObjectWriter writer, Map { getSubstrates().forEach(substrate -> { try { - String association = getAssociation(state, substrate); - if (Emitter.isResult(association)) { - writer.field(substrate, association); + SoundsKey association = getAssociation(state, substrate); + if (association.isResult()) { + writer.field(substrate, association.raw()); } } catch (IOException ignore) {} }); @@ -240,14 +240,14 @@ private record Key( Identifier identifier, String substrate, Set properties, - String value, + SoundsKey value, boolean empty, boolean isTag, boolean isWildcard ) { - public static final Key NULL = new Key(new Identifier("air"), "", ObjectSets.emptySet(), Emitter.UNASSIGNED, true, false, false); + public static final Key NULL = new Key(new Identifier("air"), "", ObjectSets.emptySet(), SoundsKey.UNASSIGNED, true, false, false); - public static Key of(String key, String value) { + public static Key of(String key, SoundsKey value) { final boolean isTag = key.indexOf('#') == 0; if (isTag) { @@ -261,7 +261,7 @@ public static Key of(String key, String value) { if (!isWildcard) { if (id.indexOf('^') > -1) { identifier = new Identifier(id.split("\\^")[0]); - PresenceFootsteps.logger.warn("Metadata entry for " + key + "=" + value + " was ignored"); + PresenceFootsteps.logger.warn("Metadata entry for " + key + "=" + value.raw() + " was ignored"); } else { identifier = new Identifier(id); }