Merge pull request #3140 from Owain94/upstream-0903
project: Merge upstream
This commit is contained in:
@@ -25,9 +25,9 @@
|
||||
|
||||
object ProjectVersions {
|
||||
const val launcherVersion = "2.2.0"
|
||||
const val rlVersion = "1.8.12"
|
||||
const val rlVersion = "1.8.13"
|
||||
|
||||
const val openosrsVersion = "4.20.2"
|
||||
const val openosrsVersion = "4.20.3"
|
||||
|
||||
const val rsversion = 203
|
||||
const val cacheversion = 165
|
||||
|
||||
@@ -38,8 +38,8 @@ public class TextureDefinition
|
||||
public int[] field1780;
|
||||
public int[] field1781;
|
||||
public int[] field1786;
|
||||
public int field1782;
|
||||
public int field1783;
|
||||
public int animationSpeed;
|
||||
public int animationDirection;
|
||||
|
||||
public transient int[] pixels;
|
||||
|
||||
|
||||
@@ -26,13 +26,9 @@ package net.runelite.cache.definitions.loaders;
|
||||
|
||||
import net.runelite.cache.definitions.TextureDefinition;
|
||||
import net.runelite.cache.io.InputStream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TextureLoader
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(TextureLoader.class);
|
||||
|
||||
public TextureDefinition load(int id, byte[] b)
|
||||
{
|
||||
TextureDefinition def = new TextureDefinition();
|
||||
@@ -77,8 +73,8 @@ public class TextureLoader
|
||||
def.field1786[var3] = is.readInt();
|
||||
}
|
||||
|
||||
def.field1783 = is.readUnsignedByte();
|
||||
def.field1782 = is.readUnsignedByte();
|
||||
def.animationDirection = is.readUnsignedByte();
|
||||
def.animationSpeed = is.readUnsignedByte();
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
package net.runelite.cache.script.assembler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -267,7 +267,7 @@ public class ScriptWriter extends rs2asmBaseListener
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<Integer, Integer> map = maps[index++] = new HashMap<>();
|
||||
Map<Integer, Integer> map = maps[index++] = new LinkedHashMap<>();
|
||||
|
||||
for (LookupCase scase : lswitch.getCases())
|
||||
{
|
||||
|
||||
@@ -445,6 +445,20 @@ public interface Client extends GameEngine
|
||||
@Nullable
|
||||
SpritePixels createItemSprite(int itemId, int quantity, int border, int shadowColor, @MagicConstant(valuesFromClass = ItemQuantityMode.class) int stackable, boolean noted, int scale);
|
||||
|
||||
/**
|
||||
* Get the item model cache. These models are used for drawing widgets of type {@link net.runelite.api.widgets.WidgetType#MODEL}
|
||||
* and inventory item icons
|
||||
* @return
|
||||
*/
|
||||
NodeCache getItemModelCache();
|
||||
|
||||
/**
|
||||
* Get the item sprite cache. These are 2d SpritePixels which are used to raster item images on the inventory and
|
||||
* on widgets of type {@link net.runelite.api.widgets.WidgetType#GRAPHIC}
|
||||
* @return
|
||||
*/
|
||||
NodeCache getItemSpriteCache();
|
||||
|
||||
/**
|
||||
* Loads and creates the sprite images of the passed archive and file IDs.
|
||||
*
|
||||
@@ -2042,6 +2056,18 @@ public interface Client extends GameEngine
|
||||
*/
|
||||
void setSpellSelected(boolean selected);
|
||||
|
||||
/**
|
||||
* Get if an item is selected with "Use"
|
||||
* @return 1 if selected, else 0
|
||||
*/
|
||||
int getSelectedItem();
|
||||
|
||||
/**
|
||||
* If an item is selected, this is the item index in the inventory.
|
||||
* @return
|
||||
*/
|
||||
int getSelectedItemIndex();
|
||||
|
||||
/**
|
||||
* Returns client item composition cache
|
||||
*/
|
||||
|
||||
@@ -8,14 +8,15 @@ import javax.annotation.Nullable;
|
||||
public interface ItemComposition extends ParamHolder
|
||||
{
|
||||
/**
|
||||
* Gets the items name.
|
||||
* Gets the item's name.
|
||||
*
|
||||
* @return the name of the item
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Sets the items name.
|
||||
* Sets the item's name.
|
||||
* @param name the new name
|
||||
*/
|
||||
void setName(String name);
|
||||
|
||||
@@ -141,20 +142,109 @@ public interface ItemComposition extends ParamHolder
|
||||
int getInventoryModel();
|
||||
|
||||
/**
|
||||
* Since the client reuses item models, it stores colors that can be replaced.
|
||||
* This returns what colors the item model will be replaced with.
|
||||
*
|
||||
* Set the model ID of the inventory item. You will also need to flush the item model cache and the item
|
||||
* sprite cache to have the changes fully propagated after changing this value.
|
||||
* @see Client#getItemModelCache()
|
||||
* @see Client#getItemSpriteCache()
|
||||
*/
|
||||
void setInventoryModel(int model);
|
||||
|
||||
/**
|
||||
* Get the colors to be replaced on this item's model for this item.
|
||||
* @see JagexColor
|
||||
* @see ItemComposition#getColorToReplaceWith()
|
||||
* @return the colors to be replaced
|
||||
*/
|
||||
@Nullable
|
||||
short[] getColorToReplace();
|
||||
|
||||
/**
|
||||
* Set the colors to be replaced on this item's model for this item.
|
||||
* @see JagexColor
|
||||
* @see ItemComposition#setColorToReplaceWith(short[])
|
||||
*/
|
||||
void setColorToReplace(short[] colorsToReplace);
|
||||
|
||||
/**
|
||||
* Get the colors applied to this item's model for this item.
|
||||
* @see JagexColor
|
||||
* @see ItemComposition#getColorToReplace()
|
||||
* @return the colors to replace with
|
||||
*/
|
||||
@Nullable
|
||||
short[] getColorToReplaceWith();
|
||||
|
||||
/**
|
||||
* Since the client reuses item models, it stores textures that can be replaced.
|
||||
* This returns what textures the item model will be replaced with.
|
||||
*
|
||||
* Set the colors applied to this item's model for this item.
|
||||
* @see JagexColor
|
||||
* @see ItemComposition#setColorToReplace(short[])
|
||||
*/
|
||||
void setColorToReplaceWith(short[] colorToReplaceWith);
|
||||
|
||||
/**
|
||||
* Get the textures to be replaced on this item's model for this item.
|
||||
* @see ItemComposition#getTextureToReplaceWith()
|
||||
* @return the textures to be replaced
|
||||
*/
|
||||
@Nullable
|
||||
short[] getTextureToReplace();
|
||||
|
||||
/**
|
||||
* Set the textures to be replaced on this item's model for this item.
|
||||
* @see ItemComposition#setTextureToReplaceWith(short[])
|
||||
*/
|
||||
void setTextureToReplace(short[] textureToFind);
|
||||
|
||||
/**
|
||||
* Get the textures applied to this item's model for this item.
|
||||
* @see ItemComposition#getTextureToReplace()
|
||||
* @return the textures to replace with
|
||||
*/
|
||||
@Nullable
|
||||
short[] getTextureToReplaceWith();
|
||||
|
||||
/**
|
||||
* Set the textures applied to this item's model for this item.
|
||||
* @see ItemComposition#setTextureToReplace(short[])
|
||||
*/
|
||||
void setTextureToReplaceWith(short[] textureToReplaceWith);
|
||||
|
||||
/**
|
||||
* Get the x angle for 2d item sprites used in the inventory.
|
||||
* @see net.runelite.api.coords.Angle
|
||||
* @return
|
||||
*/
|
||||
int getXan2d();
|
||||
|
||||
/**
|
||||
* Get the y angle for 2d item sprites used in the inventory.
|
||||
* @see net.runelite.api.coords.Angle
|
||||
* @return
|
||||
*/
|
||||
int getYan2d();
|
||||
|
||||
/**
|
||||
* Get the z angle for 2d item sprites used in the inventory.
|
||||
* @see net.runelite.api.coords.Angle
|
||||
* @return
|
||||
*/
|
||||
int getZan2d();
|
||||
|
||||
/**
|
||||
* Set the x angle for 2d item sprites used in the inventory.
|
||||
* @see net.runelite.api.coords.Angle
|
||||
*/
|
||||
void setXan2d(int angle);
|
||||
|
||||
/**
|
||||
* Set the y angle for 2d item sprites used in the inventory.
|
||||
* @see net.runelite.api.coords.Angle
|
||||
*/
|
||||
void setYan2d(int angle);
|
||||
|
||||
/**
|
||||
* Set the z angle for 2d item sprites used in the inventory.
|
||||
* @see net.runelite.api.coords.Angle
|
||||
*/
|
||||
void setZan2d(int angle);
|
||||
}
|
||||
|
||||
@@ -48,8 +48,6 @@ public interface NPCComposition extends ParamHolder
|
||||
|
||||
boolean isClickable();
|
||||
|
||||
boolean isFollower();
|
||||
|
||||
/**
|
||||
* NPC can be interacting with via menu options
|
||||
* @return
|
||||
@@ -98,4 +96,11 @@ public interface NPCComposition extends ParamHolder
|
||||
* Gets the displayed overhead icon of the NPC.
|
||||
*/
|
||||
HeadIcon getOverheadIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the npc is a follower, such as a pet. Is affected by the
|
||||
* "Move follower options lower down" setting.
|
||||
* @return
|
||||
*/
|
||||
boolean isFollower();
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ public class RuneLite
|
||||
{
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
|
||||
final OptionParser parser = new OptionParser();
|
||||
final OptionParser parser = new OptionParser(false);
|
||||
parser.accepts("developer-mode", "Enable developer tools");
|
||||
parser.accepts("debug", "Show extra debugging output");
|
||||
parser.accepts("safe-mode", "Disables external plugins and the GPU plugin");
|
||||
@@ -389,6 +389,7 @@ public class RuneLite
|
||||
// Load the plugins, but does not start them yet.
|
||||
// This will initialize configuration
|
||||
pluginManager.loadCorePlugins();
|
||||
pluginManager.loadSideLoadPlugins();
|
||||
|
||||
oprsExternalPluginManager.loadPlugins();
|
||||
|
||||
|
||||
@@ -374,7 +374,27 @@ public class ConfigManager
|
||||
|
||||
public List<String> getConfigurationKeys(String prefix)
|
||||
{
|
||||
return properties.keySet().stream().filter(v -> ((String) v).startsWith(prefix)).map(String.class::cast).collect(Collectors.toList());
|
||||
return properties.keySet().stream()
|
||||
.map(String.class::cast)
|
||||
.filter(k -> k.startsWith(prefix))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<String> getRSProfileConfigurationKeys(String group, String profile, String keyPrefix)
|
||||
{
|
||||
if (profile == null)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
assert profile.startsWith(RSPROFILE_GROUP);
|
||||
|
||||
String prefix = group + "." + profile + "." + keyPrefix;
|
||||
return properties.keySet().stream()
|
||||
.map(String.class::cast)
|
||||
.filter(k -> k.startsWith(prefix))
|
||||
.map(k -> splitKey(k)[KEY_SPLITTER_KEY])
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static String getWholeKey(String groupName, String profile, String key)
|
||||
@@ -534,6 +554,8 @@ public class ConfigManager
|
||||
RuneScapeProfile prof = findRSProfile(getRSProfiles(), username, RuneScapeProfileType.getCurrent(client), displayName, true);
|
||||
rsProfileKey = prof.getKey();
|
||||
this.rsProfileKey = rsProfileKey;
|
||||
|
||||
eventBus.post(new RuneScapeProfileChanged());
|
||||
}
|
||||
setConfiguration(groupName, rsProfileKey, key, value);
|
||||
}
|
||||
@@ -982,7 +1004,10 @@ public class ConfigManager
|
||||
return methods;
|
||||
}
|
||||
|
||||
@Subscribe(priority = 100)
|
||||
@Subscribe(
|
||||
// run after plugins, in the event they save config on shutdown
|
||||
priority = -100
|
||||
)
|
||||
private void onClientShutdown(ClientShutdown e)
|
||||
{
|
||||
Future<Void> f = sendConfig();
|
||||
|
||||
@@ -38,5 +38,9 @@ import java.lang.annotation.Target;
|
||||
@Documented
|
||||
public @interface Subscribe
|
||||
{
|
||||
/**
|
||||
* Priority relative to other event subscribers. Higher priorities run first.
|
||||
* @return
|
||||
*/
|
||||
float priority() default 0;
|
||||
}
|
||||
|
||||
@@ -365,8 +365,7 @@ public class ItemManager
|
||||
{
|
||||
return wikiPrice;
|
||||
}
|
||||
int d = jagPrice - (int) (jagPrice * activePriceThreshold);
|
||||
return wikiPrice >= jagPrice - d && wikiPrice <= jagPrice + d ? wikiPrice : jagPrice;
|
||||
return wikiPrice < jagPrice * activePriceThreshold ? wikiPrice : jagPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
class PluginClassLoader extends URLClassLoader
|
||||
{
|
||||
private final ClassLoader parent;
|
||||
|
||||
PluginClassLoader(File plugin, ClassLoader parent) throws MalformedURLException
|
||||
{
|
||||
// null parent classloader, or else class path scanning includes everything from the main class loader
|
||||
super(new URL[]{plugin.toURI().toURL()}, null);
|
||||
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
try
|
||||
{
|
||||
return super.loadClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException ex)
|
||||
{
|
||||
// fall back to main class loader
|
||||
return parent.loadClass(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import com.google.inject.CreationException;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Module;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
@@ -89,6 +90,7 @@ public class PluginManager
|
||||
* Base package where the core plugins are
|
||||
*/
|
||||
private static final String PLUGIN_PACKAGE = "net.runelite.client.plugins";
|
||||
private static final File SIDELOADED_PLUGINS = new File(RuneLite.RUNELITE_DIR, "sideloaded-plugins");
|
||||
|
||||
private final boolean developerMode;
|
||||
private final boolean safeMode;
|
||||
@@ -309,6 +311,45 @@ public class PluginManager
|
||||
SplashScreen.stage(.60, .70, null, "Loading Plugins", loaded, total, false));
|
||||
}
|
||||
|
||||
public void loadSideLoadPlugins()
|
||||
{
|
||||
if (!developerMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
File[] files = SIDELOADED_PLUGINS.listFiles();
|
||||
if (files == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (File f : files)
|
||||
{
|
||||
if (f.getName().endsWith(".jar"))
|
||||
{
|
||||
log.info("Side-loading plugin {}", f);
|
||||
|
||||
try
|
||||
{
|
||||
ClassLoader classLoader = new PluginClassLoader(f, getClass().getClassLoader());
|
||||
|
||||
List<Class<?>> plugins = ClassPath.from(classLoader)
|
||||
.getAllClasses()
|
||||
.stream()
|
||||
.map(ClassInfo::load)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
loadPlugins(plugins, null);
|
||||
}
|
||||
catch (PluginInstantiationException | IOException ex)
|
||||
{
|
||||
log.error("error sideloading plugin", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Plugin> loadPlugins(List<Class<?>> plugins, BiConsumer<Integer, Integer> onPluginLoaded) throws PluginInstantiationException
|
||||
{
|
||||
MutableGraph<Class<? extends Plugin>> graph = GraphBuilder
|
||||
|
||||
@@ -153,7 +153,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc
|
||||
new CrypticClue("Search the crates in the Port Sarim Fishing shop.", CRATE_9534, new WorldPoint(3012, 3222, 0), "Search the crates, by the door, in Gerrant's Fishy Business in Port Sarim."),
|
||||
new CrypticClue("Speak to The Lady of the Lake.", "The Lady of the Lake", new WorldPoint(2924, 3405, 0), "Talk to The Lady of the Lake in Taverley."),
|
||||
new CrypticClue("Rotting next to a ditch. Dig next to the fish.", new WorldPoint(3547, 3183, 0), "Dig next to a fishing spot on the south-east side of Burgh de Rott."),
|
||||
new CrypticClue("The King's magic won't be wasted by me.", "Guardian Mummy", new WorldPoint(1934, 4427, 0), "Talk to the Guardian mummy inside the Pyramid Plunder minigame in Sophanem."),
|
||||
new CrypticClue("The King's magic won't be wasted by me.", "Guardian mummy", new WorldPoint(1934, 4427, 0), "Talk to the Guardian mummy inside the Pyramid Plunder minigame in Sophanem."),
|
||||
new CrypticClue("Dig where the forces of Zamorak and Saradomin collide.", new WorldPoint(3049, 4839, 0), "Dig next to the law rift in the Abyss."),
|
||||
new CrypticClue("Search the boxes in the goblin house near Lumbridge.", BOXES, new WorldPoint(3245, 3245, 0), "Goblin house on the eastern side of the river outside of Lumbridge."),
|
||||
new CrypticClue("W marks the spot.", new WorldPoint(2867, 3546, 0), "Dig in the middle of the Warriors' Guild entrance hall."),
|
||||
|
||||
@@ -223,7 +223,6 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
private int textureArrayId;
|
||||
|
||||
private final GLBuffer uniformBuffer = new GLBuffer();
|
||||
private final float[] textureOffsets = new float[256];
|
||||
|
||||
private GpuIntBuffer vertexBuffer;
|
||||
private GpuFloatBuffer uvBuffer;
|
||||
@@ -291,12 +290,13 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
private int uniTexTargetDimensions;
|
||||
private int uniUiAlphaOverlay;
|
||||
private int uniTextures;
|
||||
private int uniTextureOffsets;
|
||||
private int uniTextureAnimations;
|
||||
private int uniBlockSmall;
|
||||
private int uniBlockLarge;
|
||||
private int uniBlockMain;
|
||||
private int uniSmoothBanding;
|
||||
private int uniTextureLightMode;
|
||||
private int uniTick;
|
||||
|
||||
private int needsReset;
|
||||
|
||||
@@ -665,6 +665,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
uniDrawDistance = gl.glGetUniformLocation(glProgram, "drawDistance");
|
||||
uniColorBlindMode = gl.glGetUniformLocation(glProgram, "colorBlindMode");
|
||||
uniTextureLightMode = gl.glGetUniformLocation(glProgram, "textureLightMode");
|
||||
uniTick = gl.glGetUniformLocation(glProgram, "tick");
|
||||
|
||||
uniTex = gl.glGetUniformLocation(glUiProgram, "tex");
|
||||
uniTexSamplingMode = gl.glGetUniformLocation(glUiProgram, "samplingMode");
|
||||
@@ -673,7 +674,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
uniUiColorBlindMode = gl.glGetUniformLocation(glUiProgram, "colorBlindMode");
|
||||
uniUiAlphaOverlay = gl.glGetUniformLocation(glUiProgram, "alphaOverlay");
|
||||
uniTextures = gl.glGetUniformLocation(glProgram, "textures");
|
||||
uniTextureOffsets = gl.glGetUniformLocation(glProgram, "textureOffsets");
|
||||
uniTextureAnimations = gl.glGetUniformLocation(glProgram, "textureAnimations");
|
||||
|
||||
uniBlockSmall = gl.glGetUniformBlockIndex(glSmallComputeProgram, "uniforms");
|
||||
uniBlockLarge = gl.glGetUniformBlockIndex(glComputeProgram, "uniforms");
|
||||
@@ -1222,18 +1223,25 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
gl.glClear(gl.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Draw 3d scene
|
||||
final TextureProvider textureProvider = client.getTextureProvider();
|
||||
final GameState gameState = client.getGameState();
|
||||
if (textureProvider != null && gameState.getState() >= GameState.LOADING.getState())
|
||||
if (gameState.getState() >= GameState.LOADING.getState())
|
||||
{
|
||||
final TextureProvider textureProvider = client.getTextureProvider();
|
||||
if (textureArrayId == -1)
|
||||
{
|
||||
// lazy init textures as they may not be loaded at plugin start.
|
||||
// this will return -1 and retry if not all textures are loaded yet, too.
|
||||
textureArrayId = textureManager.initTextureArray(textureProvider, gl);
|
||||
if (textureArrayId > -1)
|
||||
{
|
||||
// if texture upload is successful, compute and set texture animations
|
||||
float[] texAnims = textureManager.computeTextureAnimations(textureProvider);
|
||||
gl.glUseProgram(glProgram);
|
||||
gl.glUniform2fv(uniTextureAnimations, texAnims.length, texAnims, 0);
|
||||
gl.glUseProgram(0);
|
||||
}
|
||||
}
|
||||
|
||||
final Texture[] textures = textureProvider.getTextures();
|
||||
int renderWidthOff = viewportOffsetX;
|
||||
int renderHeightOff = viewportOffsetY;
|
||||
int renderCanvasHeight = canvasHeight;
|
||||
@@ -1285,6 +1293,11 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
gl.glUniform1f(uniSmoothBanding, config.smoothBanding() ? 0f : 1f);
|
||||
gl.glUniform1i(uniColorBlindMode, config.colorBlindMode().ordinal());
|
||||
gl.glUniform1f(uniTextureLightMode, config.brightTextures() ? 1f : 0f);
|
||||
if (gameState == GameState.LOGGED_IN)
|
||||
{
|
||||
// avoid textures animating during loading
|
||||
gl.glUniform1i(uniTick, client.getGameCycle());
|
||||
}
|
||||
|
||||
// Calculate projection matrix
|
||||
Matrix4 projectionMatrix = new Matrix4();
|
||||
@@ -1295,24 +1308,9 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
projectionMatrix.translate(-client.getCameraX2(), -client.getCameraY2(), -client.getCameraZ2());
|
||||
gl.glUniformMatrix4fv(uniProjectionMatrix, 1, false, projectionMatrix.getMatrix(), 0);
|
||||
|
||||
for (int id = 0; id < textures.length; ++id)
|
||||
{
|
||||
Texture texture = textures[id];
|
||||
if (texture == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
textureProvider.load(id); // trips the texture load flag which lets textures animate
|
||||
|
||||
textureOffsets[id * 2] = texture.getU();
|
||||
textureOffsets[id * 2 + 1] = texture.getV();
|
||||
}
|
||||
|
||||
// Bind uniforms
|
||||
gl.glUniformBlockBinding(glProgram, uniBlockMain, 0);
|
||||
gl.glUniform1i(uniTextures, 1); // texture sampler array is bound to texture1
|
||||
gl.glUniform2fv(uniTextureOffsets, textureOffsets.length, textureOffsets, 0);
|
||||
|
||||
// We just allow the GL to do face culling. Note this requires the priority renderer
|
||||
// to have logic to disregard culled faces in the priority depth testing.
|
||||
@@ -1518,7 +1516,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
@Override
|
||||
public void animate(Texture texture, int diff)
|
||||
{
|
||||
textureManager.animate(texture, diff);
|
||||
// texture animation happens on gpu
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
||||
@@ -35,9 +35,6 @@ import net.runelite.api.TextureProvider;
|
||||
@Slf4j
|
||||
class TextureManager
|
||||
{
|
||||
private static final float PERC_64 = 1f / 64f;
|
||||
private static final float PERC_128 = 1f / 128f;
|
||||
|
||||
private static final int TEXTURE_SIZE = 128;
|
||||
|
||||
int initTextureArray(TextureProvider textureProvider, GL4 gl)
|
||||
@@ -207,64 +204,42 @@ class TextureManager
|
||||
return pixels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animate the given texture
|
||||
*
|
||||
* @param texture
|
||||
* @param diff Number of elapsed client ticks since last animation
|
||||
*/
|
||||
void animate(Texture texture, int diff)
|
||||
float[] computeTextureAnimations(TextureProvider textureProvider)
|
||||
{
|
||||
final int[] pixels = texture.getPixels();
|
||||
if (pixels == null)
|
||||
Texture[] textures = textureProvider.getTextures();
|
||||
float[] anims = new float[TEXTURE_SIZE * 2];
|
||||
for (int i = 0; i < textures.length; ++i)
|
||||
{
|
||||
return;
|
||||
Texture texture = textures[i];
|
||||
if (texture == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float u = 0f, v = 0f;
|
||||
switch (texture.getAnimationDirection())
|
||||
{
|
||||
case 1:
|
||||
v = -1f;
|
||||
break;
|
||||
case 3:
|
||||
v = 1f;
|
||||
break;
|
||||
case 2:
|
||||
u = -1f;
|
||||
break;
|
||||
case 4:
|
||||
u = 1f;
|
||||
break;
|
||||
}
|
||||
|
||||
int speed = texture.getAnimationSpeed();
|
||||
u *= speed;
|
||||
v *= speed;
|
||||
|
||||
anims[i * 2] = u;
|
||||
anims[i * 2 + 1] = v;
|
||||
}
|
||||
|
||||
final int animationSpeed = texture.getAnimationSpeed();
|
||||
final float uvdiff = pixels.length == 4096 ? PERC_64 : PERC_128;
|
||||
|
||||
float u = texture.getU();
|
||||
float v = texture.getV();
|
||||
|
||||
int offset = animationSpeed * diff;
|
||||
float d = (float) offset * uvdiff;
|
||||
|
||||
switch (texture.getAnimationDirection())
|
||||
{
|
||||
case 1:
|
||||
v -= d;
|
||||
if (v < 0f)
|
||||
{
|
||||
v += 1f;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
v += d;
|
||||
if (v > 1f)
|
||||
{
|
||||
v -= 1f;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
u -= d;
|
||||
if (u < 0f)
|
||||
{
|
||||
u += 1f;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
u += d;
|
||||
if (u > 1f)
|
||||
{
|
||||
u -= 1f;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
texture.setU(u);
|
||||
texture.setV(v);
|
||||
return anims;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,8 @@ import net.runelite.client.plugins.PluginDescriptor;
|
||||
@PluginDescriptor(
|
||||
name = "Idle Notifier",
|
||||
description = "Send a notification when going idle, or when HP/Prayer reaches a threshold",
|
||||
tags = {"health", "hitpoints", "notifications", "prayer"}
|
||||
tags = {"health", "hitpoints", "notifications", "prayer"},
|
||||
enabledByDefault = false
|
||||
)
|
||||
public class IdleNotifierPlugin extends Plugin
|
||||
{
|
||||
|
||||
@@ -317,6 +317,10 @@ enum ItemIdentification
|
||||
FISHING(Type.POTION, "Fishing", "Fi", ItemID.FISHING_POTION4, ItemID.FISHING_POTION3, ItemID.FISHING_POTION2, ItemID.FISHING_POTION1),
|
||||
HUNTER(Type.POTION, "Hunter", "Hu", ItemID.HUNTER_POTION4, ItemID.HUNTER_POTION3, ItemID.HUNTER_POTION2, ItemID.HUNTER_POTION1),
|
||||
|
||||
GOBLIN(Type.POTION, "Goblin", "G", ItemID.GOBLIN_POTION4, ItemID.GOBLIN_POTION3, ItemID.GOBLIN_POTION2, ItemID.GOBLIN_POTION1),
|
||||
MAGIC_ESS(Type.POTION, "MagEss", "M.E", ItemID.MAGIC_ESSENCE4, ItemID.MAGIC_ESSENCE3, ItemID.MAGIC_ESSENCE2, ItemID.MAGIC_ESSENCE1),
|
||||
REJUVENATION(Type.POTION, "Rejuv", "Rj", ItemID.REJUVENATION_POTION_4, ItemID.REJUVENATION_POTION_3, ItemID.REJUVENATION_POTION_2, ItemID.REJUVENATION_POTION_1),
|
||||
|
||||
// Unfinished Potions
|
||||
GUAM_POTION(Type.POTION, "Guam", "G", ItemID.GUAM_POTION_UNF),
|
||||
MARRENTILL_POTION(Type.POTION, "Marren", "M", ItemID.MARRENTILL_POTION_UNF),
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.loottracker;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.runelite.http.api.loottracker.LootRecordType;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = {"type", "name"})
|
||||
class ConfigLoot
|
||||
{
|
||||
LootRecordType type;
|
||||
String name;
|
||||
int kills;
|
||||
Instant first = Instant.now();
|
||||
Instant last;
|
||||
int[] drops;
|
||||
|
||||
ConfigLoot(LootRecordType type, String name)
|
||||
{
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.drops = new int[0];
|
||||
}
|
||||
|
||||
void add(int id, int qty)
|
||||
{
|
||||
for (int i = 0; i < drops.length; i += 2)
|
||||
{
|
||||
if (drops[i] == id)
|
||||
{
|
||||
drops[i + 1] += qty;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
drops = Arrays.copyOf(drops, drops.length + 2);
|
||||
drops[drops.length - 2] = id;
|
||||
drops[drops.length - 1] = qty;
|
||||
}
|
||||
|
||||
int numDrops()
|
||||
{
|
||||
return drops.length / 2;
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,7 @@ class LootTrackerBox extends JPanel
|
||||
private final ItemManager itemManager;
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final String id;
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final LootRecordType lootRecordType;
|
||||
private final LootTrackerPriceType priceType;
|
||||
private final boolean showPriceType;
|
||||
@@ -316,6 +317,7 @@ class LootTrackerBox extends JPanel
|
||||
itemContainer.removeAll();
|
||||
itemContainer.setLayout(new GridLayout(rowSize, ITEMS_PER_ROW, 1, 1));
|
||||
|
||||
final EmptyBorder emptyBorder = new EmptyBorder(5, 5, 5, 5);
|
||||
for (int i = 0; i < rowSize * ITEMS_PER_ROW; i++)
|
||||
{
|
||||
final JPanel slotContainer = new JPanel();
|
||||
@@ -350,7 +352,7 @@ class LootTrackerBox extends JPanel
|
||||
|
||||
// Create popup menu
|
||||
final JPopupMenu popupMenu = new JPopupMenu();
|
||||
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
popupMenu.setBorder(emptyBorder);
|
||||
slotContainer.setComponentPopupMenu(popupMenu);
|
||||
|
||||
final JMenuItem toggle = new JMenuItem("Toggle item");
|
||||
|
||||
@@ -30,9 +30,11 @@ import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
import net.runelite.client.config.ConfigSection;
|
||||
|
||||
@ConfigGroup("loottracker")
|
||||
@ConfigGroup(LootTrackerConfig.GROUP)
|
||||
public interface LootTrackerConfig extends Config
|
||||
{
|
||||
String GROUP = "loottracker";
|
||||
|
||||
@ConfigSection(
|
||||
name = "Ignored Entries",
|
||||
description = "The Ignore items and Ignore groups options",
|
||||
@@ -79,28 +81,6 @@ public interface LootTrackerConfig extends Config
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "saveLoot",
|
||||
name = "Submit loot tracker data",
|
||||
description = "Submit loot tracker data"
|
||||
)
|
||||
default boolean saveLoot()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "syncPanel",
|
||||
name = "Synchronize panel contents",
|
||||
description = "Synchronize your local loot tracker with your server data (requires being signed in).<br/>" +
|
||||
" This means the panel is filled with portions of your remote data on startup<br/>" +
|
||||
" and deleting data in the panel also deletes it on the server."
|
||||
)
|
||||
default boolean syncPanel()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "ignoredEvents",
|
||||
name = "Ignored Loot Sources",
|
||||
|
||||
@@ -87,10 +87,12 @@ class LootTrackerPanel extends PluginPanel
|
||||
|
||||
private static final String HTML_LABEL_TEMPLATE =
|
||||
"<html><body style='color:%s'>%s<span style='color:white'>%s</span></body></html>";
|
||||
private static final String SYNC_RESET_ALL_WARNING_TEXT =
|
||||
"This will permanently delete the current loot from both the client and the RuneLite website.";
|
||||
private static final String NO_SYNC_RESET_ALL_WARNING_TEXT =
|
||||
"This will permanently delete the current loot from the client.";
|
||||
private static final String RESET_ALL_WARNING_TEXT =
|
||||
"<html>This will permanently delete <b>all</b> loot.</html>";
|
||||
private static final String RESET_CURRENT_WARNING_TEXT =
|
||||
"This will permanently delete \"%s\" loot.";
|
||||
private static final String RESET_ONE_WARNING_TEXT =
|
||||
"This will delete one kill.";
|
||||
|
||||
// When there is no loot, display this
|
||||
private final PluginErrorPanel errorPanel = new PluginErrorPanel();
|
||||
@@ -99,13 +101,13 @@ class LootTrackerPanel extends PluginPanel
|
||||
private final JPanel logsContainer = new JPanel();
|
||||
|
||||
// Handle overall session data
|
||||
private final JPanel overallPanel = new JPanel();
|
||||
private final JPanel overallPanel;
|
||||
private final JLabel overallKillsLabel = new JLabel();
|
||||
private final JLabel overallGpLabel = new JLabel();
|
||||
private final JLabel overallIcon = new JLabel();
|
||||
|
||||
// Details and navigation
|
||||
private final JPanel actionsContainer = new JPanel();
|
||||
private final JPanel actionsPanel;
|
||||
private final JLabel detailsTitle = new JLabel();
|
||||
private final JButton backBtn = new JButton();
|
||||
private final JToggleButton viewHiddenBtn = new JToggleButton();
|
||||
@@ -175,6 +177,28 @@ class LootTrackerPanel extends PluginPanel
|
||||
layoutPanel.setLayout(new BoxLayout(layoutPanel, BoxLayout.Y_AXIS));
|
||||
add(layoutPanel, BorderLayout.NORTH);
|
||||
|
||||
actionsPanel = buildActionsPanel();
|
||||
overallPanel = buildOverallPanel();
|
||||
|
||||
// Create loot boxes wrapper
|
||||
logsContainer.setLayout(new BoxLayout(logsContainer, BoxLayout.Y_AXIS));
|
||||
layoutPanel.add(actionsPanel);
|
||||
layoutPanel.add(overallPanel);
|
||||
layoutPanel.add(logsContainer);
|
||||
|
||||
// Add error pane
|
||||
errorPanel.setContent("Loot tracker", "You have not received any loot yet.");
|
||||
add(errorPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* The actions panel includes the back/title label for the current view,
|
||||
* as well as the view controls panel which includes hidden, single/grouped, and
|
||||
* collapse buttons.
|
||||
*/
|
||||
private JPanel buildActionsPanel()
|
||||
{
|
||||
final JPanel actionsContainer = new JPanel();
|
||||
actionsContainer.setLayout(new BorderLayout());
|
||||
actionsContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
actionsContainer.setPreferredSize(new Dimension(0, 30));
|
||||
@@ -252,7 +276,13 @@ class LootTrackerPanel extends PluginPanel
|
||||
actionsContainer.add(viewControls, BorderLayout.EAST);
|
||||
actionsContainer.add(leftTitleContainer, BorderLayout.WEST);
|
||||
|
||||
return actionsContainer;
|
||||
}
|
||||
|
||||
private JPanel buildOverallPanel()
|
||||
{
|
||||
// Create panel that will contain overall data
|
||||
final JPanel overallPanel = new JPanel();
|
||||
overallPanel.setBorder(BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createMatteBorder(5, 0, 0, 0, ColorScheme.DARK_GRAY_COLOR),
|
||||
BorderFactory.createEmptyBorder(8, 10, 8, 10)
|
||||
@@ -277,10 +307,8 @@ class LootTrackerPanel extends PluginPanel
|
||||
final JMenuItem reset = new JMenuItem("Reset All");
|
||||
reset.addActionListener(e ->
|
||||
{
|
||||
final LootTrackerClient client = plugin.getLootTrackerClient();
|
||||
final boolean syncLoot = client.getUuid() != null && config.syncPanel();
|
||||
final int result = JOptionPane.showOptionDialog(overallPanel,
|
||||
syncLoot ? SYNC_RESET_ALL_WARNING_TEXT : NO_SYNC_RESET_ALL_WARNING_TEXT,
|
||||
currentView == null ? RESET_ALL_WARNING_TEXT : String.format(RESET_CURRENT_WARNING_TEXT, currentView),
|
||||
"Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
|
||||
null, new String[]{"Yes", "No"}, "No");
|
||||
|
||||
@@ -298,9 +326,14 @@ class LootTrackerPanel extends PluginPanel
|
||||
logsContainer.repaint();
|
||||
|
||||
// Delete all loot, or loot matching the current view
|
||||
if (syncLoot)
|
||||
if (currentView != null)
|
||||
{
|
||||
client.delete(currentView);
|
||||
assert currentType != null;
|
||||
plugin.removeLootConfig(currentType, currentView);
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin.removeAllLoot();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -310,15 +343,7 @@ class LootTrackerPanel extends PluginPanel
|
||||
popupMenu.add(reset);
|
||||
overallPanel.setComponentPopupMenu(popupMenu);
|
||||
|
||||
// Create loot boxes wrapper
|
||||
logsContainer.setLayout(new BoxLayout(logsContainer, BoxLayout.Y_AXIS));
|
||||
layoutPanel.add(actionsContainer);
|
||||
layoutPanel.add(overallPanel);
|
||||
layoutPanel.add(logsContainer);
|
||||
|
||||
// Add error pane
|
||||
errorPanel.setContent("Loot tracker", "You have not received any loot yet.");
|
||||
add(errorPanel);
|
||||
return overallPanel;
|
||||
}
|
||||
|
||||
void updateCollapseText()
|
||||
@@ -370,6 +395,14 @@ class LootTrackerPanel extends PluginPanel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all records in the panel
|
||||
*/
|
||||
void clearRecords()
|
||||
{
|
||||
aggregateRecords.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Collection of records to the panel
|
||||
*/
|
||||
@@ -511,7 +544,7 @@ class LootTrackerPanel extends PluginPanel
|
||||
|
||||
// Show main view
|
||||
remove(errorPanel);
|
||||
actionsContainer.setVisible(true);
|
||||
actionsPanel.setVisible(true);
|
||||
overallPanel.setVisible(true);
|
||||
|
||||
// Create box
|
||||
@@ -553,10 +586,8 @@ class LootTrackerPanel extends PluginPanel
|
||||
final JMenuItem reset = new JMenuItem("Reset");
|
||||
reset.addActionListener(e ->
|
||||
{
|
||||
final LootTrackerClient client = plugin.getLootTrackerClient();
|
||||
final boolean syncLoot = client.getUuid() != null && config.syncPanel();
|
||||
final int result = JOptionPane.showOptionDialog(overallPanel,
|
||||
syncLoot ? SYNC_RESET_ALL_WARNING_TEXT : NO_SYNC_RESET_ALL_WARNING_TEXT,
|
||||
final int result = JOptionPane.showOptionDialog(box,
|
||||
groupLoot ? String.format(RESET_CURRENT_WARNING_TEXT, box.getId()) : RESET_ONE_WARNING_TEXT,
|
||||
"Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
|
||||
null, new String[]{"Yes", "No"}, "No");
|
||||
|
||||
@@ -578,9 +609,9 @@ class LootTrackerPanel extends PluginPanel
|
||||
logsContainer.repaint();
|
||||
|
||||
// Without loot being grouped we have no way to identify single kills to be deleted
|
||||
if (client.getUuid() != null && groupLoot && config.syncPanel())
|
||||
if (groupLoot)
|
||||
{
|
||||
client.delete(box.getId());
|
||||
plugin.removeLootConfig(box.getLootRecordType(), box.getId());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
package net.runelite.client.plugins.loottracker;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
@@ -33,9 +34,11 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.common.collect.Multisets;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.inject.Provides;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
@@ -43,6 +46,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -96,6 +100,7 @@ import net.runelite.client.events.ClientShutdown;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.client.events.NpcLootReceived;
|
||||
import net.runelite.client.events.PlayerLootReceived;
|
||||
import net.runelite.client.events.RuneScapeProfileChanged;
|
||||
import net.runelite.client.events.SessionClose;
|
||||
import net.runelite.client.events.SessionOpen;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
@@ -119,12 +124,14 @@ import org.apache.commons.text.WordUtils;
|
||||
@PluginDescriptor(
|
||||
name = "Loot Tracker",
|
||||
description = "Tracks loot from monsters and minigames",
|
||||
tags = {"drops"},
|
||||
enabledByDefault = false
|
||||
tags = {"drops"}
|
||||
)
|
||||
@Slf4j
|
||||
public class LootTrackerPlugin extends Plugin
|
||||
{
|
||||
private static final int MAX_DROPS = 1024;
|
||||
private static final Duration MAX_AGE = Duration.ofDays(365L);
|
||||
|
||||
// Activity/Event loot handling
|
||||
private static final Pattern CLUE_SCROLL_PATTERN = Pattern.compile("You have completed [0-9]+ ([a-z]+) Treasure Trails?\\.");
|
||||
private static final int THEATRE_OF_BLOOD_REGION = 12867;
|
||||
@@ -291,6 +298,12 @@ public class LootTrackerPlugin extends Plugin
|
||||
@Inject
|
||||
private LootManager lootManager;
|
||||
|
||||
@Inject
|
||||
private ConfigManager configManager;
|
||||
|
||||
@Inject
|
||||
private Gson gson;
|
||||
|
||||
private LootTrackerPanel panel;
|
||||
private NavigationButton navButton;
|
||||
@VisibleForTesting
|
||||
@@ -310,6 +323,8 @@ public class LootTrackerPlugin extends Plugin
|
||||
@Inject
|
||||
private LootTrackerClient lootTrackerClient;
|
||||
private final List<LootRecord> queuedLoots = new ArrayList<>();
|
||||
private String profileKey;
|
||||
private Instant lastLootImport = Instant.now().minus(1, ChronoUnit.MINUTES);
|
||||
|
||||
private static Collection<ItemStack> stack(Collection<ItemStack> items)
|
||||
{
|
||||
@@ -367,20 +382,118 @@ public class LootTrackerPlugin extends Plugin
|
||||
lootTrackerClient.setUuid(null);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onRuneScapeProfileChanged(RuneScapeProfileChanged e)
|
||||
{
|
||||
final String profileKey = configManager.getRSProfileKey();
|
||||
if (profileKey == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (profileKey.equals(this.profileKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Profile changed to {}", profileKey);
|
||||
switchProfile(profileKey);
|
||||
}
|
||||
|
||||
private void switchProfile(String profileKey)
|
||||
{
|
||||
executor.execute(() ->
|
||||
{
|
||||
// Current queued loot is for the previous profile, so save it first with the current profile key
|
||||
submitLoot();
|
||||
|
||||
this.profileKey = profileKey;
|
||||
|
||||
log.debug("Switched to profile {}", profileKey);
|
||||
|
||||
int drops = 0;
|
||||
List<ConfigLoot> loots = new ArrayList<>();
|
||||
Instant old = Instant.now().minus(MAX_AGE);
|
||||
for (String key : configManager.getRSProfileConfigurationKeys(LootTrackerConfig.GROUP, profileKey, "drops_"))
|
||||
{
|
||||
String json = configManager.getConfiguration(LootTrackerConfig.GROUP, profileKey, key);
|
||||
ConfigLoot configLoot;
|
||||
|
||||
try
|
||||
{
|
||||
configLoot = gson.fromJson(json, ConfigLoot.class);
|
||||
}
|
||||
catch (JsonSyntaxException ex)
|
||||
{
|
||||
log.warn("Removing loot with malformed json: {}", json, ex);
|
||||
configManager.unsetConfiguration(LootTrackerConfig.GROUP, profileKey, key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (configLoot.last.isBefore(old))
|
||||
{
|
||||
log.debug("Removing old loot for {} {}", configLoot.type, configLoot.name);
|
||||
configManager.unsetConfiguration(LootTrackerConfig.GROUP, profileKey, key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (drops >= MAX_DROPS && !loots.isEmpty() && loots.get(0).last.isAfter(configLoot.last))
|
||||
{
|
||||
// fast drop
|
||||
continue;
|
||||
}
|
||||
|
||||
sortedInsert(loots, configLoot, Comparator.comparing(ConfigLoot::getLast));
|
||||
drops += configLoot.numDrops();
|
||||
|
||||
if (drops >= MAX_DROPS)
|
||||
{
|
||||
ConfigLoot top = loots.remove(0);
|
||||
drops -= top.numDrops();
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("Loaded {} records", loots.size());
|
||||
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
// convertToLootTrackerRecord must be called on client thread
|
||||
List<LootTrackerRecord> records = loots.stream()
|
||||
.map(this::convertToLootTrackerRecord)
|
||||
.collect(Collectors.toList());
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
panel.clearRecords();
|
||||
panel.addRecords(records);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static <T> void sortedInsert(List<T> list, T value, Comparator<? super T> c)
|
||||
{
|
||||
int idx = Collections.binarySearch(list, value, c);
|
||||
list.add(idx < 0 ? -idx - 1 : idx, value);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onConfigChanged(ConfigChanged event)
|
||||
{
|
||||
if (event.getGroup().equals("loottracker"))
|
||||
if (event.getGroup().equals(LootTrackerConfig.GROUP))
|
||||
{
|
||||
ignoredItems = Text.fromCSV(config.getIgnoredItems());
|
||||
ignoredEvents = Text.fromCSV(config.getIgnoredEvents());
|
||||
SwingUtilities.invokeLater(panel::updateIgnoredRecords);
|
||||
if ("ignoredItems".equals(event.getKey()) || "ignoredEvents".equals(event.getKey()))
|
||||
{
|
||||
ignoredItems = Text.fromCSV(config.getIgnoredItems());
|
||||
ignoredEvents = Text.fromCSV(config.getIgnoredEvents());
|
||||
SwingUtilities.invokeLater(panel::updateIgnoredRecords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
profileKey = null;
|
||||
ignoredItems = Text.fromCSV(config.getIgnoredItems());
|
||||
ignoredEvents = Text.fromCSV(config.getIgnoredEvents());
|
||||
panel = new LootTrackerPanel(this, itemManager, config);
|
||||
@@ -401,44 +514,12 @@ public class LootTrackerPlugin extends Plugin
|
||||
if (accountSession != null)
|
||||
{
|
||||
lootTrackerClient.setUuid(accountSession.getUuid());
|
||||
}
|
||||
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
switch (client.getGameState())
|
||||
{
|
||||
case STARTING:
|
||||
case UNKNOWN:
|
||||
return false;
|
||||
}
|
||||
|
||||
executor.submit(() ->
|
||||
{
|
||||
if (!config.syncPanel())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<LootAggregate> lootRecords;
|
||||
try
|
||||
{
|
||||
lootRecords = lootTrackerClient.get();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.debug("Unable to look up loot", e);
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Loaded {} data entries", lootRecords.size());
|
||||
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
Collection<LootTrackerRecord> records = convertToLootTrackerRecord(lootRecords);
|
||||
SwingUtilities.invokeLater(() -> panel.addRecords(records));
|
||||
});
|
||||
});
|
||||
return true;
|
||||
});
|
||||
String profileKey = configManager.getRSProfileKey();
|
||||
if (profileKey != null)
|
||||
{
|
||||
switchProfile(profileKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,13 +556,10 @@ public class LootTrackerPlugin extends Plugin
|
||||
final LootTrackerItem[] entries = buildEntries(stack(items));
|
||||
SwingUtilities.invokeLater(() -> panel.add(name, type, combatLevel, entries));
|
||||
|
||||
if (config.saveLoot())
|
||||
LootRecord lootRecord = new LootRecord(name, type, metadata, toGameItems(items), Instant.now(), getLootWorldId());
|
||||
synchronized (queuedLoots)
|
||||
{
|
||||
LootRecord lootRecord = new LootRecord(name, type, metadata, toGameItems(items), Instant.now(), getLootWorldId());
|
||||
synchronized (queuedLoots)
|
||||
{
|
||||
queuedLoots.add(lootRecord);
|
||||
}
|
||||
queuedLoots.add(lootRecord);
|
||||
}
|
||||
|
||||
eventBus.post(new LootReceived(name, combatLevel, type, items));
|
||||
@@ -932,16 +1010,53 @@ public class LootTrackerPlugin extends Plugin
|
||||
queuedLoots.clear();
|
||||
}
|
||||
|
||||
if (!config.saveLoot())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
saveLoot(copy);
|
||||
|
||||
log.debug("Submitting {} loot records", copy.size());
|
||||
|
||||
return lootTrackerClient.submit(copy);
|
||||
}
|
||||
|
||||
private Collection<ConfigLoot> combine(List<LootRecord> records)
|
||||
{
|
||||
Map<ConfigLoot, ConfigLoot> map = new HashMap<>();
|
||||
for (LootRecord record : records)
|
||||
{
|
||||
ConfigLoot key = new ConfigLoot(record.getType(), record.getEventId());
|
||||
ConfigLoot loot = map.computeIfAbsent(key, k -> key);
|
||||
loot.kills++;
|
||||
for (GameItem item : record.getDrops())
|
||||
{
|
||||
loot.add(item.getId(), item.getQty());
|
||||
}
|
||||
}
|
||||
return map.values();
|
||||
}
|
||||
|
||||
private void saveLoot(List<LootRecord> records)
|
||||
{
|
||||
Instant now = Instant.now();
|
||||
Collection<ConfigLoot> combinedRecords = combine(records);
|
||||
for (ConfigLoot record : combinedRecords)
|
||||
{
|
||||
ConfigLoot lootConfig = getLootConfig(record.type, record.name);
|
||||
if (lootConfig == null)
|
||||
{
|
||||
lootConfig = record;
|
||||
}
|
||||
else
|
||||
{
|
||||
lootConfig.kills += record.kills;
|
||||
for (int i = 0; i < record.drops.length; i += 2)
|
||||
{
|
||||
lootConfig.add(record.drops[i], record.drops[i + 1]);
|
||||
}
|
||||
}
|
||||
lootConfig.last = now;
|
||||
setLootConfig(lootConfig.type, lootConfig.name, lootConfig);
|
||||
}
|
||||
}
|
||||
|
||||
private void setEvent(LootRecordType lootRecordType, String eventType, Object metadata)
|
||||
{
|
||||
this.lootRecordType = lootRecordType;
|
||||
@@ -1113,6 +1228,18 @@ public class LootTrackerPlugin extends Plugin
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
private LootTrackerRecord convertToLootTrackerRecord(final ConfigLoot configLoot)
|
||||
{
|
||||
LootTrackerItem[] items = new LootTrackerItem[configLoot.drops.length / 2];
|
||||
for (int i = 0; i < configLoot.drops.length; i += 2)
|
||||
{
|
||||
int id = configLoot.drops[i];
|
||||
int qty = configLoot.drops[i + 1];
|
||||
items[i >> 1] = buildLootTrackerItem(id, qty);
|
||||
}
|
||||
return new LootTrackerRecord(configLoot.name, "", configLoot.type, items, configLoot.kills);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is player currently within the provided map regions
|
||||
*/
|
||||
@@ -1131,26 +1258,18 @@ public class LootTrackerPlugin extends Plugin
|
||||
return false;
|
||||
}
|
||||
|
||||
private long getTotalPrice(Collection<ItemStack> items)
|
||||
{
|
||||
long totalPrice = 0;
|
||||
|
||||
for (final ItemStack itemStack : items)
|
||||
{
|
||||
totalPrice += (long) itemManager.getItemPrice(itemStack.getId()) * itemStack.getQuantity();
|
||||
}
|
||||
|
||||
return totalPrice;
|
||||
}
|
||||
|
||||
private void lootReceivedChatMessage(final Collection<ItemStack> items, final String name)
|
||||
{
|
||||
long totalPrice = items.stream()
|
||||
.mapToLong(is -> (long) itemManager.getItemPrice(is.getId()) * is.getQuantity())
|
||||
.sum();
|
||||
|
||||
final String message = new ChatMessageBuilder()
|
||||
.append(ChatColorType.HIGHLIGHT)
|
||||
.append("You've killed ")
|
||||
.append(name)
|
||||
.append(" for ")
|
||||
.append(QuantityFormatter.quantityToStackSize(getTotalPrice(items)))
|
||||
.append(QuantityFormatter.quantityToStackSize(totalPrice))
|
||||
.append(" loot.")
|
||||
.build();
|
||||
|
||||
@@ -1160,4 +1279,62 @@ public class LootTrackerPlugin extends Plugin
|
||||
.runeLiteFormattedMessage(message)
|
||||
.build());
|
||||
}
|
||||
|
||||
ConfigLoot getLootConfig(LootRecordType type, String name)
|
||||
{
|
||||
String profile = profileKey;
|
||||
if (Strings.isNullOrEmpty(profile))
|
||||
{
|
||||
log.debug("Trying to get loot with no profile!");
|
||||
return null;
|
||||
}
|
||||
|
||||
String json = configManager.getConfiguration(LootTrackerConfig.GROUP, profile, "drops_" + type + "_" + name);
|
||||
if (json == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return gson.fromJson(json, ConfigLoot.class);
|
||||
}
|
||||
|
||||
void setLootConfig(LootRecordType type, String name, ConfigLoot loot)
|
||||
{
|
||||
String profile = profileKey;
|
||||
if (Strings.isNullOrEmpty(profile))
|
||||
{
|
||||
log.debug("Trying to set loot with no profile!");
|
||||
return;
|
||||
}
|
||||
|
||||
String json = gson.toJson(loot);
|
||||
configManager.setConfiguration(LootTrackerConfig.GROUP, profile, "drops_" + type + "_" + name, json);
|
||||
}
|
||||
|
||||
void removeLootConfig(LootRecordType type, String name)
|
||||
{
|
||||
String profile = profileKey;
|
||||
if (Strings.isNullOrEmpty(profile))
|
||||
{
|
||||
log.debug("Trying to remove loot with no profile!");
|
||||
return;
|
||||
}
|
||||
|
||||
configManager.unsetConfiguration(LootTrackerConfig.GROUP, profile, "drops_" + type + "_" + name);
|
||||
}
|
||||
|
||||
void removeAllLoot()
|
||||
{
|
||||
String profile = profileKey;
|
||||
if (Strings.isNullOrEmpty(profile))
|
||||
{
|
||||
log.debug("Trying to clear loot with no profile!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (String key : configManager.getRSProfileConfigurationKeys(LootTrackerConfig.GROUP, profile, "drops_"))
|
||||
{
|
||||
configManager.unsetConfiguration(LootTrackerConfig.GROUP, profile, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ public class SlayerPlugin extends Plugin
|
||||
private int cachedXp = -1;
|
||||
private Instant infoTimer;
|
||||
private boolean loginFlag;
|
||||
private final List<String> targetNames = new ArrayList<>();
|
||||
private final List<Pattern> targetNames = new ArrayList<>();
|
||||
|
||||
public final Function<NPC, HighlightedNpc> isTarget = (n) ->
|
||||
{
|
||||
@@ -664,7 +664,8 @@ public class SlayerPlugin extends Plugin
|
||||
SlayerUnlock.GROTESQUE_GUARDIAN_DOUBLE_COUNT.isEnabled(client);
|
||||
}
|
||||
|
||||
private boolean isTarget(NPC npc)
|
||||
@VisibleForTesting
|
||||
boolean isTarget(NPC npc)
|
||||
{
|
||||
if (targetNames.isEmpty())
|
||||
{
|
||||
@@ -681,16 +682,15 @@ public class SlayerPlugin extends Plugin
|
||||
.replace('\u00A0', ' ')
|
||||
.toLowerCase();
|
||||
|
||||
for (String target : targetNames)
|
||||
for (Pattern target : targetNames)
|
||||
{
|
||||
if (name.contains(target))
|
||||
{
|
||||
if (ArrayUtils.contains(composition.getActions(), "Attack")
|
||||
final Matcher targetMatcher = target.matcher(name);
|
||||
if (targetMatcher.find()
|
||||
&& (ArrayUtils.contains(composition.getActions(), "Attack")
|
||||
// Pick action is for zygomite-fungi
|
||||
|| ArrayUtils.contains(composition.getActions(), "Pick"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|| ArrayUtils.contains(composition.getActions(), "Pick")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -703,13 +703,18 @@ public class SlayerPlugin extends Plugin
|
||||
if (task != null)
|
||||
{
|
||||
Arrays.stream(task.getTargetNames())
|
||||
.map(String::toLowerCase)
|
||||
.map(SlayerPlugin::targetNamePattern)
|
||||
.forEach(targetNames::add);
|
||||
|
||||
targetNames.add(taskName.toLowerCase().replaceAll("s$", ""));
|
||||
targetNames.add(targetNamePattern(taskName.replaceAll("s$", "")));
|
||||
}
|
||||
}
|
||||
|
||||
private static Pattern targetNamePattern(final String targetName)
|
||||
{
|
||||
return Pattern.compile("(?:\\s|^)" + targetName + "(?:\\s|$)", Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
|
||||
private void rebuildTargetList()
|
||||
{
|
||||
targets.clear();
|
||||
@@ -723,7 +728,8 @@ public class SlayerPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
private void setTask(String name, int amt, int initAmt)
|
||||
@VisibleForTesting
|
||||
void setTask(String name, int amt, int initAmt)
|
||||
{
|
||||
setTask(name, amt, initAmt, null);
|
||||
}
|
||||
|
||||
@@ -993,6 +993,13 @@ public class ClientUI
|
||||
|
||||
int width = panel.getWrappedPanel().getPreferredSize().width;
|
||||
int expandBy = pluginPanel != null ? pluginPanel.getWrappedPanel().getPreferredSize().width - width : width;
|
||||
|
||||
// Deactivate previously active panel
|
||||
if (pluginPanel != null)
|
||||
{
|
||||
pluginPanel.onDeactivate();
|
||||
}
|
||||
|
||||
pluginPanel = panel;
|
||||
|
||||
// Expand sidebar
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#version 330
|
||||
|
||||
uniform sampler2DArray textures;
|
||||
uniform vec2 textureOffsets[128];
|
||||
uniform float brightness;
|
||||
uniform float smoothBanding;
|
||||
uniform vec4 fogColor;
|
||||
@@ -49,9 +48,7 @@ void main() {
|
||||
if (textureId > 0) {
|
||||
int textureIdx = textureId - 1;
|
||||
|
||||
vec2 animatedUv = fUv + textureOffsets[textureIdx];
|
||||
|
||||
vec4 textureColor = texture(textures, vec3(animatedUv, float(textureIdx)));
|
||||
vec4 textureColor = texture(textures, vec3(fUv, float(textureIdx)));
|
||||
vec4 textureColorBrightness = pow(textureColor, vec4(brightness, brightness, brightness, 1.0f));
|
||||
|
||||
// textured triangles hsl is a 7 bit lightness 2-126
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
|
||||
#define TILE_SIZE 128
|
||||
|
||||
// smallest unit of the texture which can be moved per tick. textures are all
|
||||
// 128x128px - so this is equivalent to +1px
|
||||
#define TEXTURE_ANIM_UNIT (1.0f / 128.0f)
|
||||
|
||||
#define FOG_SCENE_EDGE_MIN TILE_SIZE
|
||||
#define FOG_SCENE_EDGE_MAX (103 * TILE_SIZE)
|
||||
#define FOG_CORNER_ROUNDING 1.5
|
||||
@@ -52,6 +56,8 @@ uniform int useFog;
|
||||
uniform int fogDepth;
|
||||
uniform int drawDistance;
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform vec2 textureAnimations[128];
|
||||
uniform int tick;
|
||||
|
||||
out vec4 Color;
|
||||
noperspective centroid out float fHsl;
|
||||
@@ -77,8 +83,17 @@ void main()
|
||||
gl_Position = projectionMatrix * vec4(vertex, 1.f);
|
||||
Color = vec4(rgb, 1.f - a);
|
||||
fHsl = float(hsl);
|
||||
textureId = int(uv.x);
|
||||
fUv = uv.yz;
|
||||
|
||||
int textureIdx = int(uv.x); // the texture id + 1
|
||||
vec2 textureUv = uv.yz;
|
||||
|
||||
vec2 textureAnim = vec2(0);
|
||||
if (textureIdx > 0) {
|
||||
textureAnim = textureAnimations[textureIdx - 1];
|
||||
}
|
||||
|
||||
textureId = textureIdx;
|
||||
fUv = textureUv + tick * textureAnim * TEXTURE_ANIM_UNIT;
|
||||
|
||||
int fogWest = max(FOG_SCENE_EDGE_MIN, cameraX - drawDistance);
|
||||
int fogEast = min(FOG_SCENE_EDGE_MAX, cameraX + drawDistance - TILE_SIZE);
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 420 B |
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.game;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.testing.fieldbinder.Bind;
|
||||
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.inject.Named;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.RuneLiteConfig;
|
||||
import net.runelite.http.api.item.ItemPrice;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ItemManagerTest
|
||||
{
|
||||
@Inject
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private Client client;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ScheduledExecutorService scheduledExecutorService;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ItemClient itemClient;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private RuneLiteConfig runeLiteConfig;
|
||||
|
||||
@Bind
|
||||
@Named("activePriceThreshold")
|
||||
private double activePriceThreshold = 5;
|
||||
|
||||
@Bind
|
||||
@Named("lowPriceThreshold")
|
||||
private int lowPriceThreshold = 1000;
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetWikiPrice()
|
||||
{
|
||||
ItemPrice itemPrice = new ItemPrice();
|
||||
itemPrice.setId(ItemID.YEW_SEED);
|
||||
itemPrice.setName("Yew seed");
|
||||
itemPrice.setPrice(47_975);
|
||||
itemPrice.setWikiPrice(50_754);
|
||||
assertEquals(itemPrice.getWikiPrice(), itemManager.getWikiPrice(itemPrice));
|
||||
|
||||
itemPrice.setWikiPrice(300_000); // outside of 5x range
|
||||
assertEquals(itemPrice.getPrice(), itemManager.getWikiPrice(itemPrice));
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ import net.runelite.api.widgets.WidgetID;
|
||||
import net.runelite.client.account.SessionManager;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
import net.runelite.client.chat.QueuedMessage;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.ItemStack;
|
||||
import net.runelite.client.game.SpriteManager;
|
||||
@@ -139,6 +140,10 @@ public class LootTrackerPluginTest
|
||||
@Bind
|
||||
private LootTrackerClient lootTrackerClient;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ConfigManager configManager;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
|
||||
@@ -60,6 +60,8 @@ import net.runelite.client.game.npcoverlay.NpcOverlayService;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -926,4 +928,30 @@ public class SlayerPluginTest
|
||||
assertEquals("Suqahs", slayerPlugin.getTaskName());
|
||||
assertEquals(229, slayerPlugin.getAmount()); // 2 kills
|
||||
}
|
||||
|
||||
@Test
|
||||
public void npcMatching()
|
||||
{
|
||||
assertTrue(matches("Abyssal demon", Task.ABYSSAL_DEMONS));
|
||||
assertTrue(matches("Baby blue dragon", Task.BLUE_DRAGONS));
|
||||
assertTrue(matches("Duck", Task.BIRDS));
|
||||
assertTrue(matches("Donny the Lad", Task.BANDITS));
|
||||
|
||||
assertFalse(matches("Rat", Task.PIRATES));
|
||||
assertFalse(matches("Wolf", Task.WEREWOLVES));
|
||||
assertFalse(matches("Scorpia's offspring", Task.SCORPIA));
|
||||
assertFalse(matches("Jonny the beard", Task.BEARS));
|
||||
}
|
||||
|
||||
private boolean matches(final String npcName, final Task task)
|
||||
{
|
||||
final NPC npc = mock(NPC.class);
|
||||
final NPCComposition comp = mock(NPCComposition.class);
|
||||
when(npc.getTransformedComposition()).thenReturn(comp);
|
||||
when(comp.getName()).thenReturn(npcName);
|
||||
when(comp.getActions()).thenReturn(new String[] { "Attack" });
|
||||
|
||||
slayerPlugin.setTask(task.getName(), 0, 0);
|
||||
return slayerPlugin.isTarget(npc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1160,6 +1160,10 @@ public interface RSClient extends RSGameEngine, Client
|
||||
@Override
|
||||
void setSelectedItemSlot(int index);
|
||||
|
||||
@Import("selectedItemSlot")
|
||||
@Override
|
||||
int getSelectedItemIndex();
|
||||
|
||||
@Import("selectedItemWidget")
|
||||
@Override
|
||||
int getSelectedItemWidget();
|
||||
@@ -1308,6 +1312,10 @@ public interface RSClient extends RSGameEngine, Client
|
||||
@Import("isItemSelected")
|
||||
int isItemSelected();
|
||||
|
||||
@Override
|
||||
@Import("isItemSelected")
|
||||
int getSelectedItem();
|
||||
|
||||
@Override
|
||||
@Import("selectedItemName")
|
||||
String getSelectedItemName();
|
||||
|
||||
Reference in New Issue
Block a user