Merge remote-tracking branch 'runelite/master'
This commit is contained in:
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -534,6 +534,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);
|
||||
}
|
||||
|
||||
@@ -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,7 @@ 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);
|
||||
gl.glUniform1i(uniTick, client.getGameCycle());
|
||||
|
||||
// Calculate projection matrix
|
||||
Matrix4 projectionMatrix = new Matrix4();
|
||||
@@ -1295,24 +1304,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 +1512,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
|
||||
{
|
||||
|
||||
@@ -316,6 +316,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 +351,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");
|
||||
|
||||
@@ -95,17 +95,18 @@ class LootTrackerPanel extends PluginPanel
|
||||
// When there is no loot, display this
|
||||
private final PluginErrorPanel errorPanel = new PluginErrorPanel();
|
||||
|
||||
// When there is loot, display this. This contains the actions, overall, and log panel.
|
||||
private final JPanel layoutPanel = new JPanel();
|
||||
|
||||
// Handle loot boxes
|
||||
private final JPanel logsContainer = new JPanel();
|
||||
|
||||
// Handle overall session data
|
||||
private final JPanel overallPanel = new JPanel();
|
||||
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 JLabel detailsTitle = new JLabel();
|
||||
private final JButton backBtn = new JButton();
|
||||
private final JToggleButton viewHiddenBtn = new JToggleButton();
|
||||
@@ -171,15 +172,36 @@ class LootTrackerPanel extends PluginPanel
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
// Create layout panel for wrapping
|
||||
final JPanel layoutPanel = new JPanel();
|
||||
layoutPanel.setLayout(new BoxLayout(layoutPanel, BoxLayout.Y_AXIS));
|
||||
layoutPanel.setVisible(false);
|
||||
add(layoutPanel, BorderLayout.NORTH);
|
||||
|
||||
final JPanel actionsPanel = buildActionsPanel();
|
||||
final JPanel 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));
|
||||
actionsContainer.setBorder(new EmptyBorder(5, 5, 5, 10));
|
||||
actionsContainer.setVisible(false);
|
||||
|
||||
final JPanel viewControls = new JPanel(new GridLayout(1, 3, 10, 0));
|
||||
viewControls.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
@@ -252,14 +274,19 @@ 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)
|
||||
));
|
||||
overallPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
overallPanel.setLayout(new BorderLayout());
|
||||
overallPanel.setVisible(false);
|
||||
|
||||
// Add icon and contents
|
||||
final JPanel overallInfo = new JPanel();
|
||||
@@ -310,15 +337,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()
|
||||
@@ -511,8 +530,7 @@ class LootTrackerPanel extends PluginPanel
|
||||
|
||||
// Show main view
|
||||
remove(errorPanel);
|
||||
actionsContainer.setVisible(true);
|
||||
overallPanel.setVisible(true);
|
||||
layoutPanel.setVisible(true);
|
||||
|
||||
// Create box
|
||||
final LootTrackerBox box = new LootTrackerBox(itemManager, record.getTitle(), record.getType(), record.getSubTitle(),
|
||||
@@ -555,7 +573,7 @@ class LootTrackerPanel extends PluginPanel
|
||||
{
|
||||
final LootTrackerClient client = plugin.getLootTrackerClient();
|
||||
final boolean syncLoot = client.getUuid() != null && config.syncPanel();
|
||||
final int result = JOptionPane.showOptionDialog(overallPanel,
|
||||
final int result = JOptionPane.showOptionDialog(box,
|
||||
syncLoot ? SYNC_RESET_ALL_WARNING_TEXT : NO_SYNC_RESET_ALL_WARNING_TEXT,
|
||||
"Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
|
||||
null, new String[]{"Yes", "No"}, "No");
|
||||
|
||||
@@ -1131,26 +1131,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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user