From d8a4196c766f51d7016ef51b74ac53984e0ea8df Mon Sep 17 00:00:00 2001 From: TheRealNull Date: Mon, 20 Jan 2020 23:48:48 -0500 Subject: [PATCH] plugins: add sounds service plugin --- .../net/runelite/http/api/RuneLiteAPI.java | 6 + .../http/api/sounds/SoundsClient.java | 109 ++++++++++++++ .../api/events/SoundEffectPlayed.java | 1 + .../client/plugins/sounds/SoundsPlugin.java | 77 ++++++++++ .../net/runelite/mixins/SoundEffectMixin.java | 142 +++++++++--------- 5 files changed, 268 insertions(+), 67 deletions(-) create mode 100644 http-api/src/main/java/net/runelite/http/api/sounds/SoundsClient.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/sounds/SoundsPlugin.java diff --git a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java index 58b48f4e33..7a06250070 100644 --- a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java +++ b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java @@ -68,6 +68,7 @@ public class RuneLiteAPI private static final String OPENOSRS_SESSION = "http://session.openosrs.dev"; private static final String OPENOSRS_XTEA = "http://xtea.openosrs.dev"; private static final String OPENOSRS_ANIMATIONS = "http://animations.openosrs.dev"; + private static final String OPENOSRS_SOUNDS = "http://sounds.openosrs.dev"; private static final String MAVEN_METADATA = "http://repo.runelite.net/net/runelite/runelite-parent/maven-metadata.xml"; private static final Properties properties = new Properties(); @@ -133,6 +134,11 @@ public class RuneLiteAPI return HttpUrl.parse(OPENOSRS_ANIMATIONS); } + public static HttpUrl getSoundsBase() + { + return HttpUrl.parse(OPENOSRS_SOUNDS); + } + public static HttpUrl getApiBase() { final String prop = System.getProperty("runelite.http-service.url"); diff --git a/http-api/src/main/java/net/runelite/http/api/sounds/SoundsClient.java b/http-api/src/main/java/net/runelite/http/api/sounds/SoundsClient.java new file mode 100644 index 0000000000..e47d1edc27 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/sounds/SoundsClient.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.http.api.sounds; + +import com.google.gson.JsonParseException; +import com.google.gson.reflect.TypeToken; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SoundsClient +{ + private static final Logger logger = LoggerFactory.getLogger(SoundsClient.class); + + public void submit(int npcid, int soundid) + { + + HttpUrl url = RuneLiteAPI.getSoundsBase().newBuilder() + .addPathSegment("submit") + .addQueryParameter("npcid", String.valueOf(npcid)) + .addQueryParameter("soundid", String.valueOf(soundid)) + .build(); + + Request request = new Request.Builder() + .url(url) + .build(); + + RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() + { + @Override + public void onFailure(Call call, IOException e) + { + System.out.println("unable to submit sound"); + } + + @Override + public void onResponse(Call call, Response response) + { + try + { + if (!response.isSuccessful()) + { + System.out.println("unsuccessful sound response"); + } + } + finally + { + response.close(); + } + } + }); + } + + public HashMap get() throws IOException + { + HttpUrl url = RuneLiteAPI.getSoundsBase().newBuilder() + .addPathSegment("get") + .build(); + + Request request = new Request.Builder() + .url(url) + .build(); + + try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) + { + InputStream in = response.body().byteStream(); + // CHECKSTYLE:OFF + return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), new TypeToken>() + { + }.getType()); + // CHECKSTYLE:ON + } + catch (JsonParseException ex) + { + throw new IOException(ex); + } + } +} 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 43de5ebaac..b2edb71708 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 @@ -36,6 +36,7 @@ public class SoundEffectPlayed implements Event private int soundId; private int delay; + private int npcid; private boolean consumed; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/sounds/SoundsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/sounds/SoundsPlugin.java new file mode 100644 index 0000000000..248d6a056e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/sounds/SoundsPlugin.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.sounds; + +import java.io.IOException; +import java.util.HashMap; +import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.events.SoundEffectPlayed; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.http.api.sounds.SoundsClient; +import org.apache.commons.lang3.ArrayUtils; + +@PluginDescriptor( + name = "Sounds", + hidden = true +) +@Slf4j +public class SoundsPlugin extends Plugin +{ + private final SoundsClient soundsClient = new SoundsClient(); + + private HashMap sounds; + @Inject + private Client client; + + { + try + { + sounds = soundsClient.get(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + @Subscribe + private void onSoundEffectPlayed(SoundEffectPlayed event) + { + if (event.getNpcid() != -1) + { + if (ArrayUtils.contains(sounds.get(event.getNpcid()), event.getSoundId())) + { + return; + } + int[] newSounds = ArrayUtils.add(sounds.get(event.getNpcid()), event.getSoundId()); + sounds.put(event.getNpcid(), newSounds); + soundsClient.submit(event.getNpcid(), event.getSoundId()); + } + } +} 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 a0615b0472..85dd2af596 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/SoundEffectMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/SoundEffectMixin.java @@ -35,6 +35,7 @@ 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.RSNPC; import net.runelite.rs.api.RSPcmStream; import net.runelite.rs.api.RSRawPcmStream; import net.runelite.rs.api.RSRawSound; @@ -52,6 +53,80 @@ public abstract class SoundEffectMixin implements RSClient @Inject private static RSActor lastSoundEffectSourceActor; + @Inject + private static int lastSoundEffectSourceNPCid; + + @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) + { + if (actor instanceof RSNPC) + { + lastSoundEffectSourceNPCid = ((RSNPC) actor).getId(); + } + lastSoundEffectSourceActor = actor; + + rs$updateActorSequence(actor, size); + + lastSoundEffectSourceActor = null; + } + + @FieldHook("soundEffectCount") + @Inject + public static void queuedSoundEffectCountChanged(int idx) + { + int soundCount = client.getQueuedSoundEffectCount(); + if (soundCount == lastSoundEffectCount + 1) + { + int soundIndex = soundCount - 1; + int packedLocation = client.getSoundLocations()[soundIndex]; + boolean consumed; + + if (packedLocation == 0) + { + // Regular sound effect + SoundEffectPlayed event = new SoundEffectPlayed(lastSoundEffectSourceActor); + event.setNpcid(lastSoundEffectSourceNPCid); + lastSoundEffectSourceNPCid = -1; + event.setSoundId(client.getQueuedSoundEffectIDs()[soundIndex]); + event.setDelay(client.getQueuedSoundEffectDelays()[soundIndex]); + client.getCallbacks().post(SoundEffectPlayed.class, event); + consumed = event.isConsumed(); + } + else + { + // Area sound effect + + int x = (packedLocation >> 16) & 0xFF; + int y = (packedLocation >> 8) & 0xFF; + int range = (packedLocation) & 0xFF; + + 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; + } + @Inject @Override public void playSoundEffect(int id) @@ -111,71 +186,4 @@ 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) - { - int soundCount = client.getQueuedSoundEffectCount(); - if (soundCount == lastSoundEffectCount + 1) - { - int soundIndex = soundCount - 1; - int packedLocation = client.getSoundLocations()[soundIndex]; - boolean consumed; - - if (packedLocation == 0) - { - // Regular sound effect - - 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 - { - // Area sound effect - - int x = (packedLocation >> 16) & 0xFF; - int y = (packedLocation >> 8) & 0xFF; - int range = (packedLocation) & 0xFF; - - 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; - } }