diff --git a/runelite-api/src/main/java/net/runelite/api/events/AreaSoundEffectPlayed.java b/runelite-api/src/main/java/net/runelite/api/events/AreaSoundEffectPlayed.java index f29bb831b3..c40aab4119 100644 --- a/runelite-api/src/main/java/net/runelite/api/events/AreaSoundEffectPlayed.java +++ b/runelite-api/src/main/java/net/runelite/api/events/AreaSoundEffectPlayed.java @@ -24,11 +24,16 @@ */ package net.runelite.api.events; +import javax.annotation.Nullable; import lombok.Data; +import net.runelite.api.Actor; @Data public class AreaSoundEffectPlayed implements Event { + @Nullable + private final Actor source; + private int soundId; private int sceneX; private int sceneY; diff --git a/runelite-api/src/main/java/net/runelite/api/events/SoundEffectPlayed.java b/runelite-api/src/main/java/net/runelite/api/events/SoundEffectPlayed.java index fd0be1044c..43de5ebaac 100644 --- a/runelite-api/src/main/java/net/runelite/api/events/SoundEffectPlayed.java +++ b/runelite-api/src/main/java/net/runelite/api/events/SoundEffectPlayed.java @@ -24,11 +24,16 @@ */ package net.runelite.api.events; +import javax.annotation.Nullable; import lombok.Data; +import net.runelite.api.Actor; @Data public class SoundEffectPlayed implements Event { + @Nullable + private final Actor source; + private int soundId; private int delay; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicConfig.java index 33f3623fe5..85381a0345 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicConfig.java @@ -87,4 +87,14 @@ public interface MusicConfig extends Config hidden = true ) void setAreaSoundEffectVolume(int vol); + + @ConfigItem( + keyName = "muteOtherAreaSounds", + name = "Mute others' area sounds", + description = "Mute area sounds caused from other players" + ) + default boolean muteOtherAreaSounds() + { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java index b21e29bfd6..5c1b2d5b87 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java @@ -37,13 +37,16 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; +import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.Player; import net.runelite.api.ScriptID; import net.runelite.api.SoundEffectID; import net.runelite.api.SpriteID; import net.runelite.api.VarClientInt; import net.runelite.api.VarPlayer; +import net.runelite.api.events.AreaSoundEffectPlayed; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.ScriptCallbackEvent; @@ -136,6 +139,7 @@ public class MusicPlugin extends Plugin eventBus.subscribe(VarClientIntChanged.class, this, this::onVarClientIntChanged); eventBus.subscribe(VolumeChanged.class, this, this::onVolumeChanged); eventBus.subscribe(ScriptCallbackEvent.class, this, this::onScriptCallbackEvent); + eventBus.subscribe(AreaSoundEffectPlayed.class, this, this::onAreaSoundEffectPlayed); } private void onGameStateChanged(GameStateChanged gameStateChanged) @@ -558,4 +562,15 @@ public class MusicPlugin extends Plugin client.getIntStack()[client.getIntStackSize() - 1] = -1; } } + + private void onAreaSoundEffectPlayed(AreaSoundEffectPlayed areaSoundEffectPlayed) + { + Actor source = areaSoundEffectPlayed.getSource(); + if (source != client.getLocalPlayer() + && source instanceof Player + && musicConfig.muteOtherAreaSounds()) + { + areaSoundEffectPlayed.consume(); + } + } } \ No newline at end of file diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/SoundEffectMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/SoundEffectMixin.java index 6181dd87f4..a0615b0472 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/SoundEffectMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/SoundEffectMixin.java @@ -27,10 +27,13 @@ package net.runelite.mixins; import net.runelite.api.SoundEffectVolume; import net.runelite.api.events.AreaSoundEffectPlayed; import net.runelite.api.events.SoundEffectPlayed; +import net.runelite.api.mixins.Copy; import net.runelite.api.mixins.FieldHook; import net.runelite.api.mixins.Inject; import net.runelite.api.mixins.Mixin; +import net.runelite.api.mixins.Replace; import net.runelite.api.mixins.Shadow; +import net.runelite.rs.api.RSActor; import net.runelite.rs.api.RSClient; import net.runelite.rs.api.RSPcmStream; import net.runelite.rs.api.RSRawPcmStream; @@ -46,6 +49,9 @@ public abstract class SoundEffectMixin implements RSClient @Inject private static int lastSoundEffectCount; + @Inject + private static RSActor lastSoundEffectSourceActor; + @Inject @Override public void playSoundEffect(int id) @@ -106,6 +112,23 @@ public abstract class SoundEffectMixin implements RSClient getSoundEffectAudioQueue().addSubStream((RSPcmStream) rawPcmStream); } + + @Copy("updateActorSequence") + public static void rs$updateActorSequence(RSActor actor, int size) + { + throw new RuntimeException(); + } + + @Replace("updateActorSequence") + public static void rl$updateActorSequence(RSActor actor, int size) + { + lastSoundEffectSourceActor = actor; + + rs$updateActorSequence(actor, size); + + lastSoundEffectSourceActor = null; + } + @FieldHook("soundEffectCount") @Inject public static void queuedSoundEffectCountChanged(int idx) @@ -115,15 +138,17 @@ public abstract class SoundEffectMixin implements RSClient { int soundIndex = soundCount - 1; int packedLocation = client.getSoundLocations()[soundIndex]; + boolean consumed; if (packedLocation == 0) { // Regular sound effect - SoundEffectPlayed event = new SoundEffectPlayed(); + SoundEffectPlayed event = new SoundEffectPlayed(lastSoundEffectSourceActor); event.setSoundId(client.getQueuedSoundEffectIDs()[soundIndex]); event.setDelay(client.getQueuedSoundEffectDelays()[soundIndex]); client.getCallbacks().post(SoundEffectPlayed.class, event); + consumed = event.isConsumed(); } else { @@ -133,16 +158,24 @@ public abstract class SoundEffectMixin implements RSClient int y = (packedLocation >> 8) & 0xFF; int range = (packedLocation) & 0xFF; - AreaSoundEffectPlayed event = new AreaSoundEffectPlayed(); + AreaSoundEffectPlayed event = new AreaSoundEffectPlayed(lastSoundEffectSourceActor); event.setSoundId(client.getQueuedSoundEffectIDs()[soundIndex]); event.setSceneX(x); event.setSceneY(y); event.setRange(range); event.setDelay(client.getQueuedSoundEffectDelays()[soundIndex]); client.getCallbacks().post(AreaSoundEffectPlayed.class, event); + consumed = event.isConsumed(); + } + + if (consumed) + { + soundCount--; + client.setQueuedSoundEffectCount(soundCount); } } + lastSoundEffectCount = soundCount; } } diff --git a/runescape-client/src/main/java/Client.java b/runescape-client/src/main/java/Client.java index 30ae007f0b..4ec14479d6 100644 --- a/runescape-client/src/main/java/Client.java +++ b/runescape-client/src/main/java/Client.java @@ -4136,7 +4136,7 @@ public final class Client extends GameShell implements Usernamed { var15 = npcIndices[var1]; NPC var25 = npcs[var15]; if (var25 != null) { - HitSplatDefinition.calculateActorPosition(var25, var25.definition.size); + HitSplatDefinition.updateActorSequence(var25, var25.definition.size); } } diff --git a/runescape-client/src/main/java/HitSplatDefinition.java b/runescape-client/src/main/java/HitSplatDefinition.java index cb426b1874..dae6dfe6dc 100644 --- a/runescape-client/src/main/java/HitSplatDefinition.java +++ b/runescape-client/src/main/java/HitSplatDefinition.java @@ -415,8 +415,8 @@ public class HitSplatDefinition extends DualNode { signature = "(Lbz;IB)V", garbageValue = "-26" ) - @Export("calculateActorPosition") - static final void calculateActorPosition(Actor var0, int var1) { + @Export("updateActorSequence") + static final void updateActorSequence(Actor var0, int var1) { int var2; if (var0.field925 > Client.cycle) { WorldMapDecoration.method386(var0); diff --git a/runescape-client/src/main/java/WorldMapData_1.java b/runescape-client/src/main/java/WorldMapData_1.java index 40fe83d4bb..b7273a779c 100644 --- a/runescape-client/src/main/java/WorldMapData_1.java +++ b/runescape-client/src/main/java/WorldMapData_1.java @@ -267,7 +267,7 @@ public class WorldMapData_1 extends AbstractWorldMapData { for (int var2 = 0; var2 < var0; ++var2) { Player var3 = Client.players[var1[var2]]; if (var3 != null) { - HitSplatDefinition.calculateActorPosition(var3, 1); + HitSplatDefinition.updateActorSequence(var3, 1); } }