This commit is contained in:
PKLite
2019-07-30 21:25:15 -04:00
46 changed files with 1003 additions and 847 deletions

View File

@@ -6,9 +6,9 @@ plugins {
description = 'Deobfuscator'
def rootPath = project.rootDir.toString().replace('\\', '/')
def deobfuscatedJar = "${rootPath}/runescape-client/build/libs/rs-client-${project.version}.jar"
def vanillaJar = "${rootPath}/injector-plugin/vanilla-${rsversion}.jar"
configurations {
deobjars
}
dependencies {
implementation project(':runelite-api')
@@ -19,18 +19,28 @@ dependencies {
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
implementation group: 'org.ow2.asm', name: 'asm-debug-all', version: '5.2'
runtime group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.26'
testImplementation project(':rs-client')
testImplementation group: 'net.runelite.rs', name: 'vanilla', version: '181'
deobjars project(':rs-client')
deobjars group: 'net.runelite.rs', name: 'vanilla', version: '181'
testImplementation configurations.deobjars.dependencies
testImplementation group: 'junit', name: 'junit', version: '4.12'
testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.0.0'
}
processResources {
from file("src/main/resources/deob.properties"), {
filter(ReplaceTokens, tokens: [
"rs.version": rsversion.toString(),
"vanilla.jar": configurations.deobjars.find {it.name.startsWith("vanilla")}.toString().replace('\\', "/"),
"rs.client": configurations.deobjars.find {it.name.startsWith("rs-client")}.toString().replace('\\', "/")
])
}
}
processTestResources {
from file("src/test/resources/deob-test.properties"), {
filter(ReplaceTokens, tokens: [
"rs.client": deobfuscatedJar.toString(),
"rs.client": configurations.deobjars.find {it.name.startsWith("rs-client")}.toString().replace('\\', "/"),
"rs.version": rsversion.toString(),
"vanilla.jar": vanillaJar.toString()
"vanilla.jar": configurations.deobjars.find {it.name.startsWith("vanilla")}.toString().replace('\\', "/")
])
}
}

View File

@@ -30,6 +30,7 @@ import net.runelite.asm.attributes.Annotations;
import net.runelite.asm.attributes.annotation.Annotation;
import net.runelite.asm.pool.Class;
import net.runelite.asm.signature.Signature;
import static net.runelite.deob.DeobAnnotations.*;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
@@ -308,6 +309,20 @@ public class ClassFile
return null;
}
public Method findObfStaticMethod(String name, Signature type)
{
for (Method m : methods)
{
if (m.isStatic() &&
name.equals(getObfuscatedName(m.getAnnotations())) &&
type.equals(getObfuscatedSignature(m)))
{
return m;
}
}
return findMethodDeepStatic(name, type);
}
public Method findMethod(String name)
{
for (Method m : methods)

View File

@@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map;
import net.runelite.asm.attributes.Code;
import net.runelite.asm.signature.Signature;
import static net.runelite.deob.DeobAnnotations.*;
public class ClassGroup
{
@@ -142,4 +143,17 @@ public class ClassGroup
return m;
}
public ClassFile findObfuscatedName(String name)
{
for (ClassFile cf : classes)
{
if (name.equals(getObfuscatedName(cf.getAnnotations())))
{
return cf;
}
}
return findClass(name);
}
}

View File

@@ -26,6 +26,7 @@ package net.runelite.asm;
import net.runelite.asm.attributes.Annotations;
import net.runelite.asm.attributes.annotation.Annotation;
import net.runelite.deob.DeobAnnotations;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
@@ -131,6 +132,17 @@ public class Field
this.type = type;
}
public Type getObfuscatedType()
{
Type type = DeobAnnotations.getObfuscatedType(this);
if (type == null)
{
type = getType();
}
return type;
}
public Object getValue()
{
return value;

View File

@@ -35,6 +35,7 @@ import net.runelite.asm.attributes.code.LocalVariable;
import net.runelite.asm.attributes.code.Parameter;
import net.runelite.asm.attributes.code.instruction.types.LVTInstruction;
import net.runelite.asm.signature.Signature;
import net.runelite.deob.DeobAnnotations;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
@@ -193,6 +194,17 @@ public class Method
this.arguments = signature;
}
public Signature getObfuscatedSignature()
{
Signature sig = DeobAnnotations.getObfuscatedSignature(this);
if (sig == null)
{
sig = arguments;
}
return sig;
}
public boolean isNative()
{
return (accessFlags & ACC_NATIVE) != 0;

View File

@@ -25,10 +25,13 @@
package net.runelite.asm.attributes;
import java.util.ArrayList;
import java.util.List;
import net.runelite.asm.Method;
import net.runelite.asm.attributes.code.Exceptions;
import net.runelite.asm.attributes.code.Instruction;
import net.runelite.asm.attributes.code.Instructions;
import net.runelite.asm.attributes.code.Label;
import net.runelite.asm.attributes.code.instruction.types.LVTInstruction;
import net.runelite.asm.signature.Signature;
@@ -110,4 +113,28 @@ public class Code
{
return instructions;
}
public List<Integer> getLineNumbers()
{
final List<Integer> lineNumbers = new ArrayList<>();
for (Instruction i : instructions.getInstructions())
{
if (!(i instanceof Label))
{
continue;
}
Integer lineNumber = ((Label) i).getLineNumber();
if (lineNumber == null)
{
continue;
}
lineNumbers.add(lineNumber);
}
lineNumbers.sort(Integer::compareTo);
return lineNumbers;
}
}

View File

@@ -109,6 +109,11 @@ public class Label extends NOP
this.lineNumber = lineNumber;
}
public Integer getLineNumber()
{
return this.lineNumber;
}
public Instruction next()
{
Instructions ins = this.getInstructions();

View File

@@ -45,7 +45,7 @@ public class Field
@Override
public String toString()
{
return "Field{" + "clazz=" + clazz + ", name=" + name + ", type=" + type + '}';
return clazz.getName() + '.' + name + " " + type;
}
@Override

View File

@@ -43,7 +43,7 @@ public class Method
@Override
public String toString()
{
return clazz + "." + name + type;
return clazz.getName() + "." + name + type;
}
@Override

View File

@@ -75,7 +75,7 @@ public class Deob
System.exit(-1);
}
//logger.info("Deobfuscator revision {}", DeobProperties.getRevision());
logger.info("Deobfuscator revision {}", DeobProperties.getRevision());
Stopwatch stopwatch = Stopwatch.createStarted();

View File

@@ -24,18 +24,39 @@
*/
package net.runelite.deob;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class DeobProperties
{
public static String getRevision() throws IOException
private static final Properties properties;
static
{
Properties properties = new Properties();
InputStream resourceAsStream = DeobProperties.class.getResourceAsStream("/deob.properties");
properties.load(resourceAsStream);
properties = new Properties();
try (InputStream resourceAsStream = DeobProperties.class.getResourceAsStream("/deob.properties"))
{
properties.load(resourceAsStream);
}
catch (IOException e)
{
//yes
}
}
return "420";
public static String getRevision()
{
return properties.getProperty("rs.version");
}
public static File getVanilla()
{
return new File(properties.getProperty("vanilla.jar"));
}
public static File getRsClient()
{
return new File(properties.getProperty("rs.client"));
}
}

View File

@@ -0,0 +1,130 @@
package net.runelite.deob.updater;
import com.google.common.base.Stopwatch;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import net.runelite.asm.ClassFile;
import net.runelite.asm.ClassGroup;
import net.runelite.asm.pool.Field;
import net.runelite.asm.pool.Method;
import net.runelite.deob.DeobProperties;
import net.runelite.deob.updater.mappingdumper.MappedClass;
import net.runelite.deob.updater.mappingdumper.MappedField;
import net.runelite.deob.updater.mappingdumper.MappedMethod;
import net.runelite.deob.updater.mappingdumper.MappingDump;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MappingDumper
{
private static ClassGroup group;
private final Logger log = LoggerFactory.getLogger(MappingDumper.class);
private static final Map<ClassFile, MappedClass> classMap = new HashMap<>();
private static final Map<Field, MappedField> fieldMap = new HashMap<>();
private static final Map<Method, MappedMethod> methodMap = new HashMap<>();
public MappingDumper(ClassGroup group)
{
MappingDumper.group = group;
}
public void dump(final File outputFile)
{
Stopwatch st = Stopwatch.createStarted();
group.buildClassGraph();
// MappingDump.of(ClassGroup) dumps everything completely
final MappingDump dump = new MappingDump().visitGroup(group);
dump.revision = Integer.parseInt(DeobProperties.getRevision());
log.info("RS version {}. Dump took {}", dump.revision, st.toString());
log.info("Total classes: {}. Total mapped classes: {}. ({}%)", dump.totalClasses, dump.totalNamedClasses, dump.totalNamedClasses * 100 / dump.totalClasses);
log.info("Total non static methods: {}. Total mapped non static methods: {}. ({}%)", dump.totalNonStaticMethods, dump.totalNamedNonStaticMethods, dump.totalNamedNonStaticMethods * 100 / dump.totalNamedMethods);
log.info("Total methods: {}. Total mapped methods: {}. ({}%)", dump.totalMethods, dump.totalNamedMethods, dump.totalNamedMethods * 100 / dump.totalMethods);
log.info("Total fields: {}. Total mapped fields: {}. ({}%)", dump.totalFields, dump.totalNamedFields, dump.totalNamedFields * 100 / dump.totalFields);
log.info("Total non static fields: {}. Total mapped non static fields: {}. ({}%)", dump.totalNonStaticFields, dump.totalNamedNonStaticFields, dump.totalNamedNonStaticFields * 100 / dump.totalNamedFields);
writeJson(dump, outputFile);
}
// Without this stack'll overflow :P
private void writeJson(MappingDump dump, File outputFile)
{
final Gson gson = new GsonBuilder().setPrettyPrinting().create();
try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8)))
{
writer.setIndent(" ");
writer.beginObject();
writer.name("revision").value(dump.revision);
writer.name("totalClasses").value(dump.totalClasses);
writer.name("totalNamedClasses").value(dump.totalNamedClasses);
writer.name("totalFields").value(dump.totalFields);
writer.name("totalNamedFields").value(dump.totalNamedFields);
writer.name("totalNonStaticFields").value(dump.totalNonStaticFields);
writer.name("totalNamedNonStaticFields").value(dump.totalNamedNonStaticFields);
writer.name("totalStaticFields").value(dump.totalStaticFields);
writer.name("totalNamedStaticFields").value(dump.totalNamedStaticFields);
writer.name("totalMethods").value(dump.totalMethods);
writer.name("totalNamedMethods").value(dump.totalNamedMethods);
writer.name("totalNonStaticMethods").value(dump.totalNonStaticMethods);
writer.name("totalNamedNonStaticMethods").value(dump.totalNamedNonStaticMethods);
writer.name("totalStaticMethods").value(dump.totalStaticMethods);
writer.name("totalNamedStaticMethods").value(dump.totalNamedStaticMethods);
writer.name("mappedClasses");
writer.beginArray();
for (MappedClass mc : dump.classes)
{
gson.toJson(mc, MappedClass.class, writer);
}
writer.endArray();
writer.endObject();
}
catch (IOException e)
{
log.error("Error saving json: ", e);
}
}
public static ClassGroup getGroup()
{
return group;
}
public static void putMap(ClassFile clazz, MappedClass mc)
{
classMap.put(clazz, mc);
}
public static MappedClass getMap(ClassFile clazz)
{
return classMap.get(clazz);
}
public static void putMap(Field field, MappedField mf)
{
fieldMap.put(field, mf);
}
public static MappedField getMap(Field field)
{
return fieldMap.get(field);
}
public static void putMap(Method method, MappedMethod mm)
{
methodMap.put(method, mm);
}
public static MappedMethod getMap(Method method)
{
return methodMap.get(method);
}
}

View File

@@ -0,0 +1,68 @@
package net.runelite.deob.updater.mappingdumper;
import com.google.gson.annotations.SerializedName;
import java.util.List;
import java.util.stream.Collectors;
import net.runelite.asm.ClassFile;
import net.runelite.deob.DeobAnnotations;
import net.runelite.deob.updater.MappingDumper;
public class MappedClass
{
@SerializedName("class")
public String implementingName;
@SerializedName("name")
public String obfuscatedName;
@SerializedName("super")
public String superClass;
public int access;
public List<String> interfaces;
public List<MappedField> fields;
public List<MappedMethod> methods;
public List<MappedMethod> constructors;
public MappedClass visitClass(final ClassFile c, final MappingDump dump)
{
MappingDumper.putMap(c, this);
implementingName = DeobAnnotations.getImplements(c);
obfuscatedName = DeobAnnotations.getObfuscatedName(c.getAnnotations());
if (obfuscatedName == null)
{
obfuscatedName = c.getName();
}
ClassFile parent = c.getParent();
if (parent != null)
{
superClass = DeobAnnotations.getObfuscatedName(parent.getAnnotations());
}
access = c.getAccess();
interfaces = c.getInterfaces()
.getMyInterfaces()
.stream()
.map(ClassFile::getAnnotations)
.map(DeobAnnotations::getObfuscatedName)
.collect(Collectors.toList());
fields = c.getFields()
.stream()
.map(f -> new MappedField().visitField(f, dump))
.collect(Collectors.toList());
methods = c.getMethods()
.stream()
.map(m -> new MappedMethod().visitMethod(m, dump))
.collect(Collectors.toList());
constructors = methods
.stream()
.filter(m -> m.obfuscatedName.endsWith("init>"))
.collect(Collectors.toList());
return this;
}
}

View File

@@ -0,0 +1,47 @@
package net.runelite.deob.updater.mappingdumper;
import com.google.gson.annotations.SerializedName;
import java.util.HashMap;
import java.util.Map;
import net.runelite.asm.Field;
import net.runelite.asm.pool.Method;
import net.runelite.deob.DeobAnnotations;
import net.runelite.deob.updater.MappingDumper;
public class MappedField
{
@SerializedName("field")
public String exportedName;
public String owner;
@SerializedName("name")
public String obfuscatedName;
public int access;
public String descriptor;
public Number decoder;
// method name, amt of times
public Map<Method, Integer> puts = new HashMap<>();
public Map<Method, Integer> gets = new HashMap<>();
public MappedField visitField(final Field f, final MappingDump dump)
{
MappingDumper.putMap(f.getPoolField(), this);
exportedName = DeobAnnotations.getExportedName(f.getAnnotations());
owner = MappingDumper.getMap(f.getClassFile()).obfuscatedName;
obfuscatedName = DeobAnnotations.getObfuscatedName(f.getAnnotations());
if (obfuscatedName == null)
{
obfuscatedName = f.getName();
}
access = f.getAccessFlags();
descriptor = f.getObfuscatedType().toString();
decoder = DeobAnnotations.getObfuscatedGetter(f);
return this;
}
}

View File

@@ -0,0 +1,112 @@
package net.runelite.deob.updater.mappingdumper;
import com.google.gson.annotations.SerializedName;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import net.runelite.asm.Method;
import net.runelite.asm.attributes.Code;
import net.runelite.asm.attributes.code.Instruction;
import net.runelite.asm.attributes.code.Instructions;
import net.runelite.asm.attributes.code.Parameter;
import net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction;
import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction;
import net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction;
import net.runelite.asm.pool.Class;
import net.runelite.asm.pool.Field;
import net.runelite.deob.DeobAnnotations;
import net.runelite.deob.updater.MappingDumper;
public class MappedMethod
{
@SerializedName("method")
public String exportedName;
public String owner;
@SerializedName("name")
public String obfuscatedName;
public int access;
public List<String> parameters;
public String descriptor;
public String garbageValue;
public List<Integer> lineNumbers;
public Map<Field, Integer> fieldGets = new HashMap<>();
public Map<Field, Integer> fieldPuts = new HashMap<>();
public Map<net.runelite.asm.pool.Method, Integer> dependencies = new HashMap<>();
public MappedMethod visitMethod(final Method m, final MappingDump dump)
{
MappingDumper.putMap(m.getPoolMethod(), this);
exportedName = DeobAnnotations.getExportedName(m.getAnnotations());
owner = MappingDumper.getMap(m.getClassFile()).obfuscatedName;
obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations());
if (obfuscatedName == null)
{
obfuscatedName = m.getName();
}
access = m.getAccessFlags();
parameters = m.getParameters()
.stream()
.map(Parameter::getName)
.collect(Collectors.toList());
descriptor = m.getObfuscatedSignature().toString();
garbageValue = DeobAnnotations.getDecoder(m);
Code c = m.getCode();
if (c != null)
{
visitCode(c);
}
return this;
}
private void visitCode(Code c)
{
lineNumbers = c.getLineNumbers();
Instructions ins = c.getInstructions();
for (Instruction i : ins.getInstructions())
{
if (i instanceof GetFieldInstruction)
{
Field k = ((GetFieldInstruction) i).getField();
int v = fieldGets.getOrDefault(k, 0) + 1;
fieldGets.put(k, v);
}
else if (i instanceof SetFieldInstruction)
{
Field k = ((SetFieldInstruction) i).getField();
int v = fieldPuts.getOrDefault(k, 0) + 1;
fieldPuts.put(k, v);
}
else if (i instanceof InvokeInstruction)
{
List<Method> met = ((InvokeInstruction) i).getMethods();
net.runelite.asm.pool.Method k;
if (met.size() > 0)
{
Method mme = met.get(0);
k = new net.runelite.asm.pool.Method(
new Class(DeobAnnotations.getObfuscatedName(mme.getClassFile().getAnnotations())),
DeobAnnotations.getObfuscatedName(mme.getAnnotations()),
mme.getObfuscatedSignature() != null ? mme.getObfuscatedSignature() : mme.getDescriptor()
);
}
else
{
k = ((InvokeInstruction) i).getMethod();
}
int v = dependencies.getOrDefault(k, 0) + 1;
dependencies.put(k, v);
}
}
}
}

View File

@@ -0,0 +1,148 @@
package net.runelite.deob.updater.mappingdumper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.runelite.asm.ClassFile;
import net.runelite.asm.ClassGroup;
import net.runelite.asm.pool.Class;
import net.runelite.asm.pool.Field;
import net.runelite.asm.pool.Method;
import net.runelite.asm.signature.Signature;
import net.runelite.deob.updater.MappingDumper;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
public class MappingDump
{
public int revision;
public int totalClasses = 0;
public int totalNamedClasses = 0;
public int totalFields = 0;
public int totalNamedFields = 0;
public int totalNonStaticFields = 0;
public int totalNamedNonStaticFields = 0;
public int totalStaticFields = 0;
public int totalNamedStaticFields = 0;
public int totalMethods = 0;
public int totalNamedMethods = 0;
public int totalNonStaticMethods = 0;
public int totalNamedNonStaticMethods = 0;
public int totalStaticMethods = 0;
public int totalNamedStaticMethods = 0;
public List<MappedClass> classes;
private ClassGroup group;
public MappingDump visitGroup(ClassGroup group)
{
this.group = group;
classes = new ArrayList<>();
for (ClassFile c : group.getClasses())
{
if (c.getName().contains("runelite"))
{
continue;
}
final MappedClass mc = new MappedClass();
classes.add(mc.visitClass(c, this));
}
totalClasses = classes.size();
for (MappedClass c : classes)
{
if (c.implementingName != null)
{
totalNamedClasses++;
}
for (MappedMethod mm : c.methods)
{
for (Map.Entry<Field, Integer> entry : mm.fieldGets.entrySet())
{
MappedField mf = MappingDumper.getMap(entry.getKey());
if (mf == null)
{
continue;
}
mf.gets.put(
new Method(
new Class(mm.owner),
mm.obfuscatedName,
new Signature(mm.descriptor)),
entry.getValue());
}
for (Map.Entry<Field, Integer> entry : mm.fieldPuts.entrySet())
{
MappedField mf = MappingDumper.getMap(entry.getKey());
if (mf == null)
{
continue;
}
mf.puts.put(
new Method(
new Class(mm.owner),
mm.obfuscatedName,
new Signature(mm.descriptor)),
entry.getValue());
}
}
grabAmountInfo(c);
}
totalNonStaticFields = totalFields - totalStaticFields;
totalNamedNonStaticFields = totalNamedFields - totalNamedStaticFields;
totalNonStaticMethods = totalMethods - totalStaticMethods;
totalNamedNonStaticMethods = totalNamedMethods - totalNamedStaticMethods;
return this;
}
private void grabAmountInfo(MappedClass c)
{
totalFields += c.fields.size();
totalNamedFields += c.fields
.stream()
.filter(f -> f.exportedName != null)
.count();
totalStaticFields += c.fields
.stream()
.filter(f -> (f.access & ACC_STATIC) != 0)
.count();
totalNamedStaticFields += c.fields
.stream()
.filter(f -> f.exportedName != null
&& (f.access & ACC_STATIC) != 0)
.count();
totalMethods += c.methods.size();
totalNamedMethods += c.methods
.stream()
.filter(f -> f.exportedName != null)
.count();
totalStaticMethods += c.methods
.stream()
.filter(f -> (f.access & ACC_STATIC) != 0)
.count();
totalNamedStaticMethods += c.methods
.stream()
.filter(f -> f.exportedName != null
&& (f.access & ACC_STATIC) != 0)
.count();
}
ClassGroup getGroup()
{
return group;
}
}

View File

@@ -0,0 +1,3 @@
rs.version=@rs.version@
vanilla.jar=@vanilla.jar@
rs.client=@rs.client@

View File

@@ -24,266 +24,47 @@
*/
package net.runelite.deob.deobfuscators.mapping;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.time.Instant;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import net.runelite.asm.ClassFile;
import net.runelite.asm.ClassGroup;
import net.runelite.asm.Field;
import net.runelite.asm.Method;
import net.runelite.asm.Type;
import net.runelite.asm.attributes.code.Parameter;
import net.runelite.asm.signature.Signature;
import net.runelite.deob.Deob;
import net.runelite.deob.DeobAnnotations;
import net.runelite.deob.DeobTestProperties;
import net.runelite.deob.deobfuscators.mapping.mappingdumper.MappedClass;
import net.runelite.deob.deobfuscators.mapping.mappingdumper.MappedField;
import net.runelite.deob.deobfuscators.mapping.mappingdumper.MappedMethod;
import net.runelite.deob.deobfuscators.mapping.mappingdumper.MappingDump;
import net.runelite.deob.util.JarUtil;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MappingDumper
{
@Rule
public DeobTestProperties properties = new DeobTestProperties();
private final Logger log = LoggerFactory.getLogger(MappingDumper.class);
private MappingDump dump;
private Map<String, MappedClass> classMap;
private ClassGroup group;
private static final String OUTDIR = "";
private final File OUTFILE = new File(OUTDIR, "rlplushooks.json");
@Before
public void before()
public void before() throws IOException
{
dump = new MappingDump();
dump.revision = properties.getRsVersion();
dump.classes = new ArrayList<>();
dump.staticFields = new ArrayList<>();
dump.staticMethods = new ArrayList<>();
classMap = new HashMap<>();
group = JarUtil.loadJar(new File(properties.getRsClient()));
}
@Test
@Ignore
public void newDump() throws IOException
public void newDump()
{
final ClassGroup group = JarUtil.loadJar(new File(properties.getRsClient()));
// First create all the mappedclasses, so we can add static methods to their lists
for (ClassFile c : group.getClasses())
{
if (c.getName().contains("runelite"))
{
continue;
}
final MappedClass mc = new MappedClass();
mc.obfuscatedName = DeobAnnotations.getObfuscatedName(c.getAnnotations());
mc.implementingName = DeobAnnotations.getImplements(c);
mc.superClass = c.getSuperName();
mc.interfaces = c.getInterfaces().getIntfNames();
mc.constructors = new ArrayList<>();
mc.fields = new ArrayList<>();
mc.methods = new ArrayList<>();
mc.access = c.getAccess();
mc.staticMethods = new ArrayList<>();
mc.staticFields = new ArrayList<>();
dump.classes.add(mc);
classMap.put(c.getName(), mc);
dump.totalClasses++;
if (mc.implementingName != null)
{
dump.totalNamedClasses++;
}
}
for (ClassFile c : group.getClasses())
{
if (c.getName().contains("runelite"))
{
continue;
}
final MappedClass mc = classMap.get(c.getName());
getFields(c, mc);
getMethods(c, mc);
}
dump.totalNonStaticFields = dump.totalFields - dump.totalStaticFields;
dump.totalNamedNonStaticFields = dump.totalNamedFields - dump.totalNamedStaticFields;
dump.totalNonStaticMethods = dump.totalMethods - dump.totalStaticMethods;
dump.totalNamedNonStaticMethods = dump.totalNamedMethods - dump.totalNamedStaticMethods;
final Gson gson = new GsonBuilder().setPrettyPrinting().create();
Files.asCharSink(OUTFILE, Charset.defaultCharset()).write(gson.toJson(dump));
log.info("Dumped current mappings. revision {}", dump.revision);
log.info("Total classes: {}. Total mapped classes: {}. ({}%)", dump.totalClasses, dump.totalNamedClasses, dump.totalNamedClasses * 100 / dump.totalClasses);
log.info("Total non static methods: {}. Total mapped non static methods: {}. ({}%)", dump.totalNonStaticMethods, dump.totalNamedNonStaticMethods, dump.totalNamedNonStaticMethods * 100 / dump.totalNamedMethods);
log.info("Total methods: {}. Total mapped methods: {}. ({}%)", dump.totalMethods, dump.totalNamedMethods, dump.totalNamedMethods * 100 / dump.totalMethods);
log.info("Total fields: {}. Total mapped fields: {}. ({}%)", dump.totalFields, dump.totalNamedFields, dump.totalNamedFields * 100 / dump.totalFields);
log.info("Total non static fields: {}. Total mapped non static fields: {}. ({}%)", dump.totalNonStaticFields, dump.totalNamedNonStaticFields, dump.totalNamedNonStaticFields * 100 / dump.totalNamedFields);
}
private void getFields(final ClassFile c, final MappedClass mc)
{
for (Field f : c.getFields())
{
dump.totalFields++;
if (f.isStatic())
{
dump.totalStaticFields++;
}
if (Deob.isObfuscated(f.getName()))
{
continue;
}
dump.totalNamedFields++;
final MappedField mf = new MappedField();
mf.exportedName = f.getName();
mf.owner = mc.obfuscatedName;
mf.obfuscatedName = DeobAnnotations.getObfuscatedName(f.getAnnotations());
mf.access = f.getAccessFlags();
mf.descriptor = DeobAnnotations.getAnnotationValue(f.getAnnotations(), DeobAnnotations.OBFUSCATED_SIGNATURE);
Number decoder = DeobAnnotations.getObfuscatedGetter(f);
if (decoder != null)
{
mf.decoder = decoder.longValue();
}
if (mf.descriptor == null)
{
mf.descriptor = f.getType().toString();
}
if (f.isStatic())
{
dump.staticFields.add(mf);
dump.totalNamedStaticFields++;
int _index = mf.exportedName.indexOf('_');
if (_index != -1)
{
String className = mf.exportedName.substring(0, _index);
MappedClass staticOwner = classMap.get(className);
if (staticOwner != null)
{
staticOwner.staticFields.add(mf);
}
}
}
else
{
mc.fields.add(mf);
}
}
}
private void getMethods(final ClassFile c, final MappedClass mc)
{
for (Method m : c.getMethods())
{
dump.totalMethods++;
if (m.isStatic())
{
dump.totalStaticMethods++;
}
if (Deob.isObfuscated(m.getName()) || m.getName().equals("<clinit>"))
{
continue;
}
dump.totalNamedMethods++;
final MappedMethod mm = new MappedMethod();
mm.exportedName = m.getName();
mm.owner = mc.obfuscatedName;
mm.obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations());
mm.access = m.getAccessFlags();
mm.parameters = new ArrayList<>();
mm.descriptor = DeobAnnotations.getObfuscatedSignature(m) != null ? DeobAnnotations.getObfuscatedSignature(m).toString() : m.getDescriptor().toString();
try
{
mm.garbageValue = Long.parseLong(DeobAnnotations.getDecoder(m));
}
catch (NumberFormatException e)
{
mm.garbageValue = null;
}
for (Parameter p : m.getParameters())
{
mm.parameters.add(p.getName());
}
if (m.getName().equals("<init>"))
{
mm.exportedName = null;
mc.constructors.add(mm);
continue;
}
if (m.isStatic())
{
dump.staticMethods.add(mm);
dump.totalNamedStaticMethods++;
int _index = mm.exportedName.indexOf('_');
if (_index != -1)
{
String className = mm.exportedName.substring(0, _index - 1);
MappedClass staticOwner = classMap.get(className);
if (staticOwner != null)
{
staticOwner.staticMethods.add(mm);
}
}
}
else
{
mc.methods.add(mm);
}
}
new net.runelite.deob.updater.MappingDumper(group).dump(OUTFILE);
}
@Test

View File

@@ -1,22 +0,0 @@
package net.runelite.deob.deobfuscators.mapping.mappingdumper;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class MappedClass
{
@SerializedName("class")
public String implementingName;
@SerializedName("name")
public String obfuscatedName;
@SerializedName("super")
public String superClass;
public int access;
public List<String> interfaces;
public List<MappedField> fields;
public List<MappedMethod> methods;
public List<MappedMethod> constructors;
// Static fields/methods belonging to this class (ClassName_name)
public List<MappedField> staticFields;
public List<MappedMethod> staticMethods;
}

View File

@@ -1,15 +0,0 @@
package net.runelite.deob.deobfuscators.mapping.mappingdumper;
import com.google.gson.annotations.SerializedName;
public class MappedField
{
@SerializedName("field")
public String exportedName;
public String owner;
@SerializedName("name")
public String obfuscatedName;
public int access;
public String descriptor;
public Long decoder;
}

View File

@@ -1,17 +0,0 @@
package net.runelite.deob.deobfuscators.mapping.mappingdumper;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class MappedMethod
{
@SerializedName("method")
public String exportedName;
public String owner;
@SerializedName("name")
public String obfuscatedName;
public int access;
public List<String> parameters;
public String descriptor;
public Long garbageValue;
}

View File

@@ -1,35 +0,0 @@
package net.runelite.deob.deobfuscators.mapping.mappingdumper;
import java.util.List;
public class MappingDump
{
public int revision;
public int totalClasses;
public int totalNamedClasses;
public int totalFields;
public int totalNamedFields;
public int totalNonStaticFields;
public int totalNamedNonStaticFields;
public int totalStaticFields;
public int totalNamedStaticFields;
public int totalMethods;
public int totalNamedMethods;
public int totalNonStaticMethods;
public int totalNamedNonStaticMethods;
public int totalStaticMethods;
public int totalNamedStaticMethods;
public List<MappedClass> classes;
// Static things belonging to a certain class will be in both these lists and in the classes
public List<MappedField> staticFields;
public List<MappedMethod> staticMethods;
}

View File

@@ -1456,6 +1456,13 @@ public interface Client extends GameShell
*/
void setNPCsNames(String names);
/**
* Sets which NPCs are hidden on death
*
* @param names the names of the npcs seperated by ','
*/
void setNPCsHiddenOnDeath(String names);
/**
* Sets whether 2D sprites (ie. overhead prayers) related to
* the NPCs are hidden.
@@ -1478,6 +1485,13 @@ public interface Client extends GameShell
*/
void setProjectilesHidden(boolean state);
/**
* Sets whether dead NPCs are hidden.
*
* @param state new NPC hidden state
*/
void setDeadNPCsHidden(boolean state);
/**
* Gets an array of tile collision data.
* <p>
@@ -1678,9 +1692,9 @@ public interface Client extends GameShell
MouseRecorder getMouseRecorder();
void setPrintMenuActions(boolean b);
String getSelectedSpellName();
boolean isSpellSelected();
/**
@@ -1707,7 +1721,7 @@ public interface Client extends GameShell
* Set spells excluded from above hiding
*/
void setUnhiddenCasts(Set<String> casts);
/**
* Sorts the current menu entries in the same way the client does this.
* The last entry will be the left click one after this.

View File

@@ -66,7 +66,8 @@ public enum ItemMapping
ITEM_DRAGON_SCIMITAR(DRAGON_SCIMITAR, DRAGON_SCIMITAR_OR),
ITEM_DRAGON_SCIMITAR_ORNAMENT_KIT(DRAGON_SCIMITAR_ORNAMENT_KIT, DRAGON_SCIMITAR_OR),
ITEM_DRAGON_DEFENDER(DRAGON_DEFENDER_ORNAMENT_KIT, DRAGON_DEFENDER_T),
ITEM_DRAGON_PICKAXE(DRAGON_PICKAXE, DRAGON_PICKAXE_12797),
ITEM_DRAGON_PICKAXE(DRAGON_PICKAXE, DRAGON_PICKAXE_12797, DRAGON_PICKAXEOR),
ITEM_DRAGON_PICKAXE_OR(ZALCANO_SHARD, DRAGON_PICKAXEOR),
ITEM_DRAGON_KITESHIELD(DRAGON_KITESHIELD, DRAGON_KITESHIELD_G),
ITEM_DRAGON_KITESHIELD_ORNAMENT_KIT(DRAGON_KITESHIELD_ORNAMENT_KIT, DRAGON_KITESHIELD_G),
ITEM_DRAGON_FULL_HELM(DRAGON_FULL_HELM, DRAGON_FULL_HELM_G),
@@ -214,7 +215,17 @@ public enum ItemMapping
ITEM_HYDRA_LEATHER(HYDRA_LEATHER, FEROCIOUS_GLOVES),
ITEM_HYDRA_TAIL(HYDRA_TAIL, BONECRUSHER_NECKLACE),
ITEM_DRAGONBONE_NECKLACE(DRAGONBONE_NECKLACE, BONECRUSHER_NECKLACE),
ITEM_BOTTOMLESS_COMPOST_BUCKET(BOTTOMLESS_COMPOST_BUCKET, BOTTOMLESS_COMPOST_BUCKET_22997);
ITEM_BOTTOMLESS_COMPOST_BUCKET(BOTTOMLESS_COMPOST_BUCKET, BOTTOMLESS_COMPOST_BUCKET_22997),
// Crystal items
ITEM_CRYSTAL_TOOL_SEED(CRYSTAL_TOOL_SEED, CRYSTAL_AXE, CRYSTAL_AXE_INACTIVE, CRYSTAL_HARPOON, CRYSTAL_HARPOON_INACTIVE, CRYSTAL_PICKAXE, CRYSTAL_PICKAXE_INACTIVE),
ITEM_CRYSTAL_AXE(DRAGON_AXE, CRYSTAL_AXE, CRYSTAL_AXE_INACTIVE),
ITEM_CRYSTAL_HARPOON(DRAGON_HARPOON, CRYSTAL_HARPOON, CRYSTAL_HARPOON_INACTIVE),
ITEM_CRYSTAL_PICKAXE(DRAGON_PICKAXE, CRYSTAL_PICKAXE, CRYSTAL_PICKAXE_INACTIVE),
ITEM_BLADE_OF_SAELDOR(BLADE_OF_SAELDOR_INACTIVE, BLADE_OF_SAELDOR),
ITEM_CRYSTAL_BOW(CRYSTAL_WEAPON_SEED, CRYSTAL_BOW, CRYSTAL_BOW_INACTIVE),
ITEM_CRYSTAL_HALBERD(CRYSTAL_WEAPON_SEED, CRYSTAL_HALBERD, CRYSTAL_HALBERD_INACTIVE),
ITEM_CRYSTAL_SHIELD(CRYSTAL_WEAPON_SEED, CRYSTAL_SHIELD, CRYSTAL_SHIELD_INACTIVE);
private static final Multimap<Integer, Integer> MAPPINGS = HashMultimap.create();
private final int tradeableItem;

View File

@@ -46,7 +46,14 @@ public enum UntradeableItemMapping
PROSPECTOR_HELMET(ItemID.PROSPECTOR_HELMET, 32, ItemID.GOLDEN_NUGGET),
PROSPECTOR_JACKET(ItemID.PROSPECTOR_JACKET, 48, ItemID.GOLDEN_NUGGET),
PROSPECTOR_LEGS(ItemID.PROSPECTOR_LEGS, 40, ItemID.GOLDEN_NUGGET),
PROSPECTOR_BOOTS(ItemID.PROSPECTOR_BOOTS, 24, ItemID.GOLDEN_NUGGET);
PROSPECTOR_BOOTS(ItemID.PROSPECTOR_BOOTS, 24, ItemID.GOLDEN_NUGGET),
CRYSTAL_HELMET(ItemID.CRYSTAL_HELM, 1, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_HELMET_INACTIVE(ItemID.CRYSTAL_HELM_INACTIVE, 1, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_LEGS(ItemID.CRYSTAL_LEGS, 2, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_LEGS_INACTIVE(ItemID.CRYSTAL_LEGS_INACTIVE, 2, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_BODY(ItemID.CRYSTAL_BODY, 3, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_BODY_INACTIVE(ItemID.CRYSTAL_BODY_INACTIVE, 3, ItemID.CRYSTAL_ARMOUR_SEED);
private static final ImmutableMap<Integer, UntradeableItemMapping> UNTRADEABLE_RECLAIM_MAP;

View File

@@ -87,7 +87,7 @@ import org.apache.commons.text.WordUtils;
@Slf4j
public class ChatCommandsPlugin extends Plugin
{
private static final Pattern KILLCOUNT_PATTERN = Pattern.compile("Your (.+) (?:kill|harvest|lap) count is: <col=ff0000>(\\d+)</col>");
private static final Pattern KILLCOUNT_PATTERN = Pattern.compile("Your (.+) (?:kill|harvest|lap|completion) count is: <col=ff0000>(\\d+)</col>");
private static final Pattern RAIDS_PATTERN = Pattern.compile("Your completed (.+) count is: <col=ff0000>(\\d+)</col>");
private static final Pattern WINTERTODT_PATTERN = Pattern.compile("Your subdued Wintertodt count is: <col=ff0000>(\\d+)</col>");
private static final Pattern BARROWS_PATTERN = Pattern.compile("Your Barrows chest count is: <col=ff0000>(\\d+)</col>");
@@ -1382,6 +1382,16 @@ public class ChatCommandsPlugin extends Plugin
case "prifddinas":
return "Prifddinas Agility Course";
// The Gauntlet
case "gaunt":
case "gauntlet":
return "Gauntlet";
// Corrupted Gauntlet
case "cgaunt":
case "cgauntlet":
return "Corrupted Gauntlet";
default:
return WordUtils.capitalize(boss);
}

View File

@@ -107,7 +107,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
new EmoteClue("Cry in the Catherby Ranging shop. Bow before you talk to me. Equip blue gnome boots, a hard leather body and an unblessed silver sickle.", "Catherby", HICKTONS_ARCHERY_EMPORIUM, new WorldPoint(2823, 3443, 0), CRY, BOW, item(BLUE_BOOTS), item(HARDLEATHER_BODY), item(SILVER_SICKLE)),
new EmoteClue("Cry on the shore of Catherby beach. Laugh before you talk to me, equip an adamant sq shield, a bone dagger and mithril platebody.", "Catherby", OUTSIDE_HARRYS_FISHING_SHOP_IN_CATHERBY, new WorldPoint(2852, 3429, 0), CRY, LAUGH, item(ADAMANT_SQ_SHIELD), item(BONE_DAGGER), item(MITHRIL_PLATEBODY)),
new EmoteClue("Cry on top of the western tree in the Gnome Agility Arena. Indicate 'no' before you talk to me. Equip a steel kiteshield, ring of forging and green dragonhide chaps.", "Gnome Stronghold", GNOME_STRONGHOLD_BALANCING_ROPE, new WorldPoint(2473, 3420, 2), CRY, NO, item(STEEL_KITESHIELD), item(RING_OF_FORGING), item(GREEN_DHIDE_CHAPS)),
new EmoteClue("Cry in the TzHaar gem store. Beware of double agents! Equip a fire cape and TokTz-Xil-Ul.", "Tzhaar gem store", TZHAAR_GEM_STORE, new WorldPoint(2463, 5149, 0), CRY, any("Fire cape", item(FIRE_CAPE), item(FIRE_MAX_CAPE)), item(TOKTZXILUL)),
new EmoteClue("Cry in the TzHaar gem store. Beware of double agents! Equip a fire cape and TokTz-Xil-Ul.", "Tzhaar gem store", TZHAAR_GEM_STORE, new WorldPoint(2463, 5149, 0), CRY, any("Fire cape", item(FIRE_CAPE), item(FIRE_MAX_CAPE), item(INFERNAL_CAPE), item(INFERNAL_MAX_CAPE)), item(TOKTZXILUL)),
new EmoteClue("Cry in the Draynor Village jail. Jump for joy before you talk to me. Equip an adamant sword, a sapphire amulet and an adamant plateskirt.", "Draynor Village jail", OUTSIDE_DRAYNOR_VILLAGE_JAIL, new WorldPoint(3128, 3245, 0), CRY, JUMP_FOR_JOY, item(ADAMANT_SWORD), item(SAPPHIRE_AMULET), item(ADAMANT_PLATESKIRT)),
new EmoteClue("Dance at the crossroads north of Draynor. Equip an iron chain body, a sapphire ring and a longbow.", "Draynor Village", CROSSROADS_NORTH_OF_DRAYNOR_VILLAGE, new WorldPoint(3109, 3294, 0), DANCE, item(IRON_CHAINBODY), item(SAPPHIRE_RING), item(LONGBOW)),
new EmoteClue("Dance in the Party Room. Equip a steel full helmet, steel platebody and an iron plateskirt.", "Falador Party Room", OUTSIDE_THE_FALADOR_PARTY_ROOM, new WorldPoint(3045, 3376, 0), DANCE, item(STEEL_FULL_HELM), item(STEEL_PLATEBODY), item(IRON_PLATESKIRT)),
@@ -155,7 +155,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
new EmoteClue("Slap your head in the centre of the Kourend catacombs. Beware of double agents! Equip the arclight and the amulet of the damned.", "Kourend catacombs", CENTRE_OF_THE_CATACOMBS_OF_KOUREND, new WorldPoint(1663, 10045, 0), SLAP_HEAD, item(ARCLIGHT), any("Amulet of the damned", item(AMULET_OF_THE_DAMNED), item(AMULET_OF_THE_DAMNED_FULL))),
new EmoteClue("Spin at the crossroads north of Rimmington. Equip a green gnome hat, cream gnome top and leather chaps.", "Rimmington", ROAD_JUNCTION_NORTH_OF_RIMMINGTON, new WorldPoint(2981, 3276, 0), SPIN, item(GREEN_HAT), item(CREAM_ROBE_TOP), item(LEATHER_CHAPS)),
new EmoteClue("Spin in Draynor Manor by the fountain. Equip an iron platebody, studded leather chaps and a bronze full helmet.", "Draynor Manor", DRAYNOR_MANOR_BY_THE_FOUNTAIN, new WorldPoint(3088, 3336, 0), SPIN, item(IRON_PLATEBODY), item(STUDDED_CHAPS), item(BRONZE_FULL_HELM)),
new EmoteClue("Spin in front of the Soul altar. Beware of double agents! Equip a dragon pickaxe, helm of neitiznot and a pair of rune boots.", "Soul altar", SOUL_ALTAR, new WorldPoint(1815, 3856, 0), SPIN, any("Dragon pickaxe", item(DRAGON_PICKAXE), item(DRAGON_PICKAXE_12797), item(INFERNAL_PICKAXE), item(INFERNAL_PICKAXE_UNCHARGED)), item(HELM_OF_NEITIZNOT), item(RUNE_BOOTS)),
new EmoteClue("Spin in front of the Soul altar. Beware of double agents! Equip a dragon pickaxe, helm of neitiznot and a pair of rune boots.", "Soul altar", SOUL_ALTAR, new WorldPoint(1815, 3856, 0), SPIN, any("Dragon pickaxe", item(DRAGON_PICKAXE), item(DRAGON_PICKAXE_12797), item(INFERNAL_PICKAXE), item(INFERNAL_PICKAXE_UNCHARGED), item(DRAGON_PICKAXEOR)), item(HELM_OF_NEITIZNOT), item(RUNE_BOOTS)),
new EmoteClue("Spin in the Varrock Castle courtyard. Equip a black axe, a coif and a ruby ring.", "Varrock Castle", OUTSIDE_VARROCK_PALACE_COURTYARD, new WorldPoint(3213, 3463, 0), SPIN, item(BLACK_AXE), item(COIF), item(RUBY_RING)),
new EmoteClue("Spin in West Ardougne Church. Equip a dragon spear and red dragonhide chaps.", "Ardougne", CHAPEL_IN_WEST_ARDOUGNE, new WorldPoint(2530, 3290, 0), SPIN, item(DRAGON_SPEAR), item(RED_DHIDE_CHAPS)),
new EmoteClue("Spin on the bridge by the Barbarian Village. Salute before you talk to me. Equip purple gloves, a steel kiteshield and a mithril full helmet.", "Barbarian Village", EAST_OF_THE_BARBARIAN_VILLAGE_BRIDGE, new WorldPoint(3105, 3420, 0), SPIN, SALUTE, item(PURPLE_GLOVES), item(STEEL_KITESHIELD), item(MITHRIL_FULL_HELM)),

View File

@@ -153,12 +153,12 @@ public enum HotColdLocation
WILDERNESS_32(new WorldPoint(3311, 3773, 0), WILDERNESS, "North of Venenatis' nest, level 32 Wilderness."),
WILDERNESS_35(new WorldPoint(3153, 3795, 0), WILDERNESS, "East of the Wilderness canoe exit, level 35 Wilderness."),
WILDERNESS_37(new WorldPoint(2975, 3811, 0), WILDERNESS, "South-east of the Chaos Temple, level 37 Wilderness."),
WILDERNESS_38(new WorldPoint(3294, 3817, 0), WILDERNESS, "South of Callisto, level 38 Wilderness."),
WILDERNESS_38(new WorldPoint(3293, 3813, 0), WILDERNESS, "South of Callisto, level 38 Wilderness."),
WILDERNESS_49(new WorldPoint(3140, 3910, 0), WILDERNESS, "South-west of the Deserted Keep, level 49 Wilderness."),
WILDERNESS_54(new WorldPoint(2983, 3946, 0), WILDERNESS, "West of the Wilderness Agility Course, level 54 Wilderness."),
ZEAH_BLASTMINE_BANK(new WorldPoint(1507, 3856, 0), ZEAH, "Next to the bank in the Lovakengj blast mine."),
ZEAH_BLASTMINE_NORTH(new WorldPoint(1490, 3883, 0), ZEAH, "Northern part of the Lovakengj blast mine."),
ZEAH_LOVAKITE_FURNACE(new WorldPoint(1505, 3814, 0), ZEAH, "Next to the lovakite furnace in Lovakengj."),
ZEAH_LOVAKITE_FURNACE(new WorldPoint(1507, 3819, 0), ZEAH, "Next to the lovakite furnace in Lovakengj."),
ZEAH_LOVAKENGJ_MINE(new WorldPoint(1477, 3779, 0), ZEAH, "Next to mithril rock in the Lovakengj mine."),
ZEAH_SULPHR_MINE(new WorldPoint(1428, 3866, 0), ZEAH, "Western entrance in the Lovakengj sulphur mine."),
ZEAH_SHAYZIEN_BANK(new WorldPoint(1517, 3603, 0), ZEAH, "South-east of the bank in Shayzien."),

View File

@@ -142,6 +142,17 @@ public interface EntityHiderConfig extends Config
return "";
}
@ConfigItem(
position = 10,
keyName = "hideNPCsOnDeath",
name = "Hide NPCs On Death",
description = "Configures which NPCs to hide when they die"
)
default String hideNPCsOnDeath()
{
return "";
}
@ConfigItem(
position = 11,
keyName = "hideProjectiles",
@@ -153,4 +164,15 @@ public interface EntityHiderConfig extends Config
return false;
}
@ConfigItem(
position = 12,
keyName = "hideDeadNPCs",
name = "Hide Dead NPCs",
description = "Configures whether or not NPCs that just died are hidden"
)
default boolean hideDeadNPCs()
{
return false;
}
}

View File

@@ -108,10 +108,13 @@ public class EntityHiderPlugin extends Plugin
client.setNPCsHidden(config.hideNPCs());
client.setNPCsHidden2D(config.hideNPCs2D());
client.setNPCsNames(config.hideNPCsNames());
client.setNPCsHiddenOnDeath(config.hideNPCsOnDeath());
client.setAttackersHidden(config.hideAttackers());
client.setProjectilesHidden(config.hideProjectiles());
client.setDeadNPCsHidden(config.hideDeadNPCs());
}
@Override
@@ -136,6 +139,8 @@ public class EntityHiderPlugin extends Plugin
client.setAttackersHidden(false);
client.setProjectilesHidden(false);
client.setDeadNPCsHidden(false);
}
private boolean isPlayerRegionAllowed()

View File

@@ -99,6 +99,8 @@ import static net.runelite.api.NpcID.ROD_FISHING_SPOT_7464;
import static net.runelite.api.NpcID.ROD_FISHING_SPOT_7468;
import static net.runelite.api.NpcID.ROD_FISHING_SPOT_7676;
import static net.runelite.api.NpcID.ROD_FISHING_SPOT_8524;
import static net.runelite.api.NpcID.FISHING_SPOT_4928;
import static net.runelite.api.NpcID.FISHING_SPOT_6784;
@Getter
enum FishingSpot
@@ -132,6 +134,9 @@ enum FishingSpot
ROD_FISHING_SPOT_1526, ROD_FISHING_SPOT_1527, ROD_FISHING_SPOT_7463,
ROD_FISHING_SPOT_7464, ROD_FISHING_SPOT_7468, ROD_FISHING_SPOT_8524
),
LAVA_EEL("Lava eel", ItemID.LAVA_EEL,
FISHING_SPOT_4928, FISHING_SPOT_6784
),
BARB_FISH("Sturgeon, Salmon, Trout", ItemID.LEAPING_STURGEON,
FISHING_SPOT_1542, FISHING_SPOT_7323
),

View File

@@ -60,7 +60,7 @@ enum Impling
NINJA(ImplingType.NINJA, NpcID.NINJA_IMPLING),
NINJA_2(ImplingType.NINJA, NpcID.NINJA_IMPLING_1653),
CRYSTAL(ImplingType.CRYSTAL, NpcID.CRYSTAL_IMPLING),
CRYSTAL_2(ImplingType.CRYSTAL, NpcID.CRYSTAL_IMPLING_8742),
CRYSTAL_3(ImplingType.CRYSTAL, NpcID.CRYSTAL_IMPLING_8743),
@@ -78,7 +78,6 @@ enum Impling
CRYSTAL_15(ImplingType.CRYSTAL, NpcID.CRYSTAL_IMPLING_8755),
CRYSTAL_16(ImplingType.CRYSTAL, NpcID.CRYSTAL_IMPLING_8756),
CRYSTAL_17(ImplingType.CRYSTAL, NpcID.CRYSTAL_IMPLING_8757),
DRAGON(ImplingType.DRAGON, NpcID.DRAGON_IMPLING),
DRAGON_2(ImplingType.DRAGON, NpcID.DRAGON_IMPLING_1654),
@@ -86,8 +85,6 @@ enum Impling
LUCKY(ImplingType.LUCKY, NpcID.LUCKY_IMPLING),
LUCKY_2(ImplingType.LUCKY, NpcID.LUCKY_IMPLING_7302);
private ImplingType implingType;
private final int npcId;

View File

@@ -235,7 +235,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 19,
keyName = "showcrystal",
keyName = "showCrystal",
name = "Show Crystal implings",
description = "Configures whether or not Crystal impling tags are displayed"
)
@@ -252,7 +252,7 @@ public interface ImplingsConfig extends Config
)
default Color getCrystalColor()
{
return new Color(2, 255, 251);
return new Color(93, 188, 210);
}
@ConfigItem(

View File

@@ -309,6 +309,7 @@ public class ImplingsPlugin extends Plugin
return this.getNinjaColor;
case CRYSTAL:
return this.getCrystalColor;
case DRAGON:
return this.getDragonColor;
case LUCKY:

View File

@@ -30,426 +30,16 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import static net.runelite.api.ItemID.ADMIRAL_PIE;
import static net.runelite.api.ItemID.AGILITY_POTION1;
import static net.runelite.api.ItemID.AGILITY_POTION2;
import static net.runelite.api.ItemID.AGILITY_POTION3;
import static net.runelite.api.ItemID.AGILITY_POTION4;
import static net.runelite.api.ItemID.ANCHOVIES;
import static net.runelite.api.ItemID.ANCHOVY_PIZZA;
import static net.runelite.api.ItemID.ANGLERFISH;
import static net.runelite.api.ItemID.APPLE_PIE;
import static net.runelite.api.ItemID.ATTACK_POTION1;
import static net.runelite.api.ItemID.ATTACK_POTION2;
import static net.runelite.api.ItemID.ATTACK_POTION3;
import static net.runelite.api.ItemID.ATTACK_POTION4;
import static net.runelite.api.ItemID.AUTUMN_SQIRKJUICE;
import static net.runelite.api.ItemID.BAGUETTE;
import static net.runelite.api.ItemID.BAKED_POTATO;
import static net.runelite.api.ItemID.BANANA;
import static net.runelite.api.ItemID.BANDAGES;
import static net.runelite.api.ItemID.BASS;
import static net.runelite.api.ItemID.BASTION_POTION1;
import static net.runelite.api.ItemID.BASTION_POTION2;
import static net.runelite.api.ItemID.BASTION_POTION3;
import static net.runelite.api.ItemID.BASTION_POTION4;
import static net.runelite.api.ItemID.BATTLEMAGE_POTION1;
import static net.runelite.api.ItemID.BATTLEMAGE_POTION2;
import static net.runelite.api.ItemID.BATTLEMAGE_POTION3;
import static net.runelite.api.ItemID.BATTLEMAGE_POTION4;
import static net.runelite.api.ItemID.BAT_SHISH;
import static net.runelite.api.ItemID.BOTANICAL_PIE;
import static net.runelite.api.ItemID.BOTTLE_OF_WINE;
import static net.runelite.api.ItemID.BRAWK_FISH_3;
import static net.runelite.api.ItemID.BREAD;
import static net.runelite.api.ItemID.CABBAGE;
import static net.runelite.api.ItemID.CABBAGE_1967;
import static net.runelite.api.ItemID.CAKE;
import static net.runelite.api.ItemID.CAVE_EEL;
import static net.runelite.api.ItemID.CAVIAR;
import static net.runelite.api.ItemID.CHEESE;
import static net.runelite.api.ItemID.CHEESETOM_BATTA;
import static net.runelite.api.ItemID.CHILLI_CON_CARNE;
import static net.runelite.api.ItemID.CHILLI_POTATO;
import static net.runelite.api.ItemID.CHOCCHIP_CRUNCHIES;
import static net.runelite.api.ItemID.CHOCICE;
import static net.runelite.api.ItemID.CHOCOLATEY_MILK;
import static net.runelite.api.ItemID.CHOCOLATE_BAR;
import static net.runelite.api.ItemID.CHOCOLATE_BOMB;
import static net.runelite.api.ItemID.CHOCOLATE_CAKE;
import static net.runelite.api.ItemID.CHOCOLATE_SLICE;
import static net.runelite.api.ItemID.CHOC_SATURDAY;
import static net.runelite.api.ItemID.CHOPPED_ONION;
import static net.runelite.api.ItemID.CHOPPED_TOMATO;
import static net.runelite.api.ItemID.CHOPPED_TUNA;
import static net.runelite.api.ItemID.COATED_FROGS_LEGS;
import static net.runelite.api.ItemID.COD;
import static net.runelite.api.ItemID.COMBAT_POTION1;
import static net.runelite.api.ItemID.COMBAT_POTION2;
import static net.runelite.api.ItemID.COMBAT_POTION3;
import static net.runelite.api.ItemID.COMBAT_POTION4;
import static net.runelite.api.ItemID.COOKED_CHICKEN;
import static net.runelite.api.ItemID.COOKED_CHOMPY;
import static net.runelite.api.ItemID.COOKED_CRAB_MEAT;
import static net.runelite.api.ItemID.COOKED_FISHCAKE;
import static net.runelite.api.ItemID.COOKED_JUBBLY;
import static net.runelite.api.ItemID.COOKED_KARAMBWAN;
import static net.runelite.api.ItemID.COOKED_MEAT;
import static net.runelite.api.ItemID.COOKED_RABBIT;
import static net.runelite.api.ItemID.COOKED_SLIMY_EEL;
import static net.runelite.api.ItemID.COOKED_SWEETCORN;
import static net.runelite.api.ItemID.CURRY;
import static net.runelite.api.ItemID.DARK_CRAB;
import static net.runelite.api.ItemID.DEFENCE_POTION1;
import static net.runelite.api.ItemID.DEFENCE_POTION2;
import static net.runelite.api.ItemID.DEFENCE_POTION3;
import static net.runelite.api.ItemID.DEFENCE_POTION4;
import static net.runelite.api.ItemID.DRUNK_DRAGON;
import static net.runelite.api.ItemID.DWELLBERRIES;
import static net.runelite.api.ItemID.EASTER_EGG;
import static net.runelite.api.ItemID.EDIBLE_SEAWEED;
import static net.runelite.api.ItemID.EEL_SUSHI;
import static net.runelite.api.ItemID.EGG_AND_TOMATO;
import static net.runelite.api.ItemID.EGG_POTATO;
import static net.runelite.api.ItemID.ELDER_1;
import static net.runelite.api.ItemID.ELDER_1_20921;
import static net.runelite.api.ItemID.ELDER_2;
import static net.runelite.api.ItemID.ELDER_2_20922;
import static net.runelite.api.ItemID.ELDER_3;
import static net.runelite.api.ItemID.ELDER_3_20923;
import static net.runelite.api.ItemID.ELDER_4;
import static net.runelite.api.ItemID.ELDER_4_20924;
import static net.runelite.api.ItemID.ELDER_POTION_1;
import static net.runelite.api.ItemID.ELDER_POTION_2;
import static net.runelite.api.ItemID.ELDER_POTION_3;
import static net.runelite.api.ItemID.ELDER_POTION_4;
import static net.runelite.api.ItemID.ENERGY_POTION1;
import static net.runelite.api.ItemID.ENERGY_POTION2;
import static net.runelite.api.ItemID.ENERGY_POTION3;
import static net.runelite.api.ItemID.ENERGY_POTION4;
import static net.runelite.api.ItemID.FAT_SNAIL_MEAT;
import static net.runelite.api.ItemID.FIELD_RATION;
import static net.runelite.api.ItemID.FILLETS;
import static net.runelite.api.ItemID.FINGERS;
import static net.runelite.api.ItemID.FISHING_POTION1;
import static net.runelite.api.ItemID.FISHING_POTION2;
import static net.runelite.api.ItemID.FISHING_POTION3;
import static net.runelite.api.ItemID.FISHING_POTION4;
import static net.runelite.api.ItemID.FISH_PIE;
import static net.runelite.api.ItemID.FRIED_MUSHROOMS;
import static net.runelite.api.ItemID.FRIED_ONIONS;
import static net.runelite.api.ItemID.FROGBURGER;
import static net.runelite.api.ItemID.FROGSPAWN_GUMBO;
import static net.runelite.api.ItemID.FROG_SPAWN;
import static net.runelite.api.ItemID.FRUIT_BATTA;
import static net.runelite.api.ItemID.FRUIT_BLAST;
import static net.runelite.api.ItemID.GARDEN_PIE;
import static net.runelite.api.ItemID.GIANT_CARP;
import static net.runelite.api.ItemID.GIRAL_BAT_2;
import static net.runelite.api.ItemID.GOUT_TUBER;
import static net.runelite.api.ItemID.GREEN_GLOOP_SOUP;
import static net.runelite.api.ItemID.GRUBS__LA_MODE;
import static net.runelite.api.ItemID.GUANIC_BAT_0;
import static net.runelite.api.ItemID.GUTHIX_REST1;
import static net.runelite.api.ItemID.GUTHIX_REST2;
import static net.runelite.api.ItemID.GUTHIX_REST3;
import static net.runelite.api.ItemID.GUTHIX_REST4;
import static net.runelite.api.ItemID.HALF_AN_ADMIRAL_PIE;
import static net.runelite.api.ItemID.HALF_AN_APPLE_PIE;
import static net.runelite.api.ItemID.HALF_A_BOTANICAL_PIE;
import static net.runelite.api.ItemID.HALF_A_FISH_PIE;
import static net.runelite.api.ItemID.HALF_A_GARDEN_PIE;
import static net.runelite.api.ItemID.HALF_A_MEAT_PIE;
import static net.runelite.api.ItemID.HALF_A_MUSHROOM_PIE;
import static net.runelite.api.ItemID.HALF_A_REDBERRY_PIE;
import static net.runelite.api.ItemID.HALF_A_SUMMER_PIE;
import static net.runelite.api.ItemID.HALF_A_WILD_PIE;
import static net.runelite.api.ItemID.HERRING;
import static net.runelite.api.ItemID.HUNTER_POTION1;
import static net.runelite.api.ItemID.HUNTER_POTION2;
import static net.runelite.api.ItemID.HUNTER_POTION3;
import static net.runelite.api.ItemID.HUNTER_POTION4;
import static net.runelite.api.ItemID.IMBUED_HEART;
import static net.runelite.api.ItemID.JANGERBERRIES;
import static net.runelite.api.ItemID.JUG_OF_WINE;
import static net.runelite.api.ItemID.KODAI_1;
import static net.runelite.api.ItemID.KODAI_1_20945;
import static net.runelite.api.ItemID.KODAI_2;
import static net.runelite.api.ItemID.KODAI_2_20946;
import static net.runelite.api.ItemID.KODAI_3;
import static net.runelite.api.ItemID.KODAI_3_20947;
import static net.runelite.api.ItemID.KODAI_4;
import static net.runelite.api.ItemID.KODAI_4_20948;
import static net.runelite.api.ItemID.KODAI_POTION_1;
import static net.runelite.api.ItemID.KODAI_POTION_2;
import static net.runelite.api.ItemID.KODAI_POTION_3;
import static net.runelite.api.ItemID.KODAI_POTION_4;
import static net.runelite.api.ItemID.KRYKET_BAT_4;
import static net.runelite.api.ItemID.KYREN_FISH_6;
import static net.runelite.api.ItemID.LAVA_EEL;
import static net.runelite.api.ItemID.LECKISH_FISH_2;
import static net.runelite.api.ItemID.LEMON;
import static net.runelite.api.ItemID.LEMON_CHUNKS;
import static net.runelite.api.ItemID.LEMON_SLICES;
import static net.runelite.api.ItemID.LIME;
import static net.runelite.api.ItemID.LIME_CHUNKS;
import static net.runelite.api.ItemID.LIME_SLICES;
import static net.runelite.api.ItemID.LOACH;
import static net.runelite.api.ItemID.LOBSTER;
import static net.runelite.api.ItemID.MACKEREL;
import static net.runelite.api.ItemID.MAGIC_ESSENCE1;
import static net.runelite.api.ItemID.MAGIC_ESSENCE2;
import static net.runelite.api.ItemID.MAGIC_ESSENCE3;
import static net.runelite.api.ItemID.MAGIC_ESSENCE4;
import static net.runelite.api.ItemID.MAGIC_POTION1;
import static net.runelite.api.ItemID.MAGIC_POTION2;
import static net.runelite.api.ItemID.MAGIC_POTION3;
import static net.runelite.api.ItemID.MAGIC_POTION4;
import static net.runelite.api.ItemID.MANTA_RAY;
import static net.runelite.api.ItemID.MEAT_PIE;
import static net.runelite.api.ItemID.MEAT_PIZZA;
import static net.runelite.api.ItemID.MINT_CAKE;
import static net.runelite.api.ItemID.MONKFISH;
import static net.runelite.api.ItemID.MOONLIGHT_MEAD;
import static net.runelite.api.ItemID.MURNG_BAT_5;
import static net.runelite.api.ItemID.MUSHROOMS;
import static net.runelite.api.ItemID.MUSHROOM_PIE;
import static net.runelite.api.ItemID.MUSHROOM_POTATO;
import static net.runelite.api.ItemID.MUSHROOM__ONION;
import static net.runelite.api.ItemID.MYCIL_FISH_4;
import static net.runelite.api.ItemID.ONION;
import static net.runelite.api.ItemID.ORANGE;
import static net.runelite.api.ItemID.ORANGE_CHUNKS;
import static net.runelite.api.ItemID.ORANGE_SLICES;
import static net.runelite.api.ItemID.OVERLOAD_1;
import static net.runelite.api.ItemID.OVERLOAD_1_20985;
import static net.runelite.api.ItemID.OVERLOAD_1_20989;
import static net.runelite.api.ItemID.OVERLOAD_1_20993;
import static net.runelite.api.ItemID.OVERLOAD_2;
import static net.runelite.api.ItemID.OVERLOAD_2_20986;
import static net.runelite.api.ItemID.OVERLOAD_2_20990;
import static net.runelite.api.ItemID.OVERLOAD_2_20994;
import static net.runelite.api.ItemID.OVERLOAD_3;
import static net.runelite.api.ItemID.OVERLOAD_3_20987;
import static net.runelite.api.ItemID.OVERLOAD_3_20991;
import static net.runelite.api.ItemID.OVERLOAD_3_20995;
import static net.runelite.api.ItemID.OVERLOAD_4;
import static net.runelite.api.ItemID.OVERLOAD_4_20988;
import static net.runelite.api.ItemID.OVERLOAD_4_20992;
import static net.runelite.api.ItemID.OVERLOAD_4_20996;
import static net.runelite.api.ItemID.PAPAYA_FRUIT;
import static net.runelite.api.ItemID.PEACH;
import static net.runelite.api.ItemID.PHLUXIA_BAT_3;
import static net.runelite.api.ItemID.PIKE;
import static net.runelite.api.ItemID.PINEAPPLE_CHUNKS;
import static net.runelite.api.ItemID.PINEAPPLE_PIZZA;
import static net.runelite.api.ItemID.PINEAPPLE_PUNCH;
import static net.runelite.api.ItemID.PINEAPPLE_RING;
import static net.runelite.api.ItemID.PLAIN_PIZZA;
import static net.runelite.api.ItemID.POISON_KARAMBWAN;
import static net.runelite.api.ItemID.POTATO;
import static net.runelite.api.ItemID.POTATO_WITH_BUTTER;
import static net.runelite.api.ItemID.POTATO_WITH_CHEESE;
import static net.runelite.api.ItemID.POT_OF_CREAM;
import static net.runelite.api.ItemID.PRAEL_BAT_1;
import static net.runelite.api.ItemID.PRAYER_POTION1;
import static net.runelite.api.ItemID.PRAYER_POTION2;
import static net.runelite.api.ItemID.PRAYER_POTION3;
import static net.runelite.api.ItemID.PRAYER_POTION4;
import static net.runelite.api.ItemID.PREMADE_CHOC_BOMB;
import static net.runelite.api.ItemID.PREMADE_CHOC_SDY;
import static net.runelite.api.ItemID.PREMADE_CH_CRUNCH;
import static net.runelite.api.ItemID.PREMADE_CT_BATTA;
import static net.runelite.api.ItemID.PREMADE_DR_DRAGON;
import static net.runelite.api.ItemID.PREMADE_FRT_BATTA;
import static net.runelite.api.ItemID.PREMADE_FR_BLAST;
import static net.runelite.api.ItemID.PREMADE_P_PUNCH;
import static net.runelite.api.ItemID.PREMADE_SGG;
import static net.runelite.api.ItemID.PREMADE_SY_CRUNCH;
import static net.runelite.api.ItemID.PREMADE_TD_BATTA;
import static net.runelite.api.ItemID.PREMADE_TD_CRUNCH;
import static net.runelite.api.ItemID.PREMADE_TTL;
import static net.runelite.api.ItemID.PREMADE_VEG_BALL;
import static net.runelite.api.ItemID.PREMADE_VEG_BATTA;
import static net.runelite.api.ItemID.PREMADE_WIZ_BLZD;
import static net.runelite.api.ItemID.PREMADE_WM_BATTA;
import static net.runelite.api.ItemID.PREMADE_WM_CRUN;
import static net.runelite.api.ItemID.PREMADE_WORM_HOLE;
import static net.runelite.api.ItemID.PSYKK_BAT_6;
import static net.runelite.api.ItemID.PUMPKIN;
import static net.runelite.api.ItemID.PURPLE_SWEETS_10476;
import static net.runelite.api.ItemID.PYSK_FISH_0;
import static net.runelite.api.ItemID.RAINBOW_FISH;
import static net.runelite.api.ItemID.RANGING_POTION1;
import static net.runelite.api.ItemID.RANGING_POTION2;
import static net.runelite.api.ItemID.RANGING_POTION3;
import static net.runelite.api.ItemID.RANGING_POTION4;
import static net.runelite.api.ItemID.REDBERRY_PIE;
import static net.runelite.api.ItemID.RESTORE_POTION1;
import static net.runelite.api.ItemID.RESTORE_POTION2;
import static net.runelite.api.ItemID.RESTORE_POTION3;
import static net.runelite.api.ItemID.RESTORE_POTION4;
import static net.runelite.api.ItemID.REVITALISATION_1_20957;
import static net.runelite.api.ItemID.REVITALISATION_2_20958;
import static net.runelite.api.ItemID.REVITALISATION_3_20959;
import static net.runelite.api.ItemID.REVITALISATION_4_20960;
import static net.runelite.api.ItemID.ROAST_BEAST_MEAT;
import static net.runelite.api.ItemID.ROAST_BIRD_MEAT;
import static net.runelite.api.ItemID.ROAST_FROG;
import static net.runelite.api.ItemID.ROAST_RABBIT;
import static net.runelite.api.ItemID.ROE;
import static net.runelite.api.ItemID.ROLL;
import static net.runelite.api.ItemID.ROQED_FISH_5;
import static net.runelite.api.ItemID.SALMON;
import static net.runelite.api.ItemID.SANFEW_SERUM1;
import static net.runelite.api.ItemID.SANFEW_SERUM2;
import static net.runelite.api.ItemID.SANFEW_SERUM3;
import static net.runelite.api.ItemID.SANFEW_SERUM4;
import static net.runelite.api.ItemID.SARADOMIN_BREW1;
import static net.runelite.api.ItemID.SARADOMIN_BREW2;
import static net.runelite.api.ItemID.SARADOMIN_BREW3;
import static net.runelite.api.ItemID.SARADOMIN_BREW4;
import static net.runelite.api.ItemID.SARDINE;
import static net.runelite.api.ItemID.SEA_TURTLE;
import static net.runelite.api.ItemID.SHARK;
import static net.runelite.api.ItemID.SHORT_GREEN_GUY;
import static net.runelite.api.ItemID.SHRIMPS;
import static net.runelite.api.ItemID.SLICED_BANANA;
import static net.runelite.api.ItemID.SLICE_OF_CAKE;
import static net.runelite.api.ItemID.SPICY_CRUNCHIES;
import static net.runelite.api.ItemID.SPICY_SAUCE;
import static net.runelite.api.ItemID.SPICY_STEW;
import static net.runelite.api.ItemID.SPIDER_ON_SHAFT_6299;
import static net.runelite.api.ItemID.SPIDER_ON_STICK_6297;
import static net.runelite.api.ItemID.SPINACH_ROLL;
import static net.runelite.api.ItemID.SPRING_SQIRKJUICE;
import static net.runelite.api.ItemID.SQUARE_SANDWICH;
import static net.runelite.api.ItemID.STAMINA_POTION1;
import static net.runelite.api.ItemID.STAMINA_POTION2;
import static net.runelite.api.ItemID.STAMINA_POTION3;
import static net.runelite.api.ItemID.STAMINA_POTION4;
import static net.runelite.api.ItemID.STEW;
import static net.runelite.api.ItemID.STRANGE_FRUIT;
import static net.runelite.api.ItemID.STRAWBERRY;
import static net.runelite.api.ItemID.STRENGTH_POTION1;
import static net.runelite.api.ItemID.STRENGTH_POTION2;
import static net.runelite.api.ItemID.STRENGTH_POTION3;
import static net.runelite.api.ItemID.STRENGTH_POTION4;
import static net.runelite.api.ItemID.STUFFED_SNAKE;
import static net.runelite.api.ItemID.SUMMER_PIE;
import static net.runelite.api.ItemID.SUMMER_SQIRKJUICE;
import static net.runelite.api.ItemID.SUPER_ATTACK1;
import static net.runelite.api.ItemID.SUPER_ATTACK2;
import static net.runelite.api.ItemID.SUPER_ATTACK3;
import static net.runelite.api.ItemID.SUPER_ATTACK4;
import static net.runelite.api.ItemID.SUPER_COMBAT_POTION1;
import static net.runelite.api.ItemID.SUPER_COMBAT_POTION2;
import static net.runelite.api.ItemID.SUPER_COMBAT_POTION3;
import static net.runelite.api.ItemID.SUPER_COMBAT_POTION4;
import static net.runelite.api.ItemID.SUPER_DEFENCE1;
import static net.runelite.api.ItemID.SUPER_DEFENCE2;
import static net.runelite.api.ItemID.SUPER_DEFENCE3;
import static net.runelite.api.ItemID.SUPER_DEFENCE4;
import static net.runelite.api.ItemID.SUPER_ENERGY1;
import static net.runelite.api.ItemID.SUPER_ENERGY2;
import static net.runelite.api.ItemID.SUPER_ENERGY3;
import static net.runelite.api.ItemID.SUPER_ENERGY4;
import static net.runelite.api.ItemID.SUPER_MAGIC_POTION_1;
import static net.runelite.api.ItemID.SUPER_MAGIC_POTION_2;
import static net.runelite.api.ItemID.SUPER_MAGIC_POTION_3;
import static net.runelite.api.ItemID.SUPER_MAGIC_POTION_4;
import static net.runelite.api.ItemID.SUPER_RANGING_1;
import static net.runelite.api.ItemID.SUPER_RANGING_2;
import static net.runelite.api.ItemID.SUPER_RANGING_3;
import static net.runelite.api.ItemID.SUPER_RANGING_4;
import static net.runelite.api.ItemID.SUPER_RESTORE1;
import static net.runelite.api.ItemID.SUPER_RESTORE2;
import static net.runelite.api.ItemID.SUPER_RESTORE3;
import static net.runelite.api.ItemID.SUPER_RESTORE4;
import static net.runelite.api.ItemID.SUPER_STRENGTH1;
import static net.runelite.api.ItemID.SUPER_STRENGTH2;
import static net.runelite.api.ItemID.SUPER_STRENGTH3;
import static net.runelite.api.ItemID.SUPER_STRENGTH4;
import static net.runelite.api.ItemID.SUPHI_FISH_1;
import static net.runelite.api.ItemID.SWEETCORN_7088;
import static net.runelite.api.ItemID.SWORDFISH;
import static net.runelite.api.ItemID.TANGLED_TOADS_LEGS;
import static net.runelite.api.ItemID.THIN_SNAIL_MEAT;
import static net.runelite.api.ItemID.TOAD_BATTA;
import static net.runelite.api.ItemID.TOAD_CRUNCHIES;
import static net.runelite.api.ItemID.TOMATO;
import static net.runelite.api.ItemID.TRIANGLE_SANDWICH;
import static net.runelite.api.ItemID.TROUT;
import static net.runelite.api.ItemID.TUNA;
import static net.runelite.api.ItemID.TUNA_AND_CORN;
import static net.runelite.api.ItemID.TUNA_POTATO;
import static net.runelite.api.ItemID.TWISTED_1;
import static net.runelite.api.ItemID.TWISTED_1_20933;
import static net.runelite.api.ItemID.TWISTED_2;
import static net.runelite.api.ItemID.TWISTED_2_20934;
import static net.runelite.api.ItemID.TWISTED_3;
import static net.runelite.api.ItemID.TWISTED_3_20935;
import static net.runelite.api.ItemID.TWISTED_4;
import static net.runelite.api.ItemID.TWISTED_4_20936;
import static net.runelite.api.ItemID.TWISTED_POTION_1;
import static net.runelite.api.ItemID.TWISTED_POTION_2;
import static net.runelite.api.ItemID.TWISTED_POTION_3;
import static net.runelite.api.ItemID.TWISTED_POTION_4;
import static net.runelite.api.ItemID.UGTHANKI_KEBAB;
import static net.runelite.api.ItemID.UGTHANKI_KEBAB_1885;
import static net.runelite.api.ItemID.VEGETABLE_BATTA;
import static net.runelite.api.ItemID.VEG_BALL;
import static net.runelite.api.ItemID.WATERMELON_SLICE;
import static net.runelite.api.ItemID.WHITE_TREE_FRUIT;
import static net.runelite.api.ItemID.WILD_PIE;
import static net.runelite.api.ItemID.WINTER_SQIRKJUICE;
import static net.runelite.api.ItemID.WIZARD_BLIZZARD;
import static net.runelite.api.ItemID.WORM_BATTA;
import static net.runelite.api.ItemID.WORM_CRUNCHIES;
import static net.runelite.api.ItemID.WORM_HOLE;
import static net.runelite.api.ItemID.XERICS_AID_1_20981;
import static net.runelite.api.ItemID.XERICS_AID_2_20982;
import static net.runelite.api.ItemID.XERICS_AID_3_20983;
import static net.runelite.api.ItemID.XERICS_AID_4_20984;
import static net.runelite.api.ItemID.ZAMORAK_BREW1;
import static net.runelite.api.ItemID.ZAMORAK_BREW2;
import static net.runelite.api.ItemID.ZAMORAK_BREW3;
import static net.runelite.api.ItemID.ZAMORAK_BREW4;
import static net.runelite.api.ItemID._12_ANCHOVY_PIZZA;
import static net.runelite.api.ItemID._12_MEAT_PIZZA;
import static net.runelite.api.ItemID._12_PINEAPPLE_PIZZA;
import static net.runelite.api.ItemID._12_PLAIN_PIZZA;
import static net.runelite.api.ItemID._23_CAKE;
import static net.runelite.api.ItemID._23_CHOCOLATE_CAKE;
import static net.runelite.client.plugins.itemstats.Builders.boost;
import static net.runelite.client.plugins.itemstats.Builders.combo;
import static net.runelite.client.plugins.itemstats.Builders.dec;
import static net.runelite.client.plugins.itemstats.Builders.food;
import static net.runelite.client.plugins.itemstats.Builders.heal;
import static net.runelite.client.plugins.itemstats.Builders.perc;
import static net.runelite.client.plugins.itemstats.Builders.range;
import static net.runelite.api.ItemID.*;
import static net.runelite.client.plugins.itemstats.Builders.*;
import net.runelite.client.plugins.itemstats.food.Anglerfish;
import net.runelite.client.plugins.itemstats.potions.GauntletPotion;
import net.runelite.client.plugins.itemstats.potions.PrayerPotion;
import net.runelite.client.plugins.itemstats.potions.SaradominBrew;
import net.runelite.client.plugins.itemstats.potions.SuperRestore;
import net.runelite.client.plugins.itemstats.special.CastleWarsBandage;
import net.runelite.client.plugins.itemstats.special.SpicyStew;
import static net.runelite.client.plugins.itemstats.stats.Stats.AGILITY;
import static net.runelite.client.plugins.itemstats.stats.Stats.ATTACK;
import static net.runelite.client.plugins.itemstats.stats.Stats.CRAFTING;
import static net.runelite.client.plugins.itemstats.stats.Stats.DEFENCE;
import static net.runelite.client.plugins.itemstats.stats.Stats.FARMING;
import static net.runelite.client.plugins.itemstats.stats.Stats.FISHING;
import static net.runelite.client.plugins.itemstats.stats.Stats.HERBLORE;
import static net.runelite.client.plugins.itemstats.stats.Stats.HITPOINTS;
import static net.runelite.client.plugins.itemstats.stats.Stats.HUNTER;
import static net.runelite.client.plugins.itemstats.stats.Stats.MAGIC;
import static net.runelite.client.plugins.itemstats.stats.Stats.PRAYER;
import static net.runelite.client.plugins.itemstats.stats.Stats.RANGED;
import static net.runelite.client.plugins.itemstats.stats.Stats.RUN_ENERGY;
import static net.runelite.client.plugins.itemstats.stats.Stats.SLAYER;
import static net.runelite.client.plugins.itemstats.stats.Stats.STRENGTH;
import static net.runelite.client.plugins.itemstats.stats.Stats.THIEVING;
import static net.runelite.client.plugins.itemstats.stats.Stats.*;
@Singleton
@Slf4j
@@ -609,6 +199,10 @@ public class ItemStatChanges
add(boost(MAGIC, perc(.10, 1)), IMBUED_HEART);
add(combo(boost(ATTACK, 2), boost(STRENGTH, 1), heal(DEFENCE, -1)), JANGERBERRIES);
// Gauntlet items
add(heal(HITPOINTS, 20), PADDLEFISH);
add(new GauntletPotion(), EGNIOL_POTION_1, EGNIOL_POTION_2, EGNIOL_POTION_3, EGNIOL_POTION_4);
log.debug("{} items; {} behaviours loaded", effects.size(), new HashSet<>(effects.values()).size());
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.itemstats.potions;
import lombok.RequiredArgsConstructor;
import net.runelite.api.Client;
import net.runelite.api.Skill;
import static net.runelite.client.plugins.itemstats.Builders.heal;
import net.runelite.client.plugins.itemstats.Effect;
import net.runelite.client.plugins.itemstats.StatChange;
import net.runelite.client.plugins.itemstats.StatsChanges;
import net.runelite.client.plugins.itemstats.stats.Stats;
/**
* Acts like a prayer potion and stamina dose combined but restores 40 energy instead of 20
*/
@RequiredArgsConstructor
public class GauntletPotion implements Effect
{
private static final int PRAYER_RESTORE_DELTA = 7;
private static final double PRAYER_RESTORE_PERCENT = .25;
@Override
public StatsChanges calculate(Client client)
{
// Restores prayer similar to PrayerPotion but there aren't any possible boost so simplify the calculation
final int restorePerc = (int) (client.getRealSkillLevel(Skill.PRAYER) * PRAYER_RESTORE_PERCENT);
final StatChange prayer = heal(Stats.PRAYER, restorePerc + PRAYER_RESTORE_DELTA).effect(client);
final StatChange runEnergy = heal(Stats.RUN_ENERGY, 40).effect(client);
final StatsChanges changes = new StatsChanges(2);
changes.setStatChanges(new StatChange[]{runEnergy, prayer});
return changes;
}
}

View File

@@ -913,23 +913,11 @@ default CharterOption charterOption()
return "";
}
@ConfigItem(
keyName = "swapSmithing",
name = "Swap Smithing",
description = "Enables swapping of 'Smith-1' and 'Smith-all' options.",
position = 2,
group = "Skilling"
)
default boolean getSwapSmithing()
{
return false;
}
@ConfigItem(
keyName = "swapTanning",
name = "Swap Tanning",
description = "Enables swapping of 'Tan-1' and 'Tan-all' options.",
position = 3,
position = 2,
group = "Skilling"
)
default boolean getSwapTanning()
@@ -941,7 +929,7 @@ default CharterOption charterOption()
keyName = "swapSawmill",
name = "Swap Sawmill Operator",
description = "Makes 'Buy-plank' the default option on the Sawmill Operator.",
position = 4,
position = 3,
group = "Skilling"
)
default boolean getSwapSawmill()
@@ -953,7 +941,7 @@ default CharterOption charterOption()
keyName = "swapSawmillPlanks",
name = "Swap Buy Planks",
description = "Makes 'Buy All' the default option when buying planks.",
position = 5,
position = 4,
group = "Skilling"
)
default boolean getSwapSawmillPlanks()
@@ -965,7 +953,7 @@ default CharterOption charterOption()
keyName = "swapPuroPuro",
name = "Swap Puro-Puro Wheat",
description = "",
position = 6,
position = 5,
group = "Skilling"
)
default boolean getSwapPuro()

View File

@@ -279,7 +279,6 @@ public class MenuEntrySwapperPlugin extends Plugin
private String getSellFiftyItems;
private boolean getEasyConstruction;
private String getEasyConstructionItems;
private boolean getSwapSmithing;
private boolean getSwapTanning;
private boolean getSwapSawmill;
private boolean getSwapSawmillPlanks;
@@ -958,18 +957,6 @@ public class MenuEntrySwapperPlugin extends Plugin
}
}
else if (this.getSwapSmithing && option.contains("smith"))
{
if (option.equalsIgnoreCase("Smith 1"))
{
swap(client, "Smith All", option, target);
}
else if (option.equalsIgnoreCase("Smith 1 Set"))
{
swap(client, "Smith All Sets", option, target);
}
}
else if (this.getSwapTanning && option.equalsIgnoreCase("Tan 1"))
{
swap(client, "Tan All", option, target);
@@ -1866,7 +1853,6 @@ public class MenuEntrySwapperPlugin extends Plugin
this.getSellFiftyItems = config.getSellFiftyItems();
this.getEasyConstruction = config.getEasyConstruction();
this.getEasyConstructionItems = config.getEasyConstructionItems();
this.getSwapSmithing = config.getSwapSmithing();
this.getSwapTanning = config.getSwapTanning();
this.getSwapSawmill = config.getSwapSawmill();
this.getSwapSawmillPlanks = config.getSwapSawmillPlanks();

View File

@@ -35,7 +35,7 @@ enum Rock
{
TIN(Duration.ofMillis(2400), 0, ROCKS_11360, ROCKS_11361),
COPPER(Duration.ofMillis(2400), 0, ROCKS_10943, ROCKS_11161),
IRON(Duration.ofMillis(5400), 0, ROCKS_11364, ROCKS_11365)
IRON(Duration.ofMillis(5400), 0, ROCKS_11364, ROCKS_11365, ROCKS_36203)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
@@ -43,7 +43,7 @@ enum Rock
return inMiningGuild ? Duration.ofMillis(2400) : super.respawnTime;
}
},
COAL(Duration.ofMillis(29400), 0, ROCKS_11366, ROCKS_11367)
COAL(Duration.ofMillis(29400), 0, ROCKS_11366, ROCKS_11367, ROCKS_36204)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
@@ -51,11 +51,11 @@ enum Rock
return inMiningGuild ? Duration.ofMillis(14400) : super.respawnTime;
}
},
SILVER(Duration.ofMinutes(1), 0, ROCKS_11368, ROCKS_11369),
SILVER(Duration.ofMinutes(1), 0, ROCKS_11368, ROCKS_11369, ROCKS_36205),
SANDSTONE(Duration.ofMillis(5400), 0, ROCKS_11386),
GOLD(Duration.ofMinutes(1), 0, ROCKS_11370, ROCKS_11371),
GOLD(Duration.ofMinutes(1), 0, ROCKS_11370, ROCKS_11371, ROCKS_36206),
GRANITE(Duration.ofMillis(5400), 0, ROCKS_11387),
MITHRIL(Duration.ofMinutes(2), 0, ROCKS_11372, ROCKS_11373)
MITHRIL(Duration.ofMinutes(2), 0, ROCKS_11372, ROCKS_11373, ROCKS_36207)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
@@ -63,7 +63,7 @@ enum Rock
return inMiningGuild ? Duration.ofMinutes(1) : super.respawnTime;
}
},
ADAMANTITE(Duration.ofMinutes(4), 0, ROCKS_11374, ROCKS_11375)
ADAMANTITE(Duration.ofMinutes(4), 0, ROCKS_11374, ROCKS_11375, ROCKS_36208)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
@@ -71,7 +71,7 @@ enum Rock
return inMiningGuild ? Duration.ofMinutes(2) : super.respawnTime;
}
},
RUNITE(Duration.ofMinutes(12), 0, ROCKS_11376, ROCKS_11377)
RUNITE(Duration.ofMinutes(12), 0, ROCKS_11376, ROCKS_11377, ROCKS_36209)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)

View File

@@ -115,9 +115,9 @@ import okhttp3.Response;
import org.jetbrains.annotations.Nullable;
@PluginDescriptor(
name = "Screenshot",
description = "Enable the manual and automatic taking of screenshots",
tags = {"external", "images", "imgur", "integration", "notifications"}
name = "Screenshot",
description = "Enable the manual and automatic taking of screenshots",
tags = {"external", "images", "imgur", "integration", "notifications"}
)
@Slf4j
@Singleton
@@ -136,8 +136,8 @@ public class ScreenshotPlugin extends Plugin
private static final Pattern UNTRADEABLE_DROP_PATTERN = Pattern.compile(".*Untradeable drop: ([^<>]+)(?:</col>)?");
private static final Pattern DUEL_END_PATTERN = Pattern.compile("You have now (won|lost) ([0-9]+) duels?\\.");
private static final ImmutableList<String> PET_MESSAGES = ImmutableList.of("You have a funny feeling like you're being followed",
"You feel something weird sneaking into your backpack",
"You have a funny feeling like you would have been followed");
"You feel something weird sneaking into your backpack",
"You have a funny feeling like you would have been followed");
private static String format(Date date)
{
@@ -253,25 +253,25 @@ public class ScreenshotPlugin extends Plugin
final BufferedImage iconImage = ImageUtil.getResourceStreamFromClass(getClass(), "screenshot.png");
titleBarButton = NavigationButton.builder()
.tab(false)
.tooltip("Take screenshot")
.icon(iconImage)
.onClick(() -> takeScreenshot(format(new Date())))
.popup(ImmutableMap
.<String, Runnable>builder()
.put("Open screenshot folder...", () ->
{
try
{
Desktop.getDesktop().open(SCREENSHOT_DIR);
}
catch (IOException ex)
{
log.warn("Error opening screenshot dir", ex);
}
})
.build())
.build();
.tab(false)
.tooltip("Take screenshot")
.icon(iconImage)
.onClick(() -> takeScreenshot(format(new Date())))
.popup(ImmutableMap
.<String, Runnable>builder()
.put("Open screenshot folder...", () ->
{
try
{
Desktop.getDesktop().open(SCREENSHOT_DIR);
}
catch (IOException ex)
{
log.warn("Error opening screenshot dir", ex);
}
})
.build())
.build();
clientToolbar.addNavigation(titleBarButton);
@@ -302,7 +302,7 @@ public class ScreenshotPlugin extends Plugin
private void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOGGED_IN
&& reportButton == null)
&& reportButton == null)
{
reportButton = spriteManager.getSprite(SpriteID.CHATBOX_REPORT_BUTTON, 0);
}
@@ -358,9 +358,17 @@ public class ScreenshotPlugin extends Plugin
private void onAnimationChanged(AnimationChanged e)
{
//this got refactored somewhere, but some things were missing
if (!this.screenshotFriendDeath || !this.screenshotPlayerDeath)
if (e.getActor().getAnimation() != 836)
{
return;
}
if (this.screenshotPlayerDeath && client.getLocalPlayer().equals(e.getActor()))
{
takeScreenshot("Death");
}
if (!(e.getActor() instanceof Player))
return;
@@ -705,7 +713,7 @@ public class ScreenshotPlugin extends Plugin
Consumer<Image> imageCallback = (img) ->
{
// This callback is on the game thread, move to executor thread
executor.submit(() -> takeScreenshot(fileName, img, subdirectory));
executor.submit(() -> takeScreenshot(fileName, img, subdirectory));
};
@@ -721,8 +729,8 @@ public class ScreenshotPlugin extends Plugin
private void takeScreenshot(String fileName, Image image, @Nullable String subdirectory)
{
BufferedImage screenshot = this.includeFrame
? new BufferedImage(clientUi.getWidth(), clientUi.getHeight(), BufferedImage.TYPE_INT_ARGB)
: new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
? new BufferedImage(clientUi.getWidth(), clientUi.getHeight(), BufferedImage.TYPE_INT_ARGB)
: new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics graphics = screenshot.getGraphics();
@@ -826,10 +834,10 @@ public class ScreenshotPlugin extends Plugin
{
RequestBody body = RequestBody.Companion.create(json, JSON);
request = new Request.Builder()
.url(IMGUR_IMAGE_UPLOAD_URL)
.addHeader("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.post(body)
.build();
.url(IMGUR_IMAGE_UPLOAD_URL)
.addHeader("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.post(body)
.build();
}
if (request != null)
@@ -848,13 +856,13 @@ public class ScreenshotPlugin extends Plugin
try (InputStream in = response.body().byteStream())
{
ImageUploadResponse imageUploadResponse = RuneLiteAPI.GSON
.fromJson(new InputStreamReader(in), ImageUploadResponse.class);
.fromJson(new InputStreamReader(in), ImageUploadResponse.class);
if (imageUploadResponse.isSuccess())
{
String link = imageUploadResponse.getData().getLink();
Clipboard.store(link);
Clipboard.store(link);
if (notifyWhenTaken)
{

View File

@@ -73,7 +73,13 @@ enum GameTimer
SKULL(SpriteID.PLAYER_KILLER_SKULL_523, GameTimerImageType.SPRITE, "Skull", 20, ChronoUnit.MINUTES),
ANTIPOISON(ItemID.ANTIPOISON4, GameTimerImageType.ITEM, "Antipoison"),
ANTIVENOM(ItemID.ANTIVENOM4, GameTimerImageType.ITEM, "Anti-venom"),
DRAGON_FIRE_SHIELD(ItemID.DRAGONFIRE_SHIELD_11284, GameTimerImageType.ITEM, "Dragonfire Shield Special", 2, ChronoUnit.MINUTES);
DRAGON_FIRE_SHIELD(ItemID.DRAGONFIRE_SHIELD_11284, GameTimerImageType.ITEM, "Dragonfire Shield Special", 2, ChronoUnit.MINUTES),
DIVINE_SUPER_ATTACK(ItemID.DIVINE_SUPER_ATTACK_POTION4, GameTimerImageType.ITEM, "Divine Super Attack", 5, ChronoUnit.MINUTES, true),
DIVINE_SUPER_STRENGTH(ItemID.DIVINE_SUPER_STRENGTH_POTION4, GameTimerImageType.ITEM, "Divine Super Strength", 5, ChronoUnit.MINUTES, true),
DIVINE_SUPER_DEFENCE(ItemID.DIVINE_SUPER_DEFENCE_POTION4, GameTimerImageType.ITEM, "Divine Super Defence", 5, ChronoUnit.MINUTES, true),
DIVINE_SUPER_COMBAT(ItemID.DIVINE_SUPER_COMBAT_POTION4, GameTimerImageType.ITEM, "Divine Super Combat", 5, ChronoUnit.MINUTES, true),
DIVINE_RANGING(ItemID.DIVINE_RANGING_POTION4, GameTimerImageType.ITEM, "Divine Ranging", 5, ChronoUnit.MINUTES, true),
DIVINE_MAGIC(ItemID.DIVINE_MAGIC_POTION4, GameTimerImageType.ITEM, "Divine Magic", 5, ChronoUnit.MINUTES, true);
private final Duration duration;
private final Integer graphicId;

View File

@@ -91,6 +91,16 @@ public interface TimersConfig extends Config
return true;
}
@ConfigItem(
keyName = "showDivine",
name = "Divine potion timer",
description = "Configures whether divine potion timer is displayed"
)
default boolean showDivine()
{
return true;
}
@ConfigItem(
keyName = "showCannon",
name = "Cannon timer",

View File

@@ -27,6 +27,7 @@
package net.runelite.client.plugins.timers;
import com.google.inject.Provides;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -113,10 +114,12 @@ public class TimersPlugin extends Plugin
private static final String SUPER_ANTIFIRE_EXPIRED_MESSAGE = "<col=7f007f>Your super antifire potion has expired.</col>";
private static final int VENOM_VALUE_CUTOFF = -40; // Antivenom < -40 =< Antipoison < 0
private static final int POISON_TICK_LENGTH = 30;
private static final Pattern DEADMAN_HALF_TELEBLOCK_PATTERN = Pattern.compile("<col=4f006f>A Tele Block spell has been cast on you by (.+). It will expire in 1 minute, 15 seconds.</col>");
private static final Pattern FULL_TELEBLOCK_PATTERN = Pattern.compile("<col=4f006f>A Tele Block spell has been cast on you by (.+). It will expire in 5 minutes, 0 seconds.</col>");
private static final Pattern HALF_TELEBLOCK_PATTERN = Pattern.compile("<col=4f006f>A Tele Block spell has been cast on you by (.+). It will expire in 2 minutes, 30 seconds.</col>");
private static final String SUPER_ANTIVENOM_DRINK_MESSAGE = "You drink some of your super antivenom potion";
private static final String KILLED_TELEBLOCK_OPPONENT_TEXT = "<col=4f006f>Your Tele Block has been removed because you killed ";
private static final Pattern DEADMAN_HALF_TELEBLOCK_PATTERN = Pattern.compile("<col=4f006f>A Tele Block spell has been cast on you by (.+)\\. It will expire in 1 minute, 15 seconds\\.</col>");
private static final Pattern FULL_TELEBLOCK_PATTERN = Pattern.compile("<col=4f006f>A Tele Block spell has been cast on you by (.+)\\. It will expire in 5 minutes, 0 seconds\\.</col>");
private static final Pattern HALF_TELEBLOCK_PATTERN = Pattern.compile("<col=4f006f>A Tele Block spell has been cast on you by (.+)\\. It will expire in 2 minutes, 30 seconds\\.</col>");
private static final Pattern DIVINE_POTION_PATTERN = Pattern.compile("You drink some of your divine (.+) potion\\.");
private TimerTimer freezeTimer;
private int freezeTime = -1; // time frozen, in game ticks
@@ -172,6 +175,7 @@ public class TimersPlugin extends Plugin
private boolean showSkull;
private boolean showStaffOfTheDead;
private boolean showAbyssalSireStun;
private boolean showDivine;
@Provides
TimersConfig getConfig(ConfigManager configManager)
@@ -355,6 +359,16 @@ public class TimersPlugin extends Plugin
removeGameTimer(PRAYER_ENHANCE);
}
if (!this.showDivine)
{
removeGameTimer(DIVINE_SUPER_ATTACK);
removeGameTimer(DIVINE_SUPER_STRENGTH);
removeGameTimer(DIVINE_SUPER_DEFENCE);
removeGameTimer(DIVINE_SUPER_COMBAT);
removeGameTimer(DIVINE_RANGING);
removeGameTimer(DIVINE_MAGIC);
}
if (!this.showCannon)
{
removeGameTimer(CANNON);
@@ -421,7 +435,11 @@ public class TimersPlugin extends Plugin
if (this.showStamina
&& event.getOption().contains("Drink")
&& (event.getIdentifier() == ItemID.STAMINA_MIX1
|| event.getIdentifier() == ItemID.STAMINA_MIX2))
|| event.getIdentifier() == ItemID.STAMINA_MIX2
|| event.getIdentifier() == ItemID.EGNIOL_POTION_1
|| event.getIdentifier() == ItemID.EGNIOL_POTION_2
|| event.getIdentifier() == ItemID.EGNIOL_POTION_3
|| event.getIdentifier() == ItemID.EGNIOL_POTION_4))
{
// Needs menu option hook because mixes use a common drink message, distinct from their standard potion messages
createGameTimer(STAMINA);
@@ -582,6 +600,10 @@ public class TimersPlugin extends Plugin
{
createGameTimer(DMM_HALFTB);
}
else if (event.getMessage().startsWith(KILLED_TELEBLOCK_OPPONENT_TEXT))
{
removeTbTimers();
}
}
if (this.showAntiFire && event.getMessage().contains(SUPER_ANTIFIRE_DRINK_MESSAGE))
@@ -635,6 +657,40 @@ public class TimersPlugin extends Plugin
freezeTimer = createGameTimer(ICEBARRAGE);
freezeTime = client.getTickCount();
}
if (config.showDivine())
{
Matcher mDivine = DIVINE_POTION_PATTERN.matcher(event.getMessage());
if (mDivine.find())
{
switch (mDivine.group(1))
{
case "super attack":
createGameTimer(DIVINE_SUPER_ATTACK);
break;
case "super strength":
createGameTimer(DIVINE_SUPER_STRENGTH);
break;
case "super defence":
createGameTimer(DIVINE_SUPER_DEFENCE);
break;
case "combat":
createGameTimer(DIVINE_SUPER_COMBAT);
break;
case "ranging":
createGameTimer(DIVINE_RANGING);
break;
case "magic":
createGameTimer(DIVINE_MAGIC);
break;
}
}
}
}
private void onGameTick(GameTick event)
@@ -1020,5 +1076,6 @@ public class TimersPlugin extends Plugin
this.showSkull = config.showSkull();
this.showStaffOfTheDead = config.showStaffOfTheDead();
this.showAbyssalSireStun = config.showAbyssalSireStun();
this.showDivine = config.showDivine();
}
}

View File

@@ -38,11 +38,11 @@ import net.runelite.client.config.ConfigManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.eq;
import org.mockito.Mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ChatCommandsPluginTest
@@ -142,6 +142,28 @@ public class ChatCommandsPluginTest
verify(configManager).setConfiguration("killcount.adam", "herbiboar", 4091);
}
@Test
public void testGauntlet()
{
when(client.getUsername()).thenReturn("Adam");
ChatMessage gauntletMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Gauntlet completion count is: <col=ff0000>123</col>.", null, 0);
chatCommandsPlugin.onChatMessage(gauntletMessage);
verify(configManager).setConfiguration("killcount.adam", "gauntlet", 123);
}
@Test
public void testCorruptedGauntlet()
{
when(client.getUsername()).thenReturn("Adam");
ChatMessage corruptedGauntletMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Corrupted Gauntlet completion count is: <col=ff0000>4729</col>.", null, 0);
chatCommandsPlugin.onChatMessage(corruptedGauntletMessage);
verify(configManager).setConfiguration("killcount.adam", "corrupted gauntlet", 4729);
}
@Test
public void testPersonalBest()
{
@@ -244,4 +266,4 @@ public class ChatCommandsPluginTest
verify(configManager).setConfiguration(eq("personalbest.adam"), eq("prifddinas agility course"), eq(61));
verify(configManager).setConfiguration(eq("killcount.adam"), eq("prifddinas agility course"), eq(2));
}
}
}

View File

@@ -64,9 +64,14 @@ public abstract class EntityHiderBridgeMixin implements RSClient
@Inject
public static boolean hideProjectiles;
@Inject
public static boolean hideDeadNPCs;
@Inject
public static String hideNPCsNames;
@Inject
public static String hideNPCsOnDeath;
@Inject
@Override
@@ -138,6 +143,13 @@ public abstract class EntityHiderBridgeMixin implements RSClient
hideNPCsNames = NPCs;
}
@Inject
@Override
public void setNPCsHiddenOnDeath(String NPCs)
{
hideNPCsOnDeath = NPCs;
}
@Inject
@Override
public void setAttackersHidden(boolean state)
@@ -151,4 +163,11 @@ public abstract class EntityHiderBridgeMixin implements RSClient
{
hideProjectiles = state;
}
@Inject
@Override
public void setDeadNPCsHidden(boolean state)
{
hideDeadNPCs = state;
}
}

View File

@@ -68,7 +68,10 @@ public abstract class EntityHiderMixin implements RSScene
private static boolean hideNPCs;
@Shadow("hideNPCsNames")
private static String hideNPCsNames;
private static String hideNPCsNames;
@Shadow("hideNPCsOnDeath")
private static String hideNPCsOnDeath;
@Shadow("hideNPCs2D")
private static boolean hideNPCs2D;
@@ -79,6 +82,9 @@ public abstract class EntityHiderMixin implements RSScene
@Shadow("hideProjectiles")
private static boolean hideProjectiles;
@Shadow("hideDeadNPCs")
private static boolean hideDeadNPCs;
@Copy("newGameObject")
abstract boolean addEntityMarker(int var1, int var2, int var3, int var4, int var5, int x, int y, int var8, RSEntity renderable, int var10, boolean var11, long var12, int var13);
@@ -155,6 +161,7 @@ public abstract class EntityHiderMixin implements RSScene
{
RSNPC npc = (RSNPC) renderable;
String[] names = hideNPCsNames.split(",");
String[] removeOnDeath = hideNPCsOnDeath.split(",");
if (!hideAttackers)
{
@@ -164,16 +171,29 @@ public abstract class EntityHiderMixin implements RSScene
}
}
if (hideDeadNPCs && npc.getHealthRatio() == 0)
{
return false;
}
for (String name : names)
{
if (name != null && !name.equals(""))
{
if (npc.getName() != null)
if (npc.getName() != null && npc.getName().startsWith(name))
{
if (npc.getName().startsWith(name))
{
return false;
}
return false;
}
}
}
for (String name : removeOnDeath)
{
if (name != null && !name.equals(""))
{
if (npc.getName() != null && npc.getName().startsWith(name) && npc.getHealthRatio() == 0)
{
return false;
}
}
}