project: volumes support

This commit is contained in:
Owain van Brakel
2019-10-24 06:47:13 +02:00
parent 90b7775965
commit 45c0774093
18 changed files with 496 additions and 44 deletions

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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.music;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("music")
public interface MusicConfig extends Config
{
@ConfigItem(
keyName = "musicVolume",
name = "",
description = "",
hidden = true
)
default int getMusicVolume()
{
return 0;
}
@ConfigItem(
keyName = "musicVolume",
name = "",
description = "",
hidden = true
)
void setMusicVolume(int vol);
@ConfigItem(
keyName = "soundEffectVolume",
name = "",
description = "",
hidden = true
)
default int getSoundEffectVolume()
{
return 0;
}
@ConfigItem(
keyName = "soundEffectVolume",
name = "",
description = "",
hidden = true
)
void setSoundEffectVolume(int val);
@ConfigItem(
keyName = "areaSoundEffectVolume",
name = "",
description = "",
hidden = true
)
default int getAreaSoundEffectVolume()
{
return 0;
}
@ConfigItem(
keyName = "areaSoundEffectVolume",
name = "",
description = "",
hidden = true
)
void setAreaSoundEffectVolume(int vol);
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2019, Anthony Chen <https://github.com/achencoms>
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,33 +23,43 @@
* (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.musiclist;
package net.runelite.client.plugins.music;
import com.google.inject.Provides;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.function.BiConsumer;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
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.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.events.VarClientIntChanged;
import net.runelite.api.events.VolumeChanged;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.vars.InterfaceTab;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.game.chatbox.ChatboxTextInput;
@@ -56,11 +67,11 @@ import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@PluginDescriptor(
name = "Music List",
description = "Adds search and filter for the music list"
name = "Music",
description = "Adds search and filter for the music list, and additional volume control"
)
@Singleton
public class MusicListPlugin extends Plugin
@Slf4j
public class MusicPlugin extends Plugin
{
@Inject
private Client client;
@@ -68,6 +79,9 @@ public class MusicListPlugin extends Plugin
@Inject
private ClientThread clientThread;
@Inject
private MusicConfig musicConfig;
@Inject
private ChatboxPanelManager chatboxPanelManager;
@@ -88,14 +102,17 @@ public class MusicListPlugin extends Plugin
{
addSubscriptions();
clientThread.invoke(this::addMusicButtons);
clientThread.invoke(() ->
{
addMusicButtons();
applyMusicVolumeConfig();
updateMusicOptions();
});
}
@Override
protected void shutDown()
{
eventBus.unregister(this);
Widget header = client.getWidget(WidgetInfo.MUSIC_WINDOW);
if (header != null)
{
@@ -103,13 +120,24 @@ public class MusicListPlugin extends Plugin
}
tracks = null;
clientThread.invoke(this::teardownMusicOptions);
}
@Provides
MusicConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(MusicConfig.class);
}
private void addSubscriptions()
{
eventBus.subscribe(ConfigChanged.class, this, this::onConfigChanged);
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventBus.subscribe(WidgetLoaded.class, this, this::onWidgetLoaded);
eventBus.subscribe(VarClientIntChanged.class, this, this::onVarClientIntChanged);
eventBus.subscribe(VolumeChanged.class, this, this::onVolumeChanged);
eventBus.subscribe(ScriptCallbackEvent.class, this, this::onScriptCallbackEvent);
}
private void onGameStateChanged(GameStateChanged gameStateChanged)
@@ -132,6 +160,10 @@ public class MusicListPlugin extends Plugin
currentMusicFilter = MusicState.ALL;
addMusicButtons();
}
if (widgetLoaded.getGroupId() == WidgetID.OPTIONS_GROUP_ID)
{
updateMusicOptions();
}
}
private void addMusicButtons()
@@ -181,9 +213,48 @@ public class MusicListPlugin extends Plugin
}
}
private void onVolumeChanged(VolumeChanged volumeChanged)
{
applyMusicVolumeConfig();
}
private void onConfigChanged(ConfigChanged configChanged)
{
if (configChanged.getGroup().equals("music"))
{
clientThread.invokeLater(this::applyMusicVolumeConfig);
}
}
private void applyMusicVolumeConfig()
{
log.info("applyMusicVolumeConfig");
int musicVolume = musicConfig.getMusicVolume();
if (musicVolume > 0)
{
client.setMusicVolume(musicVolume - 1);
}
int soundEffectVolume = musicConfig.getSoundEffectVolume();
if (soundEffectVolume > 0)
{
client.setSoundEffectVolume(soundEffectVolume - 1);
}
int areaSoundEffectVolume = musicConfig.getAreaSoundEffectVolume();
if (areaSoundEffectVolume > 0)
{
client.setAreaSoundEffectVolume(areaSoundEffectVolume - 1);
}
updateMusicOptions();
}
private boolean isOnMusicTab()
{
return client.getVar(VarClientInt.INTERFACE_TAB) == InterfaceTab.MUSIC.getId();
return client.getVar(VarClientInt.INTERFACE_TAB) == 13;
}
private boolean isChatboxOpen()
@@ -304,4 +375,175 @@ public class MusicListPlugin extends Plugin
private final String name;
private final int spriteID;
}
}
@RequiredArgsConstructor
@Getter
private enum MusicSlider
{
MUSIC(WidgetInfo.OPTIONS_MUSIC_SLIDER, VarPlayer.MUSIC_VOLUME, MusicConfig::getMusicVolume, MusicConfig::setMusicVolume, 255),
AREA(WidgetInfo.OPTIONS_AREA_SOUND_SLIDER, VarPlayer.AREA_EFFECT_VOLUME, MusicConfig::getAreaSoundEffectVolume, MusicConfig::setAreaSoundEffectVolume, 127),
EFFECT(WidgetInfo.OPTIONS_SOUND_EFFECT_SLIDER, VarPlayer.SOUND_EFFECT_VOLUME, MusicConfig::getSoundEffectVolume, MusicConfig::setSoundEffectVolume, 127);
private final WidgetInfo widgetID;
private final VarPlayer var;
private final ToIntFunction<MusicConfig> getter;
private final BiConsumer<MusicConfig, Integer> setter;
private final int max;
@Setter
private Widget handle;
@Setter
private Widget track;
private static int PADDING = 8;
private int getX()
{
return getTrack().getRelativeX() + PADDING;
}
private int getWidth()
{
return getTrack().getWidth() - (PADDING * 2) - handle.getWidth();
}
}
private void teardownMusicOptions()
{
for (MusicSlider slider : MusicSlider.values())
{
Widget icon = client.getWidget(slider.getWidgetID());
if (icon == null)
{
return;
}
if (slider.getHandle() != null)
{
{
Widget handle = slider.getHandle();
Widget[] siblings = handle.getParent().getChildren();
if (siblings.length < handle.getIndex() || siblings[handle.getIndex()] != handle)
{
continue;
}
siblings[slider.getTrack().getIndex()] = null;
siblings[handle.getIndex()] = null;
}
Object[] init = icon.getOnLoadListener();
init[1] = slider.getWidgetID().getId();
// Readd the var transmit triggers and rerun options_allsounds
client.runScript(init);
slider.setHandle(null);
slider.setTrack(null);
}
}
}
private void updateMusicOptions()
{
for (MusicSlider slider : MusicSlider.values())
{
Widget icon = client.getWidget(slider.getWidgetID());
if (icon == null)
{
return;
}
Widget handle = slider.getHandle();
if (handle != null)
{
Widget[] siblings = handle.getParent().getChildren();
if (siblings.length < handle.getIndex() || siblings[handle.getIndex()] != handle)
{
handle = null;
}
}
if (handle == null)
{
Object[] init = icon.getOnLoadListener();
icon.setVarTransmitTrigger((int[]) null);
Widget track = icon.getParent().createChild(-1, WidgetType.TEXT);
slider.setTrack(track);
handle = icon.getParent().createChild(-1, WidgetType.GRAPHIC);
slider.setHandle(handle);
{
// First widget of the track
int wid = (Integer) init[2];
Widget w = client.getWidget(WidgetInfo.TO_GROUP(wid), WidgetInfo.TO_CHILD(wid));
track.setOriginalX(w.getRelativeX());
track.setOriginalY(w.getRelativeY());
}
{
// Last widget of the track
int wid = (Integer) init[6];
Widget w = client.getWidget(WidgetInfo.TO_GROUP(wid), WidgetInfo.TO_CHILD(wid));
track.setOriginalWidth((w.getRelativeX() + w.getWidth()) - track.getOriginalX());
}
track.setOriginalHeight(16);
track.setNoClickThrough(true);
track.revalidate();
handle.setSpriteId(SpriteID.OPTIONS_ZOOM_SLIDER_THUMB);
handle.setOriginalWidth(16);
handle.setOriginalHeight(16);
handle.setClickMask(WidgetConfig.DRAG);
JavaScriptCallback move = ev ->
{
int newVal = ((ev.getMouseX() - MusicSlider.PADDING - (slider.getHandle().getWidth() / 2)) * slider.getMax())
/ slider.getWidth();
if (newVal < 0)
{
newVal = 0;
}
if (newVal > slider.getMax())
{
newVal = slider.getMax();
}
// We store +1 so we can tell the difference between 0 and muted
slider.getSetter().accept(musicConfig, newVal + 1);
applyMusicVolumeConfig();
};
track.setOnClickListener(move);
track.setOnHoldListener(move);
track.setOnReleaseListener(move);
track.setHasListener(true);
client.runScript(ScriptID.OPTIONS_ALLSOUNDS, -1, init[2], init[3], init[4], init[5], init[6]);
}
int value = slider.getGetter().applyAsInt(musicConfig) - 1;
if (value <= -1)
{
// Use the vanilla value
value = ((4 - client.getVar(slider.getVar())) * slider.getMax()) / 4;
}
int newX = ((value * slider.getWidth()) / slider.getMax()) + slider.getX();
slider.getHandle().setOriginalX(newX);
slider.getHandle().setOriginalY(slider.getTrack().getOriginalY());
slider.getHandle().revalidate();
}
}
private void onScriptCallbackEvent(ScriptCallbackEvent ev)
{
switch (ev.getEventName())
{
case "optionsAllSounds":
// We have to override this script because it gets invoked periodically from the server
client.getIntStack()[client.getIntStackSize() - 1] = -1;
}
}
}