upstream
This commit is contained in:
@@ -57,7 +57,8 @@ public class InvokeInterface extends Instruction implements InvokeInstruction
|
|||||||
super(instructions, type);
|
super(instructions, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InvokeInterface(Instructions instructions, Method method) {
|
public InvokeInterface(Instructions instructions, Method method)
|
||||||
|
{
|
||||||
super(instructions, InstructionType.INVOKEINTERFACE);
|
super(instructions, InstructionType.INVOKEINTERFACE);
|
||||||
this.method = method;
|
this.method = method;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ dependencies {
|
|||||||
implementation("com.google.guava:guava:29.0-jre")
|
implementation("com.google.guava:guava:29.0-jre")
|
||||||
implementation(project(":deobfuscator"))
|
implementation(project(":deobfuscator"))
|
||||||
|
|
||||||
testCompileOnly("com.openosrs:injection-annotations:1.0")
|
testCompileOnly(project(":injection-annotations"))
|
||||||
testImplementation("junit:junit:4.13")
|
testImplementation("junit:junit:4.13")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ public interface InjectUtil
|
|||||||
* @param name The name of the method you want to find
|
* @param name The name of the method you want to find
|
||||||
* @param classHint The name of the class you expect the method to be in, or null
|
* @param classHint The name of the class you expect the method to be in, or null
|
||||||
* @param sig The signature the method has in deob, or null
|
* @param sig The signature the method has in deob, or null
|
||||||
*
|
|
||||||
* @return The obfuscated version of the found method
|
* @return The obfuscated version of the found method
|
||||||
*/
|
*/
|
||||||
static Method findMethod(
|
static Method findMethod(
|
||||||
@@ -104,7 +103,6 @@ public interface InjectUtil
|
|||||||
* @param sig The deobfuscated methods' signature, or null, if you're unsure
|
* @param sig The deobfuscated methods' signature, or null, if you're unsure
|
||||||
* @param notStatic If this is true, only check non-static methods. If classHint isn't null, check only subclasses
|
* @param notStatic If this is true, only check non-static methods. If classHint isn't null, check only subclasses
|
||||||
* @param returnDeob If this is true, this method will return the deobfuscated method, instead of turning it into vanilla first
|
* @param returnDeob If this is true, this method will return the deobfuscated method, instead of turning it into vanilla first
|
||||||
*
|
|
||||||
* @throws InjectException If the hint class couldn't be found, or no method matching the settings was found
|
* @throws InjectException If the hint class couldn't be found, or no method matching the settings was found
|
||||||
*/
|
*/
|
||||||
static Method findMethod(
|
static Method findMethod(
|
||||||
@@ -125,23 +123,41 @@ public interface InjectUtil
|
|||||||
if (notStatic)
|
if (notStatic)
|
||||||
{
|
{
|
||||||
if (sig == null)
|
if (sig == null)
|
||||||
|
{
|
||||||
m = InjectUtil.findMethodDeep(cf, name, s -> true);
|
m = InjectUtil.findMethodDeep(cf, name, s -> true);
|
||||||
else
|
|
||||||
m = InjectUtil.findMethodDeep(cf, name, sig);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
m = InjectUtil.findMethodDeep(cf, name, sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m = cf.findMethod(name);
|
m = cf.findMethod(name);
|
||||||
|
}
|
||||||
|
|
||||||
if (m != null)
|
if (m != null)
|
||||||
|
{
|
||||||
return returnDeob ? m : data.toVanilla(m);
|
return returnDeob ? m : data.toVanilla(m);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (ClassFile cf : deob)
|
for (ClassFile cf : deob)
|
||||||
|
{
|
||||||
for (Method m : cf.getMethods())
|
for (Method m : cf.getMethods())
|
||||||
|
{
|
||||||
if (m.getName().equals(name))
|
if (m.getName().equals(name))
|
||||||
|
{
|
||||||
if (!notStatic || !m.isStatic())
|
if (!notStatic || !m.isStatic())
|
||||||
|
{
|
||||||
if (sig == null || sig.test(m.getDescriptor()))
|
if (sig == null || sig.test(m.getDescriptor()))
|
||||||
|
{
|
||||||
return returnDeob ? m : data.toVanilla(m);
|
return returnDeob ? m : data.toVanilla(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new InjectException(String.format("Couldn't find %s", name));
|
throw new InjectException(String.format("Couldn't find %s", name));
|
||||||
}
|
}
|
||||||
@@ -150,7 +166,9 @@ public interface InjectUtil
|
|||||||
{
|
{
|
||||||
ClassFile clazz = group.findClass(name);
|
ClassFile clazz = group.findClass(name);
|
||||||
if (clazz == null)
|
if (clazz == null)
|
||||||
|
{
|
||||||
throw new InjectException("Hint class " + name + " doesn't exist");
|
throw new InjectException("Hint class " + name + " doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
return clazz;
|
return clazz;
|
||||||
}
|
}
|
||||||
@@ -161,10 +179,18 @@ public interface InjectUtil
|
|||||||
static Method findMethodDeep(ClassFile clazz, String name, Predicate<Signature> type)
|
static Method findMethodDeep(ClassFile clazz, String name, Predicate<Signature> type)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
|
{
|
||||||
for (Method method : clazz.getMethods())
|
for (Method method : clazz.getMethods())
|
||||||
|
{
|
||||||
if (method.getName().equals(name))
|
if (method.getName().equals(name))
|
||||||
|
{
|
||||||
if (type.test(method.getDescriptor()))
|
if (type.test(method.getDescriptor()))
|
||||||
|
{
|
||||||
return method;
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
while ((clazz = clazz.getParent()) != null);
|
while ((clazz = clazz.getParent()) != null);
|
||||||
|
|
||||||
throw new InjectException(String.format("Method %s couldn't be found", name + type.toString()));
|
throw new InjectException(String.format("Method %s couldn't be found", name + type.toString()));
|
||||||
@@ -172,7 +198,7 @@ public interface InjectUtil
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fail-fast implementation of ClassGroup.findStaticField
|
* Fail-fast implementation of ClassGroup.findStaticField
|
||||||
*
|
* <p>
|
||||||
* well...
|
* well...
|
||||||
*/
|
*/
|
||||||
static Field findStaticField(ClassGroup group, String name)
|
static Field findStaticField(ClassGroup group, String name)
|
||||||
@@ -181,8 +207,10 @@ public interface InjectUtil
|
|||||||
{
|
{
|
||||||
Field f = clazz.findField(name);
|
Field f = clazz.findField(name);
|
||||||
if (f != null && f.isStatic())
|
if (f != null && f.isStatic())
|
||||||
|
{
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new InjectException("Couldn't find static field " + name);
|
throw new InjectException("Couldn't find static field " + name);
|
||||||
}
|
}
|
||||||
@@ -194,7 +222,6 @@ public interface InjectUtil
|
|||||||
* @param name The name of the field you want to find
|
* @param name The name of the field you want to find
|
||||||
* @param classHint The name of the class you expect the field to be in, or null
|
* @param classHint The name of the class you expect the field to be in, or null
|
||||||
* @param type The type the method has in deob, or null
|
* @param type The type the method has in deob, or null
|
||||||
*
|
|
||||||
* @return The obfuscated version of the found field
|
* @return The obfuscated version of the found field
|
||||||
*/
|
*/
|
||||||
static Field findStaticField(InjectData data, String name, String classHint, Type type)
|
static Field findStaticField(InjectData data, String name, String classHint, Type type)
|
||||||
@@ -207,24 +234,36 @@ public interface InjectUtil
|
|||||||
ClassFile clazz = findClassOrThrow(deob, classHint);
|
ClassFile clazz = findClassOrThrow(deob, classHint);
|
||||||
|
|
||||||
if (type == null)
|
if (type == null)
|
||||||
|
{
|
||||||
field = clazz.findField(name);
|
field = clazz.findField(name);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
field = clazz.findField(name, type);
|
field = clazz.findField(name, type);
|
||||||
|
}
|
||||||
|
|
||||||
if (field != null)
|
if (field != null)
|
||||||
|
{
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (ClassFile clazz : deob)
|
for (ClassFile clazz : deob)
|
||||||
{
|
{
|
||||||
if (type == null)
|
if (type == null)
|
||||||
|
{
|
||||||
field = clazz.findField(name);
|
field = clazz.findField(name);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
field = clazz.findField(name, type);
|
field = clazz.findField(name, type);
|
||||||
|
}
|
||||||
|
|
||||||
if (field != null)
|
if (field != null)
|
||||||
|
{
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new InjectException(String.format("Static field %s doesn't exist", (type != null ? type + " " : "") + name));
|
throw new InjectException(String.format("Static field %s doesn't exist", (type != null ? type + " " : "") + name));
|
||||||
}
|
}
|
||||||
@@ -237,8 +276,12 @@ public interface InjectUtil
|
|||||||
Field f;
|
Field f;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
{
|
||||||
if ((f = clazz.findField(name)) != null)
|
if ((f = clazz.findField(name)) != null)
|
||||||
|
{
|
||||||
return f;
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
while ((clazz = clazz.getParent()) != null);
|
while ((clazz = clazz.getParent()) != null);
|
||||||
|
|
||||||
throw new InjectException("Couldn't find field " + name);
|
throw new InjectException("Couldn't find field " + name);
|
||||||
@@ -259,12 +302,18 @@ public interface InjectUtil
|
|||||||
|
|
||||||
field = clazz.findField(name);
|
field = clazz.findField(name);
|
||||||
if (field != null)
|
if (field != null)
|
||||||
|
{
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (ClassFile clazz : group)
|
for (ClassFile clazz : group)
|
||||||
|
{
|
||||||
if ((field = clazz.findField(name)) != null)
|
if ((field = clazz.findField(name)) != null)
|
||||||
|
{
|
||||||
return field;
|
return field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new InjectException("Field " + name + " doesn't exist");
|
throw new InjectException("Field " + name + " doesn't exist");
|
||||||
}
|
}
|
||||||
@@ -293,11 +342,15 @@ public interface InjectUtil
|
|||||||
static Type apiToDeob(InjectData data, Type api)
|
static Type apiToDeob(InjectData data, Type api)
|
||||||
{
|
{
|
||||||
if (api.isPrimitive())
|
if (api.isPrimitive())
|
||||||
|
{
|
||||||
return api;
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
final String internalName = api.getInternalName();
|
final String internalName = api.getInternalName();
|
||||||
if (internalName.startsWith(API_BASE))
|
if (internalName.startsWith(API_BASE))
|
||||||
|
{
|
||||||
return Type.getType("L" + api.getInternalName().substring(API_BASE.length()) + ";", api.getDimensions());
|
return Type.getType("L" + api.getInternalName().substring(API_BASE.length()) + ";", api.getDimensions());
|
||||||
|
}
|
||||||
else if (internalName.startsWith(RL_API_BASE))
|
else if (internalName.startsWith(RL_API_BASE))
|
||||||
{
|
{
|
||||||
Class rlApiC = new Class(internalName);
|
Class rlApiC = new Class(internalName);
|
||||||
@@ -332,11 +385,15 @@ public interface InjectUtil
|
|||||||
static Type deobToVanilla(InjectData data, Type deobT)
|
static Type deobToVanilla(InjectData data, Type deobT)
|
||||||
{
|
{
|
||||||
if (deobT.isPrimitive())
|
if (deobT.isPrimitive())
|
||||||
|
{
|
||||||
return deobT;
|
return deobT;
|
||||||
|
}
|
||||||
|
|
||||||
final ClassFile deobClass = data.getDeobfuscated().findClass(deobT.getInternalName());
|
final ClassFile deobClass = data.getDeobfuscated().findClass(deobT.getInternalName());
|
||||||
if (deobClass == null)
|
if (deobClass == null)
|
||||||
|
{
|
||||||
return deobT;
|
return deobT;
|
||||||
|
}
|
||||||
|
|
||||||
return Type.getType("L" + data.toVanilla(deobClass).getName() + ";", deobT.getDimensions());
|
return Type.getType("L" + data.toVanilla(deobClass).getName() + ";", deobT.getDimensions());
|
||||||
}
|
}
|
||||||
@@ -352,18 +409,24 @@ public interface InjectUtil
|
|||||||
List<Type> bb = b.getArguments();
|
List<Type> bb = b.getArguments();
|
||||||
|
|
||||||
if (aa.size() != bb.size())
|
if (aa.size() != bb.size())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < aa.size(); i++)
|
for (int i = 0; i < aa.size(); i++)
|
||||||
|
{
|
||||||
if (!aa.get(i).equals(bb.get(i)))
|
if (!aa.get(i).equals(bb.get(i)))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the obfuscated name from something's annotations.
|
* Gets the obfuscated name from something's annotations.
|
||||||
*
|
* <p>
|
||||||
* If the annotation doesn't exist return the current name instead.
|
* If the annotation doesn't exist return the current name instead.
|
||||||
*/
|
*/
|
||||||
static <T extends Annotated & Named> String getObfuscatedName(T from)
|
static <T extends Annotated & Named> String getObfuscatedName(T from)
|
||||||
@@ -387,7 +450,9 @@ public interface InjectUtil
|
|||||||
static Instruction createLoadForTypeIndex(Instructions instructions, Type type, int index)
|
static Instruction createLoadForTypeIndex(Instructions instructions, Type type, int index)
|
||||||
{
|
{
|
||||||
if (type.getDimensions() > 0 || !type.isPrimitive())
|
if (type.getDimensions() > 0 || !type.isPrimitive())
|
||||||
|
{
|
||||||
return new ALoad(instructions, index);
|
return new ALoad(instructions, index);
|
||||||
|
}
|
||||||
|
|
||||||
switch (type.toString())
|
switch (type.toString())
|
||||||
{
|
{
|
||||||
@@ -414,7 +479,9 @@ public interface InjectUtil
|
|||||||
static Instruction createReturnForType(Instructions instructions, Type type)
|
static Instruction createReturnForType(Instructions instructions, Type type)
|
||||||
{
|
{
|
||||||
if (!type.isPrimitive())
|
if (!type.isPrimitive())
|
||||||
|
{
|
||||||
return new Return(instructions, InstructionType.ARETURN);
|
return new Return(instructions, InstructionType.ARETURN);
|
||||||
|
}
|
||||||
|
|
||||||
switch (type.toString())
|
switch (type.toString())
|
||||||
{
|
{
|
||||||
@@ -440,10 +507,14 @@ public interface InjectUtil
|
|||||||
static Instruction createInvokeFor(Instructions instructions, net.runelite.asm.pool.Method method, boolean isStatic)
|
static Instruction createInvokeFor(Instructions instructions, net.runelite.asm.pool.Method method, boolean isStatic)
|
||||||
{
|
{
|
||||||
if (isStatic)
|
if (isStatic)
|
||||||
|
{
|
||||||
return new InvokeStatic(instructions, method);
|
return new InvokeStatic(instructions, method);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return new InvokeVirtual(instructions, method);
|
return new InvokeVirtual(instructions, method);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legit fuck annotations
|
* Legit fuck annotations
|
||||||
@@ -463,10 +534,14 @@ public interface InjectUtil
|
|||||||
into.accept(new LDC(instrs, getter));
|
into.accept(new LDC(instrs, getter));
|
||||||
|
|
||||||
if (getter instanceof Integer)
|
if (getter instanceof Integer)
|
||||||
|
{
|
||||||
into.accept(new IMul(instrs));
|
into.accept(new IMul(instrs));
|
||||||
|
}
|
||||||
else if (getter instanceof Long)
|
else if (getter instanceof Long)
|
||||||
|
{
|
||||||
into.accept(new LMul(instrs));
|
into.accept(new LMul(instrs));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add IN FRONT of the put
|
* Add IN FRONT of the put
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public class Injection extends InjectData implements InjectTaskHandler
|
|||||||
|
|
||||||
inject(new RSApiInjector(this));
|
inject(new RSApiInjector(this));
|
||||||
|
|
||||||
inject(new DrawAfterWidgets(this));
|
//inject(new DrawAfterWidgets(this));
|
||||||
|
|
||||||
inject(new ScriptVM(this));
|
inject(new ScriptVM(this));
|
||||||
|
|
||||||
@@ -107,8 +107,10 @@ public class Injection extends InjectData implements InjectTaskHandler
|
|||||||
log.lifecycle("{} {}", name, injector.getCompletionMsg());
|
log.lifecycle("{} {}", name, injector.getCompletionMsg());
|
||||||
|
|
||||||
if (injector instanceof Validator)
|
if (injector instanceof Validator)
|
||||||
|
{
|
||||||
validate((Validator) injector);
|
validate((Validator) injector);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validate(Validator validator)
|
private void validate(Validator validator)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ public class InjectorValidator implements Validator
|
|||||||
for (Class intf : cf.getInterfaces())
|
for (Class intf : cf.getInterfaces())
|
||||||
{
|
{
|
||||||
if (!intf.getName().startsWith(API_BASE))
|
if (!intf.getName().startsWith(API_BASE))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
RSApiClass apiC = rsApi.findClass(intf.getName());
|
RSApiClass apiC = rsApi.findClass(intf.getName());
|
||||||
if (apiC == null)
|
if (apiC == null)
|
||||||
@@ -61,7 +63,9 @@ public class InjectorValidator implements Validator
|
|||||||
for (RSApiMethod apiMethod : apiClass)
|
for (RSApiMethod apiMethod : apiClass)
|
||||||
{
|
{
|
||||||
if (apiMethod.isSynthetic() || apiMethod.isDefault())
|
if (apiMethod.isSynthetic() || apiMethod.isDefault())
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (clazz.findMethodDeep(apiMethod.getName(), apiMethod.getSignature()) == null)
|
if (clazz.findMethodDeep(apiMethod.getName(), apiMethod.getSignature()) == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ public abstract class InjectData
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Do something with all paired classes.
|
* Do something with all paired classes.
|
||||||
*
|
* <p>
|
||||||
* Key = deobfuscated, Value = vanilla
|
* Key = deobfuscated, Value = vanilla
|
||||||
*/
|
*/
|
||||||
public void forEachPair(BiConsumer<ClassFile, ClassFile> action)
|
public void forEachPair(BiConsumer<ClassFile, ClassFile> action)
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ public class CreateAnnotations extends AbstractInjector
|
|||||||
injectMethods(deobClass);
|
injectMethods(deobClass);
|
||||||
|
|
||||||
if (deobClass.getName().startsWith("class"))
|
if (deobClass.getName().startsWith("class"))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
deobClass.addAnnotation(DeobAnnotations.IMPLEMENTS, deobClass.getName());
|
deobClass.addAnnotation(DeobAnnotations.IMPLEMENTS, deobClass.getName());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ public class InjectConstruct extends AbstractInjector
|
|||||||
{
|
{
|
||||||
Annotation construct = apiMethod.findAnnotation(CONSTRUCT);
|
Annotation construct = apiMethod.findAnnotation(CONSTRUCT);
|
||||||
if (construct == null)
|
if (construct == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final Method method = apiMethod.getMethod();
|
final Method method = apiMethod.getMethod();
|
||||||
final Class clazz = method.getClazz();
|
final Class clazz = method.getClazz();
|
||||||
@@ -103,7 +105,9 @@ public class InjectConstruct extends AbstractInjector
|
|||||||
|
|
||||||
final net.runelite.asm.Method constructor = classToConstruct.findMethod("<init>", constr);
|
final net.runelite.asm.Method constructor = classToConstruct.findMethod("<init>", constr);
|
||||||
if (constructor == null)
|
if (constructor == null)
|
||||||
|
{
|
||||||
throw new InjectException("Unable to find constructor for " + classToConstruct.getName() + ".<init>" + constr);
|
throw new InjectException("Unable to find constructor for " + classToConstruct.getName() + ".<init>" + constr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
net.runelite.asm.Method setterMethod = new net.runelite.asm.Method(targetClass, apiMethod.getName(), apiMethod.getType());
|
net.runelite.asm.Method setterMethod = new net.runelite.asm.Method(targetClass, apiMethod.getName(), apiMethod.getType());
|
||||||
|
|||||||
@@ -86,7 +86,9 @@ public class InjectHook extends AbstractInjector
|
|||||||
public void inject()
|
public void inject()
|
||||||
{
|
{
|
||||||
for (Map.Entry<Provider<ClassFile>, List<ClassFile>> entry : mixinTargets.entrySet())
|
for (Map.Entry<Provider<ClassFile>, List<ClassFile>> entry : mixinTargets.entrySet())
|
||||||
|
{
|
||||||
injectMethods(entry.getKey(), entry.getValue());
|
injectMethods(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
injectHooks();
|
injectHooks();
|
||||||
|
|
||||||
@@ -103,7 +105,9 @@ public class InjectHook extends AbstractInjector
|
|||||||
{
|
{
|
||||||
final Annotation fieldHook = mixinMethod.findAnnotation(FIELDHOOK);
|
final Annotation fieldHook = mixinMethod.findAnnotation(FIELDHOOK);
|
||||||
if (fieldHook == null)
|
if (fieldHook == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final String hookName = fieldHook.getValueString();
|
final String hookName = fieldHook.getValueString();
|
||||||
final boolean before = isBefore(fieldHook);
|
final boolean before = isBefore(fieldHook);
|
||||||
@@ -149,23 +153,33 @@ public class InjectHook extends AbstractInjector
|
|||||||
Method method = code.getMethod();
|
Method method = code.getMethod();
|
||||||
|
|
||||||
if (method.getName().equals(CLINIT))
|
if (method.getName().equals(CLINIT))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(i instanceof SetFieldInstruction))
|
if (!(i instanceof SetFieldInstruction))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!done.add(i))
|
if (!done.add(i))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SetFieldInstruction sfi = (SetFieldInstruction) i;
|
SetFieldInstruction sfi = (SetFieldInstruction) i;
|
||||||
Field fieldBeingSet = sfi.getMyField();
|
Field fieldBeingSet = sfi.getMyField();
|
||||||
|
|
||||||
if (fieldBeingSet == null)
|
if (fieldBeingSet == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
HookInfo hookInfo = hooked.get(fieldBeingSet);
|
HookInfo hookInfo = hooked.get(fieldBeingSet);
|
||||||
if (hookInfo == null)
|
if (hookInfo == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.trace("Found injection location for hook {} at instruction {}", hookInfo.method.getName(), sfi);
|
log.trace("Found injection location for hook {} at instruction {}", hookInfo.method.getName(), sfi);
|
||||||
++injectedHooks;
|
++injectedHooks;
|
||||||
@@ -174,7 +188,9 @@ public class InjectHook extends AbstractInjector
|
|||||||
|
|
||||||
StackContext objectStackContext = null;
|
StackContext objectStackContext = null;
|
||||||
if (sfi instanceof PutField)
|
if (sfi instanceof PutField)
|
||||||
|
{
|
||||||
objectStackContext = ic.getPops().get(1);
|
objectStackContext = ic.getPops().get(1);
|
||||||
|
}
|
||||||
|
|
||||||
int idx = ins.getInstructions().indexOf(sfi);
|
int idx = ins.getInstructions().indexOf(sfi);
|
||||||
assert idx != -1;
|
assert idx != -1;
|
||||||
@@ -182,11 +198,15 @@ public class InjectHook extends AbstractInjector
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (hookInfo.before)
|
if (hookInfo.before)
|
||||||
|
{
|
||||||
injectCallbackBefore(ins, idx, hookInfo, null, objectStackContext, value);
|
injectCallbackBefore(ins, idx, hookInfo, null, objectStackContext, value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
// idx + 1 to insert after the set
|
// idx + 1 to insert after the set
|
||||||
|
{
|
||||||
injectCallback(ins, idx + 1, hookInfo, null, objectStackContext);
|
injectCallback(ins, idx + 1, hookInfo, null, objectStackContext);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (InjectException ex)
|
catch (InjectException ex)
|
||||||
{
|
{
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
@@ -206,23 +226,33 @@ public class InjectHook extends AbstractInjector
|
|||||||
Method method = code.getMethod();
|
Method method = code.getMethod();
|
||||||
|
|
||||||
if (method.getName().equals(CLINIT))
|
if (method.getName().equals(CLINIT))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(i instanceof ArrayStore))
|
if (!(i instanceof ArrayStore))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!doneIh.add(i))
|
if (!doneIh.add(i))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ArrayStore as = (ArrayStore) i;
|
ArrayStore as = (ArrayStore) i;
|
||||||
|
|
||||||
Field fieldBeingSet = as.getMyField(ic);
|
Field fieldBeingSet = as.getMyField(ic);
|
||||||
if (fieldBeingSet == null)
|
if (fieldBeingSet == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
HookInfo hookInfo = hooked.get(fieldBeingSet);
|
HookInfo hookInfo = hooked.get(fieldBeingSet);
|
||||||
if (hookInfo == null)
|
if (hookInfo == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StackContext value = ic.getPops().get(0);
|
StackContext value = ic.getPops().get(0);
|
||||||
StackContext index = ic.getPops().get(1);
|
StackContext index = ic.getPops().get(1);
|
||||||
@@ -232,7 +262,9 @@ public class InjectHook extends AbstractInjector
|
|||||||
|
|
||||||
StackContext objectStackContext = null;
|
StackContext objectStackContext = null;
|
||||||
if (arrayReferencePushed.getInstruction().getType() == InstructionType.GETFIELD)
|
if (arrayReferencePushed.getInstruction().getType() == InstructionType.GETFIELD)
|
||||||
|
{
|
||||||
objectStackContext = arrayReferencePushed.getPops().get(0);
|
objectStackContext = arrayReferencePushed.getPops().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
// inject hook after 'i'
|
// inject hook after 'i'
|
||||||
log.debug("[DEBUG] Found array injection location for hook {} at instruction {}", hookInfo.method.getName(), i);
|
log.debug("[DEBUG] Found array injection location for hook {} at instruction {}", hookInfo.method.getName(), i);
|
||||||
@@ -244,10 +276,14 @@ public class InjectHook extends AbstractInjector
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (hookInfo.before)
|
if (hookInfo.before)
|
||||||
|
{
|
||||||
injectCallbackBefore(ins, idx, hookInfo, index, objectStackContext, value);
|
injectCallbackBefore(ins, idx, hookInfo, index, objectStackContext, value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
injectCallback(ins, idx + 1, hookInfo, index, objectStackContext);
|
injectCallback(ins, idx + 1, hookInfo, index, objectStackContext);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (InjectException ex)
|
catch (InjectException ex)
|
||||||
{
|
{
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
@@ -265,7 +301,9 @@ public class InjectHook extends AbstractInjector
|
|||||||
if (!hookInfo.method.isStatic())
|
if (!hookInfo.method.isStatic())
|
||||||
{
|
{
|
||||||
if (object == null)
|
if (object == null)
|
||||||
|
{
|
||||||
throw new InjectException("null object");
|
throw new InjectException("null object");
|
||||||
|
}
|
||||||
|
|
||||||
ins.getInstructions().add(idx++, new Dup(ins)); // dup value
|
ins.getInstructions().add(idx++, new Dup(ins)); // dup value
|
||||||
idx = recursivelyPush(ins, idx, object);
|
idx = recursivelyPush(ins, idx, object);
|
||||||
@@ -313,7 +351,9 @@ public class InjectHook extends AbstractInjector
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (StackContext s : Lists.reverse(ctx.getPops()))
|
for (StackContext s : Lists.reverse(ctx.getPops()))
|
||||||
|
{
|
||||||
idx = recursivelyPush(ins, idx, s);
|
idx = recursivelyPush(ins, idx, s);
|
||||||
|
}
|
||||||
|
|
||||||
ins.getInstructions().add(idx++, ctx.getInstruction().clone());
|
ins.getInstructions().add(idx++, ctx.getInstruction().clone());
|
||||||
return idx;
|
return idx;
|
||||||
@@ -324,15 +364,21 @@ public class InjectHook extends AbstractInjector
|
|||||||
if (!hookInfo.method.isStatic())
|
if (!hookInfo.method.isStatic())
|
||||||
{
|
{
|
||||||
if (objectPusher == null)
|
if (objectPusher == null)
|
||||||
|
{
|
||||||
throw new InjectException("Null object pusher");
|
throw new InjectException("Null object pusher");
|
||||||
|
}
|
||||||
|
|
||||||
idx = recursivelyPush(ins, idx, objectPusher);
|
idx = recursivelyPush(ins, idx, objectPusher);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index != null)
|
if (index != null)
|
||||||
|
{
|
||||||
idx = recursivelyPush(ins, idx, index);
|
idx = recursivelyPush(ins, idx, index);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ins.getInstructions().add(idx++, new LDC(ins, -1));
|
ins.getInstructions().add(idx++, new LDC(ins, -1));
|
||||||
|
}
|
||||||
|
|
||||||
Instruction invoke = hookInfo.getInvoke(ins);
|
Instruction invoke = hookInfo.getInvoke(ins);
|
||||||
ins.getInstructions().add(idx, invoke);
|
ins.getInstructions().add(idx, invoke);
|
||||||
|
|||||||
@@ -65,7 +65,9 @@ public class InjectHookMethod extends AbstractInjector
|
|||||||
public void inject()
|
public void inject()
|
||||||
{
|
{
|
||||||
for (Map.Entry<Provider<ClassFile>, List<ClassFile>> entry : mixinTargets.entrySet())
|
for (Map.Entry<Provider<ClassFile>, List<ClassFile>> entry : mixinTargets.entrySet())
|
||||||
|
{
|
||||||
injectMethods(entry.getKey(), entry.getValue());
|
injectMethods(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
log.info("[INFO] Injected {} method hooks", injected);
|
log.info("[INFO] Injected {} method hooks", injected);
|
||||||
}
|
}
|
||||||
@@ -80,10 +82,14 @@ public class InjectHookMethod extends AbstractInjector
|
|||||||
{
|
{
|
||||||
final Annotation methodHook = mixinMethod.findAnnotation(METHODHOOK);
|
final Annotation methodHook = mixinMethod.findAnnotation(METHODHOOK);
|
||||||
if (methodHook == null)
|
if (methodHook == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mixinMethod.getDescriptor().isVoid())
|
if (!mixinMethod.getDescriptor().isVoid())
|
||||||
|
{
|
||||||
throw new InjectException("Method hook " + mixinMethod.getPoolMethod() + " doesn't have void return type");
|
throw new InjectException("Method hook " + mixinMethod.getPoolMethod() + " doesn't have void return type");
|
||||||
|
}
|
||||||
|
|
||||||
final String hookName = methodHook.getValueString();
|
final String hookName = methodHook.getValueString();
|
||||||
final boolean end = isEnd(methodHook);
|
final boolean end = isEnd(methodHook);
|
||||||
@@ -116,8 +122,12 @@ public class InjectHookMethod extends AbstractInjector
|
|||||||
{
|
{
|
||||||
it = ins.listIterator(ins.size());
|
it = ins.listIterator(ins.size());
|
||||||
while (it.hasPrevious())
|
while (it.hasPrevious())
|
||||||
|
{
|
||||||
if (it.previous() instanceof ReturnInstruction)
|
if (it.previous() instanceof ReturnInstruction)
|
||||||
|
{
|
||||||
insertVoke(method, hookMethod, it);
|
insertVoke(method, hookMethod, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -126,8 +136,12 @@ public class InjectHookMethod extends AbstractInjector
|
|||||||
if (method.getName().equals("<init>"))
|
if (method.getName().equals("<init>"))
|
||||||
{
|
{
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
|
{
|
||||||
if (it.next() instanceof InvokeSpecial)
|
if (it.next() instanceof InvokeSpecial)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert it.hasNext() : "Constructor without invokespecial";
|
assert it.hasNext() : "Constructor without invokespecial";
|
||||||
}
|
}
|
||||||
@@ -141,7 +155,9 @@ public class InjectHookMethod extends AbstractInjector
|
|||||||
int varIdx = 0;
|
int varIdx = 0;
|
||||||
|
|
||||||
if (!method.isStatic())
|
if (!method.isStatic())
|
||||||
|
{
|
||||||
iterator.add(new ALoad(instructions, varIdx++));
|
iterator.add(new ALoad(instructions, varIdx++));
|
||||||
|
}
|
||||||
|
|
||||||
for (Type type : hookMethod.getType().getArguments())
|
for (Type type : hookMethod.getType().getArguments())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ public class InterfaceInjector extends AbstractInjector
|
|||||||
final String impls = DeobAnnotations.getImplements(deobCf);
|
final String impls = DeobAnnotations.getImplements(deobCf);
|
||||||
|
|
||||||
if (impls == null)
|
if (impls == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final String fullName = API_BASE + impls;
|
final String fullName = API_BASE + impls;
|
||||||
if (!inject.getRsApi().hasClass(fullName))
|
if (!inject.getRsApi().hasClass(fullName))
|
||||||
|
|||||||
@@ -179,13 +179,19 @@ public class MixinInjector extends AbstractInjector
|
|||||||
copy.setValue(field.getValue());
|
copy.setValue(field.getValue());
|
||||||
|
|
||||||
for (Map.Entry<Type, Annotation> e : field.getAnnotations().entrySet())
|
for (Map.Entry<Type, Annotation> e : field.getAnnotations().entrySet())
|
||||||
|
{
|
||||||
if (!e.getKey().toString().startsWith("Lnet/runelite/api/mixins"))
|
if (!e.getKey().toString().startsWith("Lnet/runelite/api/mixins"))
|
||||||
|
{
|
||||||
copy.addAnnotation(e.getValue());
|
copy.addAnnotation(e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
targetClass.addField(copy);
|
targetClass.addField(copy);
|
||||||
|
|
||||||
if (injectedFields.containsKey(field.getName()) && !ASSERTION_FIELD.equals(field.getName()))
|
if (injectedFields.containsKey(field.getName()) && !ASSERTION_FIELD.equals(field.getName()))
|
||||||
|
{
|
||||||
throw new InjectException("Duplicate field: " + field.getName());
|
throw new InjectException("Duplicate field: " + field.getName());
|
||||||
|
}
|
||||||
|
|
||||||
injectedFields.put(field.getName(), copy);
|
injectedFields.put(field.getName(), copy);
|
||||||
}
|
}
|
||||||
@@ -207,10 +213,14 @@ public class MixinInjector extends AbstractInjector
|
|||||||
Annotation shadow = field.findAnnotation(SHADOW);
|
Annotation shadow = field.findAnnotation(SHADOW);
|
||||||
|
|
||||||
if (shadow == null)
|
if (shadow == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!field.isStatic())
|
if (!field.isStatic())
|
||||||
|
{
|
||||||
throw new InjectException("Shadowed fields must be static");
|
throw new InjectException("Shadowed fields must be static");
|
||||||
|
}
|
||||||
|
|
||||||
String shadowed = shadow.getValueString();
|
String shadowed = shadow.getValueString();
|
||||||
|
|
||||||
@@ -226,7 +236,9 @@ public class MixinInjector extends AbstractInjector
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((targetField.getAccessFlags() & Opcodes.ACC_PRIVATE) != 0)
|
if ((targetField.getAccessFlags() & Opcodes.ACC_PRIVATE) != 0)
|
||||||
|
{
|
||||||
throw new InjectException("Shadowed fields can't be private");
|
throw new InjectException("Shadowed fields can't be private");
|
||||||
|
}
|
||||||
|
|
||||||
shadowFields.put(
|
shadowFields.put(
|
||||||
field.getPoolField(),
|
field.getPoolField(),
|
||||||
@@ -249,7 +261,9 @@ public class MixinInjector extends AbstractInjector
|
|||||||
{
|
{
|
||||||
Annotation copyA = mixinMethod.findAnnotation(COPY);
|
Annotation copyA = mixinMethod.findAnnotation(COPY);
|
||||||
if (copyA == null)
|
if (copyA == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
String copiedName = copyA.getValueString();
|
String copiedName = copyA.getValueString();
|
||||||
|
|
||||||
Signature deobSig = InjectUtil.apiToDeob(inject, mixinMethod.getDescriptor());
|
Signature deobSig = InjectUtil.apiToDeob(inject, mixinMethod.getDescriptor());
|
||||||
@@ -258,13 +272,17 @@ public class MixinInjector extends AbstractInjector
|
|||||||
Method deobSourceMethod = InjectUtil.findMethod(inject, copiedName, inject.toDeob(targetClass.getName()).getName(), deobSig::equals, notStat, true);
|
Method deobSourceMethod = InjectUtil.findMethod(inject, copiedName, inject.toDeob(targetClass.getName()).getName(), deobSig::equals, notStat, true);
|
||||||
|
|
||||||
if (mixinMethod.isStatic() != deobSourceMethod.isStatic())
|
if (mixinMethod.isStatic() != deobSourceMethod.isStatic())
|
||||||
|
{
|
||||||
throw new InjectException("Mixin method " + mixinMethod + " should be " + (deobSourceMethod.isStatic() ? "static" : "non-static"));
|
throw new InjectException("Mixin method " + mixinMethod + " should be " + (deobSourceMethod.isStatic() ? "static" : "non-static"));
|
||||||
|
}
|
||||||
|
|
||||||
// The actual method we're copying, including code etc
|
// The actual method we're copying, including code etc
|
||||||
Method sourceMethod = inject.toVanilla(deobSourceMethod);
|
Method sourceMethod = inject.toVanilla(deobSourceMethod);
|
||||||
|
|
||||||
if (mixinMethod.getDescriptor().size() > sourceMethod.getDescriptor().size())
|
if (mixinMethod.getDescriptor().size() > sourceMethod.getDescriptor().size())
|
||||||
|
{
|
||||||
throw new InjectException("Mixin methods cannot have more parameters than their corresponding ob method");
|
throw new InjectException("Mixin methods cannot have more parameters than their corresponding ob method");
|
||||||
|
}
|
||||||
|
|
||||||
Method copy = new Method(targetClass, "copy$" + copiedName, sourceMethod.getDescriptor());
|
Method copy = new Method(targetClass, "copy$" + copiedName, sourceMethod.getDescriptor());
|
||||||
moveCode(copy, sourceMethod.getCode());
|
moveCode(copy, sourceMethod.getCode());
|
||||||
@@ -272,7 +290,9 @@ public class MixinInjector extends AbstractInjector
|
|||||||
copy.setPublic();
|
copy.setPublic();
|
||||||
copy.getExceptions().getExceptions().addAll(sourceMethod.getExceptions().getExceptions());
|
copy.getExceptions().getExceptions().addAll(sourceMethod.getExceptions().getExceptions());
|
||||||
for (var a : sourceMethod.getAnnotations().values())
|
for (var a : sourceMethod.getAnnotations().values())
|
||||||
|
{
|
||||||
copy.addAnnotation(a);
|
copy.addAnnotation(a);
|
||||||
|
}
|
||||||
targetClass.addMethod(copy);
|
targetClass.addMethod(copy);
|
||||||
++copied;
|
++copied;
|
||||||
|
|
||||||
@@ -298,7 +318,9 @@ public class MixinInjector extends AbstractInjector
|
|||||||
if ((hasInject && isInit) || isClinit)
|
if ((hasInject && isInit) || isClinit)
|
||||||
{
|
{
|
||||||
if (!"()V".equals(mixinMethod.getDescriptor().toString()))
|
if (!"()V".equals(mixinMethod.getDescriptor().toString()))
|
||||||
|
{
|
||||||
throw new InjectException("Injected constructors cannot have arguments");
|
throw new InjectException("Injected constructors cannot have arguments");
|
||||||
|
}
|
||||||
|
|
||||||
Method[] originalMethods = targetClass.getMethods().stream()
|
Method[] originalMethods = targetClass.getMethods().stream()
|
||||||
.filter(m -> m.getName().equals(mixinMethod.getName()))
|
.filter(m -> m.getName().equals(mixinMethod.getName()))
|
||||||
@@ -309,11 +331,15 @@ public class MixinInjector extends AbstractInjector
|
|||||||
// If there isn't a <clinit> already just inject ours, otherwise rename it
|
// If there isn't a <clinit> already just inject ours, otherwise rename it
|
||||||
// This is always true for <init>
|
// This is always true for <init>
|
||||||
if (originalMethods.length > 0)
|
if (originalMethods.length > 0)
|
||||||
|
{
|
||||||
name = "rl$$" + (isInit ? "init" : "clinit");
|
name = "rl$$" + (isInit ? "init" : "clinit");
|
||||||
|
}
|
||||||
|
|
||||||
String numberlessName = name;
|
String numberlessName = name;
|
||||||
for (int i = 1; targetClass.findMethod(name, mixinMethod.getDescriptor()) != null; i++)
|
for (int i = 1; targetClass.findMethod(name, mixinMethod.getDescriptor()) != null; i++)
|
||||||
|
{
|
||||||
name = numberlessName + i;
|
name = numberlessName + i;
|
||||||
|
}
|
||||||
|
|
||||||
Method copy = new Method(targetClass, name, mixinMethod.getDescriptor());
|
Method copy = new Method(targetClass, name, mixinMethod.getDescriptor());
|
||||||
moveCode(copy, mixinMethod.getCode());
|
moveCode(copy, mixinMethod.getCode());
|
||||||
@@ -337,7 +363,9 @@ public class MixinInjector extends AbstractInjector
|
|||||||
int pops = invoke.getMethod().getType().getArguments().size() + 1;
|
int pops = invoke.getMethod().getType().getArguments().size() + 1;
|
||||||
|
|
||||||
for (int i = 0; i < pops; i++)
|
for (int i = 0; i < pops; i++)
|
||||||
|
{
|
||||||
listIter.add(new Pop(instructions));
|
listIter.add(new Pop(instructions));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -503,11 +531,15 @@ public class MixinInjector extends AbstractInjector
|
|||||||
|
|
||||||
// Update instructions for each instruction
|
// Update instructions for each instruction
|
||||||
for (Instruction i : newCode.getInstructions())
|
for (Instruction i : newCode.getInstructions())
|
||||||
|
{
|
||||||
i.setInstructions(newCode.getInstructions());
|
i.setInstructions(newCode.getInstructions());
|
||||||
|
}
|
||||||
|
|
||||||
newCode.getExceptions().getExceptions().addAll(sourceCode.getExceptions().getExceptions());
|
newCode.getExceptions().getExceptions().addAll(sourceCode.getExceptions().getExceptions());
|
||||||
for (net.runelite.asm.attributes.code.Exception e : newCode.getExceptions().getExceptions())
|
for (net.runelite.asm.attributes.code.Exception e : newCode.getExceptions().getExceptions())
|
||||||
|
{
|
||||||
e.setExceptions(newCode.getExceptions());
|
e.setExceptions(newCode.getExceptions());
|
||||||
|
}
|
||||||
|
|
||||||
targetMethod.setCode(newCode);
|
targetMethod.setCode(newCode);
|
||||||
}
|
}
|
||||||
@@ -598,8 +630,10 @@ public class MixinInjector extends AbstractInjector
|
|||||||
PushConstantInstruction pi = (PushConstantInstruction) i;
|
PushConstantInstruction pi = (PushConstantInstruction) i;
|
||||||
|
|
||||||
if (mixinCf.getPoolClass().equals(pi.getConstant()))
|
if (mixinCf.getPoolClass().equals(pi.getConstant()))
|
||||||
|
{
|
||||||
pi.setConstant(cf.getPoolClass());
|
pi.setConstant(cf.getPoolClass());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
verify(mixinCf, i);
|
verify(mixinCf, i);
|
||||||
}
|
}
|
||||||
@@ -614,26 +648,34 @@ public class MixinInjector extends AbstractInjector
|
|||||||
if (fi.getField().getClazz().getName().equals(mixinCf.getName()))
|
if (fi.getField().getClazz().getName().equals(mixinCf.getName()))
|
||||||
{
|
{
|
||||||
if (i instanceof PutField || i instanceof GetField)
|
if (i instanceof PutField || i instanceof GetField)
|
||||||
|
{
|
||||||
throw new InjectException("Access to non static member field of mixin");
|
throw new InjectException("Access to non static member field of mixin");
|
||||||
|
}
|
||||||
|
|
||||||
Field field = fi.getMyField();
|
Field field = fi.getMyField();
|
||||||
if (field != null && !field.isPublic())
|
if (field != null && !field.isPublic())
|
||||||
|
{
|
||||||
throw new InjectException("Static access to non public field " + field);
|
throw new InjectException("Static access to non public field " + field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (i instanceof InvokeStatic)
|
else if (i instanceof InvokeStatic)
|
||||||
{
|
{
|
||||||
InvokeStatic is = (InvokeStatic) i;
|
InvokeStatic is = (InvokeStatic) i;
|
||||||
|
|
||||||
if (is.getMethod().getClazz() != mixinCf.getPoolClass()
|
if (is.getMethod().getClazz() != mixinCf.getPoolClass()
|
||||||
&& is.getMethod().getClazz().getName().startsWith(MIXIN_BASE))
|
&& is.getMethod().getClazz().getName().startsWith(MIXIN_BASE))
|
||||||
|
{
|
||||||
throw new InjectException("Invoking static methods of other mixins is not supported");
|
throw new InjectException("Invoking static methods of other mixins is not supported");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (i instanceof InvokeDynamic)
|
else if (i instanceof InvokeDynamic)
|
||||||
// RS classes don't verify under java 7+ due to the
|
// RS classes don't verify under java 7+ due to the
|
||||||
// super() invokespecial being inside of a try{}
|
// super() invokespecial being inside of a try{}
|
||||||
|
{
|
||||||
throw new InjectException("Injected bytecode must be Java 6 compatible");
|
throw new InjectException("Injected bytecode must be Java 6 compatible");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Method findDeobMatching(ClassFile deobClass, Method mixinMethod, String deobName)
|
private Method findDeobMatching(ClassFile deobClass, Method mixinMethod, String deobName)
|
||||||
{
|
{
|
||||||
@@ -642,18 +684,26 @@ public class MixinInjector extends AbstractInjector
|
|||||||
for (Method method : deobClass.getMethods())
|
for (Method method : deobClass.getMethods())
|
||||||
{
|
{
|
||||||
if (!deobName.equals(method.getName()))
|
if (!deobName.equals(method.getName()))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (InjectUtil.apiToDeobSigEquals(inject, method.getDescriptor(), mixinMethod.getDescriptor()))
|
if (InjectUtil.apiToDeobSigEquals(inject, method.getDescriptor(), mixinMethod.getDescriptor()))
|
||||||
|
{
|
||||||
matching.add(method);
|
matching.add(method);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (matching.size() > 1)
|
if (matching.size() > 1)
|
||||||
// this happens when it has found several deob methods for some mixin method,
|
// this happens when it has found several deob methods for some mixin method,
|
||||||
// to get rid of the error, refine your search by making your mixin method have more parameters
|
// to get rid of the error, refine your search by making your mixin method have more parameters
|
||||||
|
{
|
||||||
throw new InjectException("There are several matching methods when there should only be one");
|
throw new InjectException("There are several matching methods when there should only be one");
|
||||||
|
}
|
||||||
else if (matching.size() == 1)
|
else if (matching.size() == 1)
|
||||||
|
{
|
||||||
return matching.get(0);
|
return matching.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
return inject.getDeobfuscated().findStaticMethod(deobName);
|
return inject.getDeobfuscated().findStaticMethod(deobName);
|
||||||
}
|
}
|
||||||
@@ -695,14 +745,16 @@ public class MixinInjector extends AbstractInjector
|
|||||||
@Value
|
@Value
|
||||||
private static class CopiedMethod
|
private static class CopiedMethod
|
||||||
{
|
{
|
||||||
@Nonnull Method copy;
|
@Nonnull
|
||||||
|
Method copy;
|
||||||
@Nullable Integer garbage;
|
@Nullable Integer garbage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
private static class ShadowField
|
private static class ShadowField
|
||||||
{
|
{
|
||||||
@Nonnull Field targetField;
|
@Nonnull
|
||||||
|
Field targetField;
|
||||||
@Nullable Number obfuscatedGetter;
|
@Nullable Number obfuscatedGetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,7 +768,9 @@ public class MixinInjector extends AbstractInjector
|
|||||||
public ClassFile get()
|
public ClassFile get()
|
||||||
{
|
{
|
||||||
if (bytes != null)
|
if (bytes != null)
|
||||||
|
{
|
||||||
return JarUtil.loadClass(bytes);
|
return JarUtil.loadClass(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
bytes = JarUtil.writeClass(mixin.getGroup(), mixin);
|
bytes = JarUtil.writeClass(mixin.getGroup(), mixin);
|
||||||
return mixin;
|
return mixin;
|
||||||
|
|||||||
@@ -84,7 +84,9 @@ public class RSApiInjector extends AbstractInjector
|
|||||||
final List<RSApiMethod> matching = findImportsFor(deobField, deobField.isStatic(), implementingClass);
|
final List<RSApiMethod> matching = findImportsFor(deobField, deobField.isStatic(), implementingClass);
|
||||||
|
|
||||||
if (matching == null)
|
if (matching == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final Type deobType = deobField.getType();
|
final Type deobType = deobField.getType();
|
||||||
|
|
||||||
@@ -153,7 +155,9 @@ public class RSApiInjector extends AbstractInjector
|
|||||||
final Number getter = DeobAnnotations.getObfuscatedGetter(deobField);
|
final Number getter = DeobAnnotations.getObfuscatedGetter(deobField);
|
||||||
|
|
||||||
if (deobField.isStatic() != vanillaField.isStatic()) // Can this even happen
|
if (deobField.isStatic() != vanillaField.isStatic()) // Can this even happen
|
||||||
|
{
|
||||||
throw new InjectException("Something went horribly wrong, and this should honestly never happen, but you never know. Btw it's the static-ness");
|
throw new InjectException("Something went horribly wrong, and this should honestly never happen, but you never know. Btw it's the static-ness");
|
||||||
|
}
|
||||||
|
|
||||||
inject(matching, deobField, vanillaField, getter);
|
inject(matching, deobField, vanillaField, getter);
|
||||||
}
|
}
|
||||||
@@ -166,7 +170,9 @@ public class RSApiInjector extends AbstractInjector
|
|||||||
final List<RSApiMethod> matching = findImportsFor(deobMethod, deobMethod.isStatic(), implementingClass);
|
final List<RSApiMethod> matching = findImportsFor(deobMethod, deobMethod.isStatic(), implementingClass);
|
||||||
|
|
||||||
if (matching == null)
|
if (matching == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final Signature deobSig = deobMethod.getDescriptor();
|
final Signature deobSig = deobMethod.getDescriptor();
|
||||||
|
|
||||||
@@ -211,9 +217,11 @@ public class RSApiInjector extends AbstractInjector
|
|||||||
apiMethod.setInjected(true);
|
apiMethod.setInjected(true);
|
||||||
}
|
}
|
||||||
else if (matching.size() != 0)
|
else if (matching.size() != 0)
|
||||||
|
{
|
||||||
throw new InjectException("Multiple api imports matching method " + deobMethod.getPoolMethod());
|
throw new InjectException("Multiple api imports matching method " + deobMethod.getPoolMethod());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void retryFailures()
|
private void retryFailures()
|
||||||
{
|
{
|
||||||
@@ -225,7 +233,9 @@ public class RSApiInjector extends AbstractInjector
|
|||||||
matched.removeIf(RSApiMethod::isInjected);
|
matched.removeIf(RSApiMethod::isInjected);
|
||||||
|
|
||||||
if (matched.size() > 2)
|
if (matched.size() > 2)
|
||||||
|
{
|
||||||
throw new InjectException("More than 2 imported api methods for field " + deobField.getPoolField());
|
throw new InjectException("More than 2 imported api methods for field " + deobField.getPoolField());
|
||||||
|
}
|
||||||
|
|
||||||
final Field vanillaField = inject.toVanilla(deobField);
|
final Field vanillaField = inject.toVanilla(deobField);
|
||||||
final Number getter = DeobAnnotations.getObfuscatedGetter(deobField);
|
final Number getter = DeobAnnotations.getObfuscatedGetter(deobField);
|
||||||
@@ -238,7 +248,9 @@ public class RSApiInjector extends AbstractInjector
|
|||||||
{
|
{
|
||||||
final String exportedName = InjectUtil.getExportedName(object);
|
final String exportedName = InjectUtil.getExportedName(object);
|
||||||
if (exportedName == null)
|
if (exportedName == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final List<RSApiMethod> matching = new ArrayList<>();
|
final List<RSApiMethod> matching = new ArrayList<>();
|
||||||
|
|
||||||
|
|||||||
@@ -271,12 +271,14 @@ public class DrawAfterWidgets extends AbstractInjector
|
|||||||
for (Field f : c.getFields())
|
for (Field f : c.getFields())
|
||||||
{
|
{
|
||||||
if (f.isStatic())
|
if (f.isStatic())
|
||||||
|
{
|
||||||
if (f.getName().equals(s))
|
if (f.getName().equals(s))
|
||||||
{
|
{
|
||||||
return inject.toVanilla(f);
|
return inject.toVanilla(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,12 +289,14 @@ public class DrawAfterWidgets extends AbstractInjector
|
|||||||
for (Field f : c.getFields())
|
for (Field f : c.getFields())
|
||||||
{
|
{
|
||||||
if (!f.isStatic())
|
if (!f.isStatic())
|
||||||
|
{
|
||||||
if (f.getName().equals(s))
|
if (f.getName().equals(s))
|
||||||
{
|
{
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ public class DrawMenu extends AbstractInjector
|
|||||||
{
|
{
|
||||||
Instruction instruction = ic.getInstruction();
|
Instruction instruction = ic.getInstruction();
|
||||||
if (!(instruction instanceof GetStatic))
|
if (!(instruction instanceof GetStatic))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (((GetStatic) instruction).getField().equals(isMenuOpen))
|
if (((GetStatic) instruction).getField().equals(isMenuOpen))
|
||||||
{
|
{
|
||||||
@@ -100,25 +102,35 @@ public class DrawMenu extends AbstractInjector
|
|||||||
// If the popper is a IfNe the label it's pointing to is the drawMenu one and topLeft is directly after it
|
// If the popper is a IfNe the label it's pointing to is the drawMenu one and topLeft is directly after it
|
||||||
// else it's the other way around, obviously
|
// else it's the other way around, obviously
|
||||||
if (isMenuOpenPopI instanceof IfNe)
|
if (isMenuOpenPopI instanceof IfNe)
|
||||||
|
{
|
||||||
injectInvokeAfter = ((IfNe) isMenuOpenPopI).getTo();
|
injectInvokeAfter = ((IfNe) isMenuOpenPopI).getTo();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
injectInvokeAfter = isMenuOpenPopI;
|
injectInvokeAfter = isMenuOpenPopI;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (((GetStatic) instruction).getField().equals(gameDrawMode))
|
else if (((GetStatic) instruction).getField().equals(gameDrawMode))
|
||||||
{
|
{
|
||||||
List<Instruction> instrL = instruction.getInstructions().getInstructions();
|
List<Instruction> instrL = instruction.getInstructions().getInstructions();
|
||||||
for (int i = instrL.indexOf(instruction); !(instruction instanceof Label); i--)
|
for (int i = instrL.indexOf(instruction); !(instruction instanceof Label); i--)
|
||||||
|
{
|
||||||
instruction = instrL.get(i);
|
instruction = instrL.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
labelToJumpTo = (Label) instruction;
|
labelToJumpTo = (Label) instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (injectInvokeAfter != null && labelToJumpTo != null)
|
if (injectInvokeAfter != null && labelToJumpTo != null)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (injectInvokeAfter == null || labelToJumpTo == null)
|
if (injectInvokeAfter == null || labelToJumpTo == null)
|
||||||
|
{
|
||||||
throw new InjectException("Couldn't find the right location for DrawMenu to inject");
|
throw new InjectException("Couldn't find the right location for DrawMenu to inject");
|
||||||
|
}
|
||||||
|
|
||||||
final Instructions instrs = mc.getMethod().getCode().getInstructions();
|
final Instructions instrs = mc.getMethod().getCode().getInstructions();
|
||||||
int idx = instrs.getInstructions().indexOf(injectInvokeAfter);
|
int idx = instrs.getInstructions().indexOf(injectInvokeAfter);
|
||||||
|
|||||||
@@ -49,12 +49,16 @@ public class Occluder extends AbstractInjector
|
|||||||
Instruction i = it.next();
|
Instruction i = it.next();
|
||||||
|
|
||||||
if (!(i instanceof BiPush))
|
if (!(i instanceof BiPush))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
boolean shouldChange = (byte) ((BiPush) i).getConstant() == OLDVALUE;
|
boolean shouldChange = (byte) ((BiPush) i).getConstant() == OLDVALUE;
|
||||||
|
|
||||||
if (!shouldChange)
|
if (!shouldChange)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
replaced++;
|
replaced++;
|
||||||
|
|
||||||
@@ -64,6 +68,8 @@ public class Occluder extends AbstractInjector
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (replaced != 10)
|
if (replaced != 10)
|
||||||
|
{
|
||||||
throw new InjectException("Only found " + replaced + " 25's to replace in occlude instead of expected 10");
|
throw new InjectException("Only found " + replaced + " 25's to replace in occlude instead of expected 10");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,7 +74,9 @@ public class RasterizerAlpha extends AbstractInjector
|
|||||||
{
|
{
|
||||||
Instructions instrs = getInstrs(mc);
|
Instructions instrs = getInstrs(mc);
|
||||||
if (instrs == null)
|
if (instrs == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int orCount = 0;
|
int orCount = 0;
|
||||||
@@ -84,14 +86,18 @@ public class RasterizerAlpha extends AbstractInjector
|
|||||||
{
|
{
|
||||||
Instruction instruction = ic.getInstruction();
|
Instruction instruction = ic.getInstruction();
|
||||||
if (!(instruction instanceof IAStore))
|
if (!(instruction instanceof IAStore))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Field field = astore.getMyField(ic);
|
// Field field = astore.getMyField(ic);
|
||||||
// doesn't track into methods so doing it here
|
// doesn't track into methods so doing it here
|
||||||
StackContext array = ic.getPops().get(2);
|
StackContext array = ic.getPops().get(2);
|
||||||
|
|
||||||
if (!isSameField(r2dPx, array))
|
if (!isSameField(r2dPx, array))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// This is the colour that's being set
|
// This is the colour that's being set
|
||||||
StackContext colour = ic.getPops().get(0);
|
StackContext colour = ic.getPops().get(0);
|
||||||
@@ -111,15 +117,21 @@ public class RasterizerAlpha extends AbstractInjector
|
|||||||
for (InstructionContext ins : mc.getInstructionContexts())
|
for (InstructionContext ins : mc.getInstructionContexts())
|
||||||
{
|
{
|
||||||
if (!(ins.getInstruction() instanceof SiPush))
|
if (!(ins.getInstruction() instanceof SiPush))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SiPush pci = (SiPush) ins.getInstruction();
|
SiPush pci = (SiPush) ins.getInstruction();
|
||||||
if ((short) pci.getConstant() != (short) 256)
|
if ((short) pci.getConstant() != (short) 256)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
InstructionContext isub = ins.getPushes().get(0).getPopped().get(0);
|
InstructionContext isub = ins.getPushes().get(0).getPopped().get(0);
|
||||||
if (!(isub.getInstruction() instanceof ISub))
|
if (!(isub.getInstruction() instanceof ISub))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
StackContext alphaPop = isub.getPops().get(0);
|
StackContext alphaPop = isub.getPops().get(0);
|
||||||
InstructionContext alphaPusher = alphaPop.getPushed();
|
InstructionContext alphaPusher = alphaPop.getPushed();
|
||||||
@@ -168,12 +180,16 @@ public class RasterizerAlpha extends AbstractInjector
|
|||||||
// If we're copying from the same field we don't have to apply extra alpha again
|
// If we're copying from the same field we don't have to apply extra alpha again
|
||||||
if (colPushI instanceof IALoad
|
if (colPushI instanceof IALoad
|
||||||
&& isSameField(r2dPx, colPusher.getPops().get(1)))
|
&& isSameField(r2dPx, colPusher.getPops().get(1)))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If the value is 0, it's supposed to be transparent, not black
|
// If the value is 0, it's supposed to be transparent, not black
|
||||||
if (colPushI instanceof PushConstantInstruction
|
if (colPushI instanceof PushConstantInstruction
|
||||||
&& ((PushConstantInstruction) colPushI).getConstant().equals(0))
|
&& ((PushConstantInstruction) colPushI).getConstant().equals(0))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// rasterPx[idx] = color | 0xff000000 (the | 0xff000000 is what's added)
|
// rasterPx[idx] = color | 0xff000000 (the | 0xff000000 is what's added)
|
||||||
int storeIdx = instrs.getInstructions().indexOf(instruction);
|
int storeIdx = instrs.getInstructions().indexOf(instruction);
|
||||||
@@ -217,7 +233,9 @@ public class RasterizerAlpha extends AbstractInjector
|
|||||||
{
|
{
|
||||||
Code c = mc.getMethod().getCode();
|
Code c = mc.getMethod().getCode();
|
||||||
if (c == null)
|
if (c == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return c.getInstructions();
|
return c.getInstructions();
|
||||||
}
|
}
|
||||||
@@ -226,11 +244,15 @@ public class RasterizerAlpha extends AbstractInjector
|
|||||||
{
|
{
|
||||||
InstructionContext pusher = stackContext.getPushed().resolve(stackContext);
|
InstructionContext pusher = stackContext.getPushed().resolve(stackContext);
|
||||||
if (pusher.getInstruction() instanceof GetFieldInstruction)
|
if (pusher.getInstruction() instanceof GetFieldInstruction)
|
||||||
|
{
|
||||||
return pusher;
|
return pusher;
|
||||||
|
}
|
||||||
|
|
||||||
// No field I wanna trace, rn at least
|
// No field I wanna trace, rn at least
|
||||||
if (!(pusher.getInstruction() instanceof LVTInstruction))
|
if (!(pusher.getInstruction() instanceof LVTInstruction))
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
int vidx = ((LVTInstruction) pusher.getInstruction()).getVariableIndex();
|
int vidx = ((LVTInstruction) pusher.getInstruction()).getVariableIndex();
|
||||||
|
|
||||||
@@ -245,7 +267,9 @@ public class RasterizerAlpha extends AbstractInjector
|
|||||||
InstructionContext ic = resolveFieldThroughInvokes(array);
|
InstructionContext ic = resolveFieldThroughInvokes(array);
|
||||||
|
|
||||||
if (ic == null)
|
if (ic == null)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ((GetFieldInstruction) ic.getInstruction()).getMyField() == f;
|
return ((GetFieldInstruction) ic.getInstruction()).getMyField() == f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ public class RenderDraw extends AbstractInjector
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (replaced != EXPECTED)
|
if (replaced != EXPECTED)
|
||||||
|
{
|
||||||
throw new InjectException("Didn't replace the expected amount of method calls");
|
throw new InjectException("Didn't replace the expected amount of method calls");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ public class InjectGetter
|
|||||||
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter)
|
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter)
|
||||||
{
|
{
|
||||||
if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null)
|
if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null)
|
||||||
|
{
|
||||||
throw new InjectException("Duplicate getter method " + apiMethod.getMethod().toString());
|
throw new InjectException("Duplicate getter method " + apiMethod.getMethod().toString());
|
||||||
|
}
|
||||||
|
|
||||||
final String name = apiMethod.getName();
|
final String name = apiMethod.getName();
|
||||||
final Signature sig = apiMethod.getSignature();
|
final Signature sig = apiMethod.getSignature();
|
||||||
@@ -75,7 +77,9 @@ public class InjectGetter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (getter != null)
|
if (getter != null)
|
||||||
|
{
|
||||||
InjectUtil.injectObfuscatedGetter(getter, instructions, ins::add);
|
InjectUtil.injectObfuscatedGetter(getter, instructions, ins::add);
|
||||||
|
}
|
||||||
|
|
||||||
ins.add(InjectUtil.createReturnForType(instructions, field.getType()));
|
ins.add(InjectUtil.createReturnForType(instructions, field.getType()));
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ public class InjectSetter
|
|||||||
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter)
|
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter)
|
||||||
{
|
{
|
||||||
if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null)
|
if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null)
|
||||||
|
{
|
||||||
throw new InjectException("Duplicate setter method " + apiMethod.getMethod().toString());
|
throw new InjectException("Duplicate setter method " + apiMethod.getMethod().toString());
|
||||||
|
}
|
||||||
|
|
||||||
final String name = apiMethod.getName();
|
final String name = apiMethod.getName();
|
||||||
final Signature sig = apiMethod.getSignature();
|
final Signature sig = apiMethod.getSignature();
|
||||||
@@ -69,7 +71,9 @@ public class InjectSetter
|
|||||||
|
|
||||||
// load this
|
// load this
|
||||||
if (!field.isStatic())
|
if (!field.isStatic())
|
||||||
|
{
|
||||||
ins.add(new ALoad(instructions, 0));
|
ins.add(new ALoad(instructions, 0));
|
||||||
|
}
|
||||||
|
|
||||||
// load argument
|
// load argument
|
||||||
final Type argumentType = sig.getTypeOfArg(0);
|
final Type argumentType = sig.getTypeOfArg(0);
|
||||||
@@ -85,12 +89,18 @@ public class InjectSetter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (getter != null)
|
if (getter != null)
|
||||||
|
{
|
||||||
InjectUtil.injectObfuscatedSetter(getter, instructions, ins::add);
|
InjectUtil.injectObfuscatedSetter(getter, instructions, ins::add);
|
||||||
|
}
|
||||||
|
|
||||||
if (field.isStatic())
|
if (field.isStatic())
|
||||||
|
{
|
||||||
ins.add(new PutStatic(instructions, field));
|
ins.add(new PutStatic(instructions, field));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ins.add(new PutField(instructions, field));
|
ins.add(new PutField(instructions, field));
|
||||||
|
}
|
||||||
|
|
||||||
ins.add(new VReturn(instructions));
|
ins.add(new VReturn(instructions));
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ public class RSApi implements Iterable<RSApiClass>
|
|||||||
for (File file : classes)
|
for (File file : classes)
|
||||||
{
|
{
|
||||||
if (!file.getName().startsWith("RS"))
|
if (!file.getName().startsWith("RS"))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try (InputStream is = new FileInputStream(file))
|
try (InputStream is = new FileInputStream(file))
|
||||||
{
|
{
|
||||||
@@ -72,7 +74,9 @@ public class RSApi implements Iterable<RSApiClass>
|
|||||||
final ImmutableMap.Builder<String, RSApiClass> builder = ImmutableMap.builder();
|
final ImmutableMap.Builder<String, RSApiClass> builder = ImmutableMap.builder();
|
||||||
|
|
||||||
for (RSApiClass clazz : this)
|
for (RSApiClass clazz : this)
|
||||||
|
{
|
||||||
builder.put(clazz.getName(), clazz);
|
builder.put(clazz.getName(), clazz);
|
||||||
|
}
|
||||||
|
|
||||||
this.map = builder.build();
|
this.map = builder.build();
|
||||||
|
|
||||||
@@ -112,11 +116,17 @@ public class RSApi implements Iterable<RSApiClass>
|
|||||||
{
|
{
|
||||||
RSApiClass clazz = findClass(interf.getName());
|
RSApiClass clazz = findClass(interf.getName());
|
||||||
if (clazz != null)
|
if (clazz != null)
|
||||||
|
{
|
||||||
return clazz;
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
for (RSApiClass apiC : this)
|
for (RSApiClass apiC : this)
|
||||||
|
{
|
||||||
if (apiC.getInterfaces().contains(interf))
|
if (apiC.getInterfaces().contains(interf))
|
||||||
|
{
|
||||||
return apiC;
|
return apiC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ public class RSApiClass extends ClassVisitor implements Iterable<RSApiMethod>
|
|||||||
for (RSApiMethod method : this)
|
for (RSApiMethod method : this)
|
||||||
{
|
{
|
||||||
if (method.isSynthetic())
|
if (method.isSynthetic())
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (method.findAnnotation(CONSTRUCT) != null)
|
if (method.findAnnotation(CONSTRUCT) != null)
|
||||||
{
|
{
|
||||||
@@ -56,12 +58,14 @@ public class RSApiClass extends ClassVisitor implements Iterable<RSApiMethod>
|
|||||||
|
|
||||||
final Annotation imported = method.findAnnotation(IMPORT);
|
final Annotation imported = method.findAnnotation(IMPORT);
|
||||||
if (imported != null)
|
if (imported != null)
|
||||||
|
{
|
||||||
imports.computeIfAbsent(
|
imports.computeIfAbsent(
|
||||||
imported.getValueString(),
|
imported.getValueString(),
|
||||||
(str) -> new ArrayList<>()
|
(str) -> new ArrayList<>()
|
||||||
).add(method);
|
).add(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RSApiMethod addMethod(String name, Signature sig, int access)
|
RSApiMethod addMethod(String name, Signature sig, int access)
|
||||||
{
|
{
|
||||||
@@ -79,7 +83,9 @@ public class RSApiClass extends ClassVisitor implements Iterable<RSApiMethod>
|
|||||||
{
|
{
|
||||||
List<RSApiMethod> imported = imports.get(str);
|
List<RSApiMethod> imported = imports.get(str);
|
||||||
if (imported == null)
|
if (imported == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
to.addAll(imported);
|
to.addAll(imported);
|
||||||
}
|
}
|
||||||
@@ -95,8 +101,10 @@ public class RSApiClass extends ClassVisitor implements Iterable<RSApiMethod>
|
|||||||
clazz = new Class(name);
|
clazz = new Class(name);
|
||||||
|
|
||||||
for (String s : interfaces)
|
for (String s : interfaces)
|
||||||
|
{
|
||||||
this.interfaces.add(new Class(s));
|
this.interfaces.add(new Class(s));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
|
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ package com.openosrs.injector.rsapi;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.runelite.asm.Annotation;
|
import net.runelite.asm.Annotation;
|
||||||
import net.runelite.asm.Named;
|
import net.runelite.asm.Named;
|
||||||
|
|||||||
@@ -15,10 +15,13 @@ import org.gradle.api.tasks.PathSensitivity
|
|||||||
interface InjectExtension {
|
interface InjectExtension {
|
||||||
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
||||||
val vanilla: RegularFileProperty
|
val vanilla: RegularFileProperty
|
||||||
|
|
||||||
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
||||||
val rsclient: RegularFileProperty
|
val rsclient: RegularFileProperty
|
||||||
|
|
||||||
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
||||||
val mixins: RegularFileProperty
|
val mixins: RegularFileProperty
|
||||||
|
|
||||||
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
||||||
val rsapi: RegularFileProperty
|
val rsapi: RegularFileProperty
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import org.gradle.api.Plugin
|
|||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
|
||||||
class InjectPlugin : Plugin<Project> {
|
class InjectPlugin : Plugin<Project> {
|
||||||
override fun apply(project: Project) { with(project) {
|
override fun apply(project: Project) {
|
||||||
|
with(project) {
|
||||||
val task = tasks.create("inject", Inject::class.java)
|
val task = tasks.create("inject", Inject::class.java)
|
||||||
task.output.convention { file("$buildDir/libs/$name-$version.jar") }
|
task.output.convention { file("$buildDir/libs/$name-$version.jar") }
|
||||||
|
|
||||||
@@ -24,5 +25,6 @@ class InjectPlugin: Plugin<Project> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extensions.add(InjectExtension::class.java, "injector", task.extension)
|
extensions.add(InjectExtension::class.java, "injector", task.extension)
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -283,7 +283,10 @@ public class MixinInjectorTest
|
|||||||
Instruction i;
|
Instruction i;
|
||||||
while (it.hasNext() &&
|
while (it.hasNext() &&
|
||||||
!((i = it.next()) instanceof GetStatic &&
|
!((i = it.next()) instanceof GetStatic &&
|
||||||
((GetStatic) i).getField().getName().equals(gottenField)));
|
((GetStatic) i).getField().getName().equals(gottenField)))
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
(i = it.next()) instanceof LDC &&
|
(i = it.next()) instanceof LDC &&
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
|
|
||||||
* 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 com.openosrs.injector.injectors.raw;
|
|
||||||
|
|
||||||
import com.google.common.io.ByteStreams;
|
|
||||||
import com.openosrs.injector.TestInjection;
|
|
||||||
import com.openosrs.injector.injection.InjectData;
|
|
||||||
import com.openosrs.injector.rsapi.RSApi;
|
|
||||||
import net.runelite.asm.ClassFile;
|
|
||||||
import net.runelite.asm.ClassGroup;
|
|
||||||
import net.runelite.deob.util.JarUtil;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class DrawAfterWidgetsTest
|
|
||||||
{
|
|
||||||
@Test
|
|
||||||
public void testInjectDrawWidgetsRev160() throws Exception
|
|
||||||
{
|
|
||||||
// Rev 160 does not have the drawWidgets call inlined
|
|
||||||
|
|
||||||
ClassFile deobClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_deob160.class")));
|
|
||||||
ClassFile deobRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_deob160.class")));
|
|
||||||
|
|
||||||
ClassGroup deob = new ClassGroup();
|
|
||||||
deob.addClass(deobClient);
|
|
||||||
deob.addClass(deobRasterizer);
|
|
||||||
|
|
||||||
ClassFile obClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_ob160.class")));
|
|
||||||
ClassFile obRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_ob160.class")));
|
|
||||||
|
|
||||||
ClassGroup vanilla = new ClassGroup();
|
|
||||||
vanilla.addClass(obClient);
|
|
||||||
vanilla.addClass(obRasterizer);
|
|
||||||
|
|
||||||
InjectData inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
|
||||||
new DrawAfterWidgets(inject).inject();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInjectDrawWidgetsRev180() throws Exception
|
|
||||||
{
|
|
||||||
// Rev 180 has the drawWidgets call inlined
|
|
||||||
|
|
||||||
ClassFile deobClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_deob180.class")));
|
|
||||||
ClassFile deobRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_deob180.class")));
|
|
||||||
|
|
||||||
ClassGroup deob = new ClassGroup();
|
|
||||||
deob.addClass(deobClient);
|
|
||||||
deob.addClass(deobRasterizer);
|
|
||||||
|
|
||||||
ClassFile obClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_ob180.class")));
|
|
||||||
ClassFile obRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_ob180.class")));
|
|
||||||
|
|
||||||
ClassGroup vanilla = new ClassGroup();
|
|
||||||
vanilla.addClass(obClient);
|
|
||||||
vanilla.addClass(obRasterizer);
|
|
||||||
|
|
||||||
InjectData inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
|
||||||
new DrawAfterWidgets(inject).inject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -36,9 +36,11 @@ public class SourceChangerTest
|
|||||||
new ClassReader(PACKAGE + "OldName").accept(vann, ClassReader.SKIP_FRAMES);
|
new ClassReader(PACKAGE + "OldName").accept(vann, ClassReader.SKIP_FRAMES);
|
||||||
|
|
||||||
new SourceChanger(
|
new SourceChanger(
|
||||||
new InjectData(new ClassGroup(), new ClassGroup(), null, null) {
|
new InjectData(new ClassGroup(), new ClassGroup(), null, null)
|
||||||
|
{
|
||||||
public void runChildInjector(Injector injector) throws InjectException
|
public void runChildInjector(Injector injector) throws InjectException
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forEachPair(BiConsumer<ClassFile, ClassFile> consumer)
|
public void forEachPair(BiConsumer<ClassFile, ClassFile> consumer)
|
||||||
|
|||||||
@@ -350,4 +350,10 @@ public final class ScriptID
|
|||||||
|
|
||||||
@ScriptArguments(integer = 7)
|
@ScriptArguments(integer = 7)
|
||||||
public static final int SETTINGS_SLIDER_CHOOSE_ONOP = 3885;
|
public static final int SETTINGS_SLIDER_CHOOSE_ONOP = 3885;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position and size the wiki button, as well as hide/unhide it
|
||||||
|
*/
|
||||||
|
@ScriptArguments(integer = 4)
|
||||||
|
public static final int WIKI_ICON_UPDATE = 3306;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import static net.runelite.api.Constants.CHUNK_SIZE;
|
import static net.runelite.api.Constants.CHUNK_SIZE;
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import java.awt.Graphics;
|
|||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.MouseWheelEvent;
|
import java.awt.event.MouseWheelEvent;
|
||||||
|
import java.util.List;
|
||||||
import net.runelite.api.MainBufferProvider;
|
import net.runelite.api.MainBufferProvider;
|
||||||
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetItem;
|
import net.runelite.api.widgets.WidgetItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,8 +72,9 @@ public interface Callbacks
|
|||||||
*/
|
*/
|
||||||
void drawAboveOverheads();
|
void drawAboveOverheads();
|
||||||
|
|
||||||
void drawAfterWidgets();
|
void drawLayer(Widget layer, List<WidgetItem> widgetItems);
|
||||||
|
|
||||||
|
void drawInterface(int interfaceId, List<WidgetItem> widgetItems);
|
||||||
/**
|
/**
|
||||||
* Client top-most draw method, rendering over top of most of game interfaces.
|
* Client top-most draw method, rendering over top of most of game interfaces.
|
||||||
*
|
*
|
||||||
@@ -82,11 +85,6 @@ public interface Callbacks
|
|||||||
*/
|
*/
|
||||||
void draw(MainBufferProvider mainBufferProvider, Graphics graphics, int x, int y);
|
void draw(MainBufferProvider mainBufferProvider, Graphics graphics, int x, int y);
|
||||||
|
|
||||||
/**
|
|
||||||
* Called before the client will render an item widget.
|
|
||||||
*/
|
|
||||||
void drawItem(int itemId, WidgetItem widgetItem);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mouse pressed event. If this event will be consumed it will not be propagated further to client.
|
* Mouse pressed event. If this event will be consumed it will not be propagated further to client.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ package net.runelite.api.widgets;
|
|||||||
|
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import net.runelite.api.FontTypeFace;
|
import net.runelite.api.FontTypeFace;
|
||||||
import net.runelite.api.Point;
|
import net.runelite.api.Point;
|
||||||
import net.runelite.api.SpritePixels;
|
import net.runelite.api.SpritePixels;
|
||||||
@@ -475,7 +476,7 @@ public interface Widget
|
|||||||
*
|
*
|
||||||
* @return any items displayed, or null if there are no items
|
* @return any items displayed, or null if there are no items
|
||||||
*/
|
*/
|
||||||
Collection<WidgetItem> getWidgetItems();
|
List<WidgetItem> getWidgetItems();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a widget item at a specific index.
|
* Gets a widget item at a specific index.
|
||||||
|
|||||||
@@ -974,6 +974,11 @@ public enum WidgetInfo
|
|||||||
return groupId << 16 | childId;
|
return groupId << 16 | childId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int PACK(int groupId, int childId)
|
||||||
|
{
|
||||||
|
return groupId << 16 | childId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility method that converts an ID returned by {@link #getId()} back
|
* Utility method that converts an ID returned by {@link #getId()} back
|
||||||
* to its group ID.
|
* to its group ID.
|
||||||
@@ -993,7 +998,7 @@ public enum WidgetInfo
|
|||||||
* @param id passed group-child ID
|
* @param id passed group-child ID
|
||||||
* @return the child ID
|
* @return the child ID
|
||||||
*/
|
*/
|
||||||
public static int getChildFromID(int id)
|
public static int TO_CHILD(int id)
|
||||||
{
|
{
|
||||||
return id & 0xFFFF;
|
return id & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import net.runelite.http.api.RuneLiteAPI;
|
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
|
|
||||||
public class RuneLiteProperties
|
public class RuneLiteProperties
|
||||||
@@ -145,7 +144,7 @@ public class RuneLiteProperties
|
|||||||
public static HttpUrl getPluginHubBase()
|
public static HttpUrl getPluginHubBase()
|
||||||
{
|
{
|
||||||
String version = System.getProperty(PLUGINHUB_VERSION, properties.getProperty(PLUGINHUB_VERSION));
|
String version = System.getProperty(PLUGINHUB_VERSION, properties.getProperty(PLUGINHUB_VERSION));
|
||||||
return HttpUrl.parse(properties.get(PLUGINHUB_BASE) + "/" + RuneLiteAPI.getVersion());
|
return HttpUrl.parse(properties.get(PLUGINHUB_BASE) + "/" + version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getImgurClientId()
|
public static String getImgurClientId()
|
||||||
|
|||||||
@@ -37,15 +37,15 @@ import java.awt.event.MouseEvent;
|
|||||||
import java.awt.event.MouseWheelEvent;
|
import java.awt.event.MouseWheelEvent;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.VolatileImage;
|
import java.awt.image.VolatileImage;
|
||||||
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.BufferProvider;
|
import net.runelite.api.BufferProvider;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.Renderable;
|
|
||||||
import net.runelite.api.MainBufferProvider;
|
import net.runelite.api.MainBufferProvider;
|
||||||
import net.runelite.api.NullItemID;
|
|
||||||
import net.runelite.api.RenderOverview;
|
import net.runelite.api.RenderOverview;
|
||||||
|
import net.runelite.api.Renderable;
|
||||||
import net.runelite.api.Skill;
|
import net.runelite.api.Skill;
|
||||||
import net.runelite.api.WorldMapManager;
|
import net.runelite.api.WorldMapManager;
|
||||||
import net.runelite.api.events.BeforeMenuRender;
|
import net.runelite.api.events.BeforeMenuRender;
|
||||||
@@ -331,7 +331,7 @@ public class Hooks implements Callbacks
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
renderer.render(graphics2d, OverlayLayer.ALWAYS_ON_TOP);
|
renderer.renderOverlayLayer(graphics2d, OverlayLayer.ALWAYS_ON_TOP);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -426,7 +426,7 @@ public class Hooks implements Callbacks
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
renderer.render(graphics2d, OverlayLayer.ABOVE_SCENE);
|
renderer.renderOverlayLayer(graphics2d, OverlayLayer.ABOVE_SCENE);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -442,7 +442,7 @@ public class Hooks implements Callbacks
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
renderer.render(graphics2d, OverlayLayer.UNDER_WIDGETS);
|
renderer.renderOverlayLayer(graphics2d, OverlayLayer.UNDER_WIDGETS);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -450,27 +450,6 @@ public class Hooks implements Callbacks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawAfterWidgets()
|
|
||||||
{
|
|
||||||
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
|
|
||||||
Graphics2D graphics2d = getGraphics(bufferProvider);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
renderer.render(graphics2d, OverlayLayer.ABOVE_MAP);
|
|
||||||
renderer.render(graphics2d, OverlayLayer.ABOVE_WIDGETS);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
log.warn("Error during overlay rendering", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WidgetItemOverlays render at ABOVE_WIDGETS, reset widget item
|
|
||||||
// list for next frame.
|
|
||||||
overlayManager.getItemWidgets().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||||
{
|
{
|
||||||
@@ -508,12 +487,34 @@ public class Hooks implements Callbacks
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawItem(int itemId, WidgetItem widgetItem)
|
public void drawInterface(int interfaceId, List<WidgetItem> widgetItems)
|
||||||
{
|
{
|
||||||
// Empty bank item
|
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
|
||||||
if (widgetItem.getId() != NullItemID.NULL_6512)
|
Graphics2D graphics2d = getGraphics(bufferProvider);
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
overlayManager.getItemWidgets().add(widgetItem);
|
renderer.renderAfterInterface(graphics2d, interfaceId, widgetItems);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log.warn("Error during overlay rendering", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawLayer(Widget layer, List<WidgetItem> widgetItems)
|
||||||
|
{
|
||||||
|
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
|
||||||
|
Graphics2D graphics2d = getGraphics(bufferProvider);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
renderer.renderAfterLayer(graphics2d, layer, widgetItems);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log.warn("Error during overlay rendering", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,6 +540,7 @@ public class Hooks implements Callbacks
|
|||||||
eventBus.post(fakeXpDrop);
|
eventBus.post(fakeXpDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void clearColorBuffer(int x, int y, int width, int height, int color)
|
public static void clearColorBuffer(int x, int y, int width, int height, int color)
|
||||||
{
|
{
|
||||||
BufferProvider bp = client.getBufferProvider();
|
BufferProvider bp = client.getBufferProvider();
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package net.runelite.client.config;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.runelite.client.ui.FontManager;
|
import net.runelite.client.ui.FontManager;
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@@ -67,13 +67,12 @@ public class ExternalPluginClient
|
|||||||
{
|
{
|
||||||
HttpUrl manifest = RuneLiteProperties.getPluginHubBase()
|
HttpUrl manifest = RuneLiteProperties.getPluginHubBase()
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.addPathSegment("manifest.js")
|
.addPathSegments("manifest.js")
|
||||||
.build();
|
.build();
|
||||||
try (Response res = okHttpClient.newCall(new Request.Builder().url(manifest).build()).execute())
|
try (Response res = okHttpClient.newCall(new Request.Builder().url(manifest).build()).execute())
|
||||||
{
|
{
|
||||||
if (res.code() != 200)
|
if (res.code() != 200)
|
||||||
{
|
{
|
||||||
System.out.println(manifest.url().toString());
|
|
||||||
throw new IOException("Non-OK response code: " + res.code());
|
throw new IOException("Non-OK response code: " + res.code());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,10 +118,10 @@ public enum AgilityShortcut
|
|||||||
GNOME_STRONGHOLD_ROCKS(37, "Rocks", new WorldPoint(2485, 3515, 0), ROCKS_16534, ROCKS_16535),
|
GNOME_STRONGHOLD_ROCKS(37, "Rocks", new WorldPoint(2485, 3515, 0), ROCKS_16534, ROCKS_16535),
|
||||||
AL_KHARID_MINING_PITCLIFF_SCRAMBLE(38, "Rocks", new WorldPoint(3305, 3315, 0), ROCKS_16549, ROCKS_16550),
|
AL_KHARID_MINING_PITCLIFF_SCRAMBLE(38, "Rocks", new WorldPoint(3305, 3315, 0), ROCKS_16549, ROCKS_16550),
|
||||||
YANILLE_WALL_GRAPPLE(39, "Grapple Wall", new WorldPoint(2552, 3072, 0), WALL_17047),
|
YANILLE_WALL_GRAPPLE(39, "Grapple Wall", new WorldPoint(2552, 3072, 0), WALL_17047),
|
||||||
NEITIZNOT_BRIDGE_REPAIR(40, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307),
|
NEITIZNOT_BRIDGE_REPAIR(0, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307),
|
||||||
NEITIZNOT_BRIDGE_SOUTHEAST(40, "Rope Bridge", null, ROPE_BRIDGE_21308, ROPE_BRIDGE_21309),
|
NEITIZNOT_BRIDGE_SOUTHEAST(0, "Rope Bridge", null, ROPE_BRIDGE_21308, ROPE_BRIDGE_21309),
|
||||||
NEITIZNOT_BRIDGE_NORTHWEST(40, "Rope Bridge", null, ROPE_BRIDGE_21310, ROPE_BRIDGE_21311),
|
NEITIZNOT_BRIDGE_NORTHWEST(0, "Rope Bridge", null, ROPE_BRIDGE_21310, ROPE_BRIDGE_21311),
|
||||||
NEITIZNOT_BRIDGE_NORTH(40, "Rope Bridge", null, ROPE_BRIDGE_21312, ROPE_BRIDGE_21313),
|
NEITIZNOT_BRIDGE_NORTH(0, "Rope Bridge", null, ROPE_BRIDGE_21312, ROPE_BRIDGE_21313),
|
||||||
NEITIZNOT_BRIDGE_NORTHEAST(40, "Broken Rope bridge", null, ROPE_BRIDGE_21314, ROPE_BRIDGE_21315),
|
NEITIZNOT_BRIDGE_NORTHEAST(40, "Broken Rope bridge", null, ROPE_BRIDGE_21314, ROPE_BRIDGE_21315),
|
||||||
KOUREND_LAKE_JUMP_EAST(40, "Stepping Stones", new WorldPoint(1612, 3570, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
|
KOUREND_LAKE_JUMP_EAST(40, "Stepping Stones", new WorldPoint(1612, 3570, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
|
||||||
KOUREND_LAKE_JUMP_WEST(40, "Stepping Stones", new WorldPoint(1604, 3572, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
|
KOUREND_LAKE_JUMP_WEST(40, "Stepping Stones", new WorldPoint(1604, 3572, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
|
||||||
|
|||||||
@@ -24,11 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.game;
|
package net.runelite.client.game;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@@ -46,14 +42,12 @@ public class NPCManager
|
|||||||
{
|
{
|
||||||
private final OkHttpClient okHttpClient;
|
private final OkHttpClient okHttpClient;
|
||||||
private Map<Integer, NpcInfo> npcMap = Collections.emptyMap();
|
private Map<Integer, NpcInfo> npcMap = Collections.emptyMap();
|
||||||
private ImmutableMap<Integer, NPCStats> statsMap;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private NPCManager(OkHttpClient okHttpClient, ScheduledExecutorService scheduledExecutorService)
|
private NPCManager(OkHttpClient okHttpClient, ScheduledExecutorService scheduledExecutorService)
|
||||||
{
|
{
|
||||||
this.okHttpClient = okHttpClient;
|
this.okHttpClient = okHttpClient;
|
||||||
scheduledExecutorService.execute(this::loadNpcs);
|
scheduledExecutorService.execute(this::loadNpcs);
|
||||||
loadStats();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -80,45 +74,4 @@ public class NPCManager
|
|||||||
log.warn("error loading npc stats", e);
|
log.warn("error loading npc stats", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadStats()
|
|
||||||
{
|
|
||||||
try (JsonReader reader = new JsonReader(new InputStreamReader(NPCManager.class.getResourceAsStream("/npc_stats.json"), StandardCharsets.UTF_8)))
|
|
||||||
{
|
|
||||||
ImmutableMap.Builder<Integer, NPCStats> builder = ImmutableMap.builderWithExpectedSize(2821);
|
|
||||||
reader.beginObject();
|
|
||||||
|
|
||||||
while (reader.hasNext())
|
|
||||||
{
|
|
||||||
builder.put(
|
|
||||||
Integer.parseInt(reader.nextName()),
|
|
||||||
NPCStats.NPC_STATS_TYPE_ADAPTER.read(reader)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.endObject();
|
|
||||||
statsMap = builder.build();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the attack speed for target NPC ID.
|
|
||||||
*
|
|
||||||
* @param npcId NPC id
|
|
||||||
* @return attack speed in game ticks for NPC ID.
|
|
||||||
*/
|
|
||||||
public int getAttackSpeed(final int npcId)
|
|
||||||
{
|
|
||||||
final NPCStats s = statsMap.get(npcId);
|
|
||||||
if (s == null || s.getAttackSpeed() == -1)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.getAttackSpeed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,203 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.game;
|
|
||||||
|
|
||||||
import com.google.gson.TypeAdapter;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
@Value
|
|
||||||
@Builder(builderClassName = "Builder")
|
|
||||||
public class NPCStats
|
|
||||||
{
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private final int hitpoints;
|
|
||||||
private final int combatLevel;
|
|
||||||
private final int slayerLevel;
|
|
||||||
private final int attackSpeed;
|
|
||||||
|
|
||||||
private final int attackLevel;
|
|
||||||
private final int strengthLevel;
|
|
||||||
private final int defenceLevel;
|
|
||||||
private final int rangeLevel;
|
|
||||||
private final int magicLevel;
|
|
||||||
|
|
||||||
private final int stab;
|
|
||||||
private final int slash;
|
|
||||||
private final int crush;
|
|
||||||
private final int range;
|
|
||||||
private final int magic;
|
|
||||||
|
|
||||||
private final int stabDef;
|
|
||||||
private final int slashDef;
|
|
||||||
private final int crushDef;
|
|
||||||
private final int rangeDef;
|
|
||||||
private final int magicDef;
|
|
||||||
|
|
||||||
private final int bonusAttack;
|
|
||||||
private final int bonusStrength;
|
|
||||||
private final int bonusRangeStrength;
|
|
||||||
private final int bonusMagicDamage;
|
|
||||||
|
|
||||||
private final boolean poisonImmune;
|
|
||||||
private final boolean venomImmune;
|
|
||||||
|
|
||||||
private final boolean dragon;
|
|
||||||
private final boolean demon;
|
|
||||||
private final boolean undead;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Based off the formula found here: http://services.runescape.com/m=forum/c=PLuJ4cy6gtA/forums.ws?317,318,712,65587452,209,337584542#209
|
|
||||||
*
|
|
||||||
* @return bonus XP modifier
|
|
||||||
*/
|
|
||||||
public double calculateXpModifier()
|
|
||||||
{
|
|
||||||
final double averageLevel = Math.floor((attackLevel + strengthLevel + defenceLevel + hitpoints) / 4);
|
|
||||||
final double averageDefBonus = Math.floor((stabDef + slashDef + crushDef) / 3);
|
|
||||||
|
|
||||||
return (1 + Math.floor(averageLevel * (averageDefBonus + bonusStrength + bonusAttack) / 5120) / 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Because this class is here we can't add the TypeAdapter to gson (easily)
|
|
||||||
// doesn't mean we can't use one to do it a bit quicker
|
|
||||||
public static final TypeAdapter<NPCStats> NPC_STATS_TYPE_ADAPTER = new TypeAdapter<>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void write(JsonWriter out, NPCStats value)
|
|
||||||
{
|
|
||||||
throw new UnsupportedOperationException("Not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public NPCStats read(JsonReader in) throws IOException
|
|
||||||
{
|
|
||||||
in.beginObject();
|
|
||||||
NPCStats.Builder builder = NPCStats.builder();
|
|
||||||
|
|
||||||
// Name is the only one that's guaranteed
|
|
||||||
in.skipValue();
|
|
||||||
builder.name(in.nextString());
|
|
||||||
|
|
||||||
while (in.hasNext())
|
|
||||||
{
|
|
||||||
switch (in.nextName())
|
|
||||||
{
|
|
||||||
case "hitpoints":
|
|
||||||
builder.hitpoints(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "combatLevel":
|
|
||||||
builder.combatLevel(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "slayerLevel":
|
|
||||||
builder.slayerLevel(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "attackSpeed":
|
|
||||||
builder.attackSpeed(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "attackLevel":
|
|
||||||
builder.attackLevel(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "strengthLevel":
|
|
||||||
builder.strengthLevel(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "defenceLevel":
|
|
||||||
builder.defenceLevel(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "rangeLevel":
|
|
||||||
builder.rangeLevel(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "magicLevel":
|
|
||||||
builder.magicLevel(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "stab":
|
|
||||||
builder.stab(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "slash":
|
|
||||||
builder.slash(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "crush":
|
|
||||||
builder.crush(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "range":
|
|
||||||
builder.range(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "magic":
|
|
||||||
builder.magic(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "stabDef":
|
|
||||||
builder.stabDef(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "slashDef":
|
|
||||||
builder.slashDef(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "crushDef":
|
|
||||||
builder.crushDef(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "rangeDef":
|
|
||||||
builder.rangeDef(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "magicDef":
|
|
||||||
builder.magicDef(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "bonusAttack":
|
|
||||||
builder.bonusAttack(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "bonusStrength":
|
|
||||||
builder.bonusStrength(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "bonusRangeStrength":
|
|
||||||
builder.bonusRangeStrength(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "bonusMagicDamage":
|
|
||||||
builder.bonusMagicDamage(in.nextInt());
|
|
||||||
break;
|
|
||||||
case "poisonImmune":
|
|
||||||
builder.poisonImmune(in.nextBoolean());
|
|
||||||
break;
|
|
||||||
case "venomImmune":
|
|
||||||
builder.venomImmune(in.nextBoolean());
|
|
||||||
break;
|
|
||||||
case "dragon":
|
|
||||||
builder.dragon(in.nextBoolean());
|
|
||||||
break;
|
|
||||||
case "demon":
|
|
||||||
builder.demon(in.nextBoolean());
|
|
||||||
break;
|
|
||||||
case "undead":
|
|
||||||
builder.undead(in.nextBoolean());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
in.endObject();
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -140,7 +140,7 @@ public class MenuManager
|
|||||||
|
|
||||||
MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
|
MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
|
||||||
menuEntry.setOption(currentMenu.getMenuOption());
|
menuEntry.setOption(currentMenu.getMenuOption());
|
||||||
menuEntry.setActionParam1(widgetId);
|
menuEntry.setParam1(widgetId);
|
||||||
menuEntry.setTarget(currentMenu.getMenuTarget());
|
menuEntry.setTarget(currentMenu.getMenuTarget());
|
||||||
menuEntry.setType(MenuAction.RUNELITE.getId());
|
menuEntry.setType(MenuAction.RUNELITE.getId());
|
||||||
|
|
||||||
@@ -241,17 +241,17 @@ public class MenuManager
|
|||||||
return; // not a managed widget option or custom player option
|
return; // not a managed widget option or custom player option
|
||||||
}
|
}
|
||||||
|
|
||||||
int widgetId = event.getActionParam1();
|
int widgetId = event.getWidgetId();
|
||||||
Collection<WidgetMenuOption> options = managedMenuOptions.get(widgetId);
|
Collection<WidgetMenuOption> options = managedMenuOptions.get(widgetId);
|
||||||
|
|
||||||
for (WidgetMenuOption curMenuOption : options)
|
for (WidgetMenuOption curMenuOption : options)
|
||||||
{
|
{
|
||||||
if (curMenuOption.getMenuTarget().equals(event.getTarget())
|
if (curMenuOption.getMenuTarget().equals(event.getMenuTarget())
|
||||||
&& curMenuOption.getMenuOption().equals(event.getOption()))
|
&& curMenuOption.getMenuOption().equals(event.getMenuOption()))
|
||||||
{
|
{
|
||||||
WidgetMenuOptionClicked customMenu = new WidgetMenuOptionClicked();
|
WidgetMenuOptionClicked customMenu = new WidgetMenuOptionClicked();
|
||||||
customMenu.setMenuOption(event.getOption());
|
customMenu.setMenuOption(event.getMenuOption());
|
||||||
customMenu.setMenuTarget(event.getTarget());
|
customMenu.setMenuTarget(event.getMenuTarget());
|
||||||
customMenu.setWidget(curMenuOption.getWidget());
|
customMenu.setWidget(curMenuOption.getWidget());
|
||||||
eventBus.post(customMenu);
|
eventBus.post(customMenu);
|
||||||
return; // don't continue because it's not a player option
|
return; // don't continue because it's not a player option
|
||||||
@@ -260,14 +260,14 @@ public class MenuManager
|
|||||||
|
|
||||||
// removes bounty hunter emblem tag and tier from player name, e.g:
|
// removes bounty hunter emblem tag and tier from player name, e.g:
|
||||||
// "username<img=20>5<col=40ff00> (level-42)" -> "username<col=40ff00> (level-42)"
|
// "username<img=20>5<col=40ff00> (level-42)" -> "username<col=40ff00> (level-42)"
|
||||||
String target = BOUNTY_EMBLEM_TAG_AND_TIER_REGEXP.matcher(event.getTarget()).replaceAll("");
|
String target = BOUNTY_EMBLEM_TAG_AND_TIER_REGEXP.matcher(event.getMenuTarget()).replaceAll("");
|
||||||
|
|
||||||
// removes tags and level from player names for example:
|
// removes tags and level from player names for example:
|
||||||
// <col=ffffff>username<col=40ff00> (level-42) or <col=ffffff><img=2>username</col>
|
// <col=ffffff>username<col=40ff00> (level-42) or <col=ffffff><img=2>username</col>
|
||||||
String username = Text.removeTags(target).split("[(]")[0].trim();
|
String username = Text.removeTags(target).split("[(]")[0].trim();
|
||||||
|
|
||||||
PlayerMenuOptionClicked playerMenuOptionClicked = new PlayerMenuOptionClicked();
|
PlayerMenuOptionClicked playerMenuOptionClicked = new PlayerMenuOptionClicked();
|
||||||
playerMenuOptionClicked.setMenuOption(event.getOption());
|
playerMenuOptionClicked.setMenuOption(event.getMenuOption());
|
||||||
playerMenuOptionClicked.setMenuTarget(username);
|
playerMenuOptionClicked.setMenuTarget(username);
|
||||||
|
|
||||||
eventBus.post(playerMenuOptionClicked);
|
eventBus.post(playerMenuOptionClicked);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
package net.runelite.client.menus;
|
package net.runelite.client.menus;
|
||||||
|
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import net.runelite.client.ui.JagexColors;
|
import net.runelite.client.ui.JagexColors;
|
||||||
import net.runelite.client.util.ColorUtil;
|
import net.runelite.client.util.ColorUtil;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package net.runelite.client.plugins.blastmine;
|
|||||||
import net.runelite.client.config.Config;
|
import net.runelite.client.config.Config;
|
||||||
import net.runelite.client.config.ConfigGroup;
|
import net.runelite.client.config.ConfigGroup;
|
||||||
import net.runelite.client.config.ConfigItem;
|
import net.runelite.client.config.ConfigItem;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
|
||||||
@ConfigGroup("blastmine")
|
@ConfigGroup("blastmine")
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ import net.runelite.api.Point;
|
|||||||
import net.runelite.api.Tile;
|
import net.runelite.api.Tile;
|
||||||
import net.runelite.api.coords.LocalPoint;
|
import net.runelite.api.coords.LocalPoint;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import net.runelite.api.widgets.Widget;
|
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||||
@@ -91,12 +90,10 @@ public class BlastMineRockOverlay extends Overlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Tile[][][] tiles = client.getScene().getTiles();
|
final Tile[][][] tiles = client.getScene().getTiles();
|
||||||
final Widget viewport = client.getViewportWidget();
|
|
||||||
|
|
||||||
for (final BlastMineRock rock : rocks.values())
|
for (final BlastMineRock rock : rocks.values())
|
||||||
{
|
{
|
||||||
if (viewport == null ||
|
if (rock.getGameObject().getCanvasLocation() == null ||
|
||||||
rock.getGameObject().getCanvasLocation() == null ||
|
|
||||||
rock.getGameObject().getWorldLocation().distanceTo(client.getLocalPlayer().getWorldLocation()) > MAX_DISTANCE)
|
rock.getGameObject().getWorldLocation().distanceTo(client.getLocalPlayer().getWorldLocation()) > MAX_DISTANCE)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -136,10 +136,6 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener
|
|||||||
Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT);
|
Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT);
|
||||||
if (settingsInit != null)
|
if (settingsInit != null)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("Implement");
|
|
||||||
//client.createScriptEvent(settingsInit.getOnLoadListener())
|
|
||||||
//.setSource(settingsInit)
|
|
||||||
//.run();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -165,10 +161,6 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener
|
|||||||
Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT);
|
Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT);
|
||||||
if (settingsInit != null)
|
if (settingsInit != null)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("Implement");
|
|
||||||
//client.createScriptEvent(settingsInit.getOnLoadListener())
|
|
||||||
//.setSource(settingsInit)
|
|
||||||
//.run();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ import net.runelite.api.events.MenuOptionClicked;
|
|||||||
import net.runelite.api.vars.InputType;
|
import net.runelite.api.vars.InputType;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
|
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
import net.runelite.client.chat.ChatMessageManager;
|
import net.runelite.client.chat.ChatMessageManager;
|
||||||
@@ -204,7 +204,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int groupId = TO_GROUP(entry.getParam1());
|
final int groupId = TO_GROUP(entry.getParam1());
|
||||||
final int childId = getChildFromID(entry.getParam1());
|
final int childId = TO_CHILD(entry.getParam1());
|
||||||
|
|
||||||
if (groupId != WidgetInfo.CHATBOX.getGroupId())
|
if (groupId != WidgetInfo.CHATBOX.getGroupId())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -280,6 +280,8 @@ class PluginHubPanel extends PluginPanel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addrm.setText("Installing");
|
||||||
|
addrm.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||||
externalPluginManager.install(manifest.getInternalName());
|
externalPluginManager.install(manifest.getInternalName());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -287,14 +289,24 @@ class PluginHubPanel extends PluginPanel
|
|||||||
{
|
{
|
||||||
addrm.setText("Remove");
|
addrm.setText("Remove");
|
||||||
addrm.setBackground(new Color(0xBE2828));
|
addrm.setBackground(new Color(0xBE2828));
|
||||||
addrm.addActionListener(l -> externalPluginManager.remove(manifest.getInternalName()));
|
addrm.addActionListener(l ->
|
||||||
|
{
|
||||||
|
addrm.setText("Removing");
|
||||||
|
addrm.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||||
|
externalPluginManager.remove(manifest.getInternalName());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert update;
|
assert update;
|
||||||
addrm.setText("Update");
|
addrm.setText("Update");
|
||||||
addrm.setBackground(new Color(0x1F621F));
|
addrm.setBackground(new Color(0x1F621F));
|
||||||
addrm.addActionListener(l -> externalPluginManager.update());
|
addrm.addActionListener(l ->
|
||||||
|
{
|
||||||
|
addrm.setText("Updating");
|
||||||
|
addrm.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||||
|
externalPluginManager.update();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
addrm.setBorder(new LineBorder(addrm.getBackground().darker()));
|
addrm.setBorder(new LineBorder(addrm.getBackground().darker()));
|
||||||
addrm.setFocusPainted(false);
|
addrm.setFocusPainted(false);
|
||||||
@@ -313,7 +325,7 @@ class PluginHubPanel extends PluginPanel
|
|||||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, 100)
|
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, 100)
|
||||||
.addComponent(help, 0, 24, 24)
|
.addComponent(help, 0, 24, 24)
|
||||||
.addComponent(configure, 0, 24, 24)
|
.addComponent(configure, 0, 24, 24)
|
||||||
.addComponent(addrm, 0, 50, GroupLayout.PREFERRED_SIZE)
|
.addComponent(addrm, 0, 57, GroupLayout.PREFERRED_SIZE)
|
||||||
.addGap(5))));
|
.addGap(5))));
|
||||||
|
|
||||||
int lineHeight = description.getFontMetrics(description.getFont()).getHeight();
|
int lineHeight = description.getFontMetrics(description.getFont()).getHeight();
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ class PluginListPanel extends PluginPanel
|
|||||||
private static final String RUNELITE_GROUP_NAME = RuneLiteConfig.class.getAnnotation(ConfigGroup.class).value();
|
private static final String RUNELITE_GROUP_NAME = RuneLiteConfig.class.getAnnotation(ConfigGroup.class).value();
|
||||||
private static final String PINNED_PLUGINS_CONFIG_KEY = "pinnedPlugins";
|
private static final String PINNED_PLUGINS_CONFIG_KEY = "pinnedPlugins";
|
||||||
private static final ImmutableList<String> CATEGORY_TAGS = ImmutableList.of(
|
private static final ImmutableList<String> CATEGORY_TAGS = ImmutableList.of(
|
||||||
"OpenOSRS",
|
|
||||||
"Combat",
|
"Combat",
|
||||||
"Chat",
|
"Chat",
|
||||||
"Item",
|
"Item",
|
||||||
@@ -165,16 +164,10 @@ class PluginListPanel extends PluginPanel
|
|||||||
setLayout(new BorderLayout());
|
setLayout(new BorderLayout());
|
||||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||||
|
|
||||||
JButton externalPluginOPRSButton = new JButton("OpenOSRS Hub");
|
|
||||||
externalPluginOPRSButton.setBorder(new EmptyBorder(5, 5, 5, 5));
|
|
||||||
externalPluginOPRSButton.setLayout(new BorderLayout(0, BORDER_OFFSET));
|
|
||||||
externalPluginOPRSButton.addActionListener(l -> muxer.pushState(pluginHubPanelProvider.get()));
|
|
||||||
|
|
||||||
JPanel topPanel = new JPanel();
|
JPanel topPanel = new JPanel();
|
||||||
topPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
topPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||||
topPanel.setLayout(new BorderLayout(0, BORDER_OFFSET));
|
topPanel.setLayout(new BorderLayout(0, BORDER_OFFSET));
|
||||||
topPanel.add(searchBar, BorderLayout.CENTER);
|
topPanel.add(searchBar, BorderLayout.CENTER);
|
||||||
topPanel.add(externalPluginOPRSButton, BorderLayout.SOUTH);
|
|
||||||
add(topPanel, BorderLayout.NORTH);
|
add(topPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
mainPanel = new FixedWidthPanel();
|
mainPanel = new FixedWidthPanel();
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package net.runelite.client.plugins.devtools;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.runelite.api.CollisionDataFlag;
|
import net.runelite.api.CollisionDataFlag;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ import net.runelite.api.events.ScriptPostFired;
|
|||||||
import net.runelite.api.events.ScriptPreFired;
|
import net.runelite.api.events.ScriptPreFired;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
|
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.EventBus;
|
import net.runelite.client.eventbus.EventBus;
|
||||||
@@ -120,7 +120,7 @@ public class ScriptInspector extends JFrame
|
|||||||
if (source != null)
|
if (source != null)
|
||||||
{
|
{
|
||||||
int id = source.getId();
|
int id = source.getId();
|
||||||
output += " - " + TO_GROUP(id) + "." + getChildFromID(id);
|
output += " - " + TO_GROUP(id) + "." + TO_CHILD(id);
|
||||||
|
|
||||||
if (source.getIndex() != -1)
|
if (source.getIndex() != -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ import net.runelite.api.Client;
|
|||||||
import net.runelite.api.MenuAction;
|
import net.runelite.api.MenuAction;
|
||||||
import net.runelite.api.MenuEntry;
|
import net.runelite.api.MenuEntry;
|
||||||
import net.runelite.api.SpriteID;
|
import net.runelite.api.SpriteID;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
|
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||||
import net.runelite.client.events.ConfigChanged;
|
import net.runelite.client.events.ConfigChanged;
|
||||||
import net.runelite.api.events.MenuEntryAdded;
|
import net.runelite.api.events.MenuEntryAdded;
|
||||||
@@ -464,7 +464,7 @@ class WidgetInspector extends JFrame
|
|||||||
|
|
||||||
picker = parent.createChild(-1, WidgetType.GRAPHIC);
|
picker = parent.createChild(-1, WidgetType.GRAPHIC);
|
||||||
|
|
||||||
log.info("Picker is {}.{} [{}]", WidgetInfo.TO_GROUP(picker.getId()), WidgetInfo.getChildFromID(picker.getId()), picker.getIndex());
|
log.info("Picker is {}.{} [{}]", WidgetInfo.TO_GROUP(picker.getId()), WidgetInfo.TO_CHILD(picker.getId()), picker.getIndex());
|
||||||
|
|
||||||
picker.setSpriteId(SpriteID.MOBILE_FINGER_ON_INTERFACE);
|
picker.setSpriteId(SpriteID.MOBILE_FINGER_ON_INTERFACE);
|
||||||
picker.setOriginalWidth(15);
|
picker.setOriginalWidth(15);
|
||||||
@@ -538,7 +538,7 @@ class WidgetInspector extends JFrame
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String name = WidgetInfo.TO_GROUP(entry.getParam1()) + "." + WidgetInfo.getChildFromID(entry.getParam1());
|
String name = WidgetInfo.TO_GROUP(entry.getParam1()) + "." + WidgetInfo.TO_CHILD(entry.getParam1());
|
||||||
|
|
||||||
if (entry.getParam0() != -1)
|
if (entry.getParam0() != -1)
|
||||||
{
|
{
|
||||||
@@ -584,7 +584,7 @@ class WidgetInspector extends JFrame
|
|||||||
public static String getWidgetIdentifier(Widget widget)
|
public static String getWidgetIdentifier(Widget widget)
|
||||||
{
|
{
|
||||||
int id = widget.getId();
|
int id = widget.getId();
|
||||||
String str = TO_GROUP(id) + "." + getChildFromID(id);
|
String str = TO_GROUP(id) + "." + TO_CHILD(id);
|
||||||
|
|
||||||
if (widget.getIndex() != -1)
|
if (widget.getIndex() != -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import javax.inject.Singleton;
|
|||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.MenuEntry;
|
import net.runelite.api.MenuEntry;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.api.widgets.WidgetItem;
|
import net.runelite.api.widgets.WidgetItem;
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||||
@@ -61,6 +62,7 @@ public class WidgetInspectorOverlay extends Overlay
|
|||||||
setPosition(OverlayPosition.DYNAMIC);
|
setPosition(OverlayPosition.DYNAMIC);
|
||||||
setLayer(OverlayLayer.ABOVE_WIDGETS);
|
setLayer(OverlayLayer.ABOVE_WIDGETS);
|
||||||
setPriority(OverlayPriority.HIGHEST);
|
setPriority(OverlayPriority.HIGHEST);
|
||||||
|
drawAfterInterface(WidgetID.FULLSCREEN_MAP_GROUP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import net.runelite.api.Point;
|
|||||||
import net.runelite.api.RenderOverview;
|
import net.runelite.api.RenderOverview;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||||
@@ -56,7 +57,8 @@ public class WorldMapLocationOverlay extends Overlay
|
|||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
setPosition(OverlayPosition.DYNAMIC);
|
setPosition(OverlayPosition.DYNAMIC);
|
||||||
setPriority(OverlayPriority.HIGHEST);
|
setPriority(OverlayPriority.HIGHEST);
|
||||||
setLayer(OverlayLayer.ABOVE_MAP);
|
setLayer(OverlayLayer.MANUAL);
|
||||||
|
drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import net.runelite.api.Client;
|
|||||||
import net.runelite.api.Point;
|
import net.runelite.api.Point;
|
||||||
import net.runelite.api.RenderOverview;
|
import net.runelite.api.RenderOverview;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||||
@@ -56,7 +57,8 @@ class WorldMapRegionOverlay extends Overlay
|
|||||||
{
|
{
|
||||||
setPosition(OverlayPosition.DYNAMIC);
|
setPosition(OverlayPosition.DYNAMIC);
|
||||||
setPriority(OverlayPriority.HIGH);
|
setPriority(OverlayPriority.HIGH);
|
||||||
setLayer(OverlayLayer.ABOVE_MAP);
|
setLayer(OverlayLayer.MANUAL);
|
||||||
|
drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID);
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import net.runelite.api.widgets.Widget;
|
|||||||
import net.runelite.api.widgets.WidgetID;
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.SEED_VAULT_ITEM_CONTAINER;
|
import static net.runelite.api.widgets.WidgetInfo.SEED_VAULT_ITEM_CONTAINER;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
|
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||||
import net.runelite.api.widgets.WidgetItem;
|
import net.runelite.api.widgets.WidgetItem;
|
||||||
import net.runelite.client.chat.ChatColorType;
|
import net.runelite.client.chat.ChatColorType;
|
||||||
@@ -124,7 +124,7 @@ public class ExaminePlugin extends Plugin
|
|||||||
|
|
||||||
int widgetId = event.getWidgetId();
|
int widgetId = event.getWidgetId();
|
||||||
int widgetGroup = TO_GROUP(widgetId);
|
int widgetGroup = TO_GROUP(widgetId);
|
||||||
int widgetChild = getChildFromID(widgetId);
|
int widgetChild = TO_CHILD(widgetId);
|
||||||
Widget widget = client.getWidget(widgetGroup, widgetChild);
|
Widget widget = client.getWidget(widgetGroup, widgetChild);
|
||||||
WidgetItem widgetItem = widget.getWidgetItem(event.getActionParam());
|
WidgetItem widgetItem = widget.getWidgetItem(event.getActionParam());
|
||||||
quantity = widgetItem != null && widgetItem.getId() >= 0 ? widgetItem.getQuantity() : 1;
|
quantity = widgetItem != null && widgetItem.getId() >= 0 ? widgetItem.getQuantity() : 1;
|
||||||
@@ -267,7 +267,7 @@ public class ExaminePlugin extends Plugin
|
|||||||
private int[] findItemFromWidget(int widgetId, int actionParam)
|
private int[] findItemFromWidget(int widgetId, int actionParam)
|
||||||
{
|
{
|
||||||
int widgetGroup = TO_GROUP(widgetId);
|
int widgetGroup = TO_GROUP(widgetId);
|
||||||
int widgetChild = getChildFromID(widgetId);
|
int widgetChild = TO_CHILD(widgetId);
|
||||||
Widget widget = client.getWidget(widgetGroup, widgetChild);
|
Widget widget = client.getWidget(widgetGroup, widgetChild);
|
||||||
|
|
||||||
if (widget == null)
|
if (widget == null)
|
||||||
|
|||||||
@@ -563,7 +563,7 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
{
|
{
|
||||||
case WidgetID.BANK_GROUP_ID:
|
case WidgetID.BANK_GROUP_ID:
|
||||||
// Don't show for view tabs and such
|
// Don't show for view tabs and such
|
||||||
if (WidgetInfo.getChildFromID(widgetId) != WidgetInfo.BANK_ITEM_CONTAINER.getChildId())
|
if (WidgetInfo.TO_CHILD(widgetId) != WidgetInfo.BANK_ITEM_CONTAINER.getChildId())
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
final FontMetrics fm = graphics.getFontMetrics();
|
final FontMetrics fm = graphics.getFontMetrics();
|
||||||
final Player player = client.getLocalPlayer();
|
final Player player = client.getLocalPlayer();
|
||||||
|
|
||||||
if (player == null || client.getViewportWidget() == null)
|
if (player == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Devin French <https://github.com/devinfrench>
|
||||||
|
* 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.idlenotifier;
|
||||||
|
|
||||||
|
import net.runelite.client.config.Config;
|
||||||
|
import net.runelite.client.config.ConfigGroup;
|
||||||
|
import net.runelite.client.config.ConfigItem;
|
||||||
|
import net.runelite.client.config.Units;
|
||||||
|
|
||||||
|
@ConfigGroup("idlenotifier")
|
||||||
|
public interface IdleNotifierConfig extends Config
|
||||||
|
{
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "animationidle",
|
||||||
|
name = "Idle Animation Notifications",
|
||||||
|
description = "Configures if idle animation notifications are enabled",
|
||||||
|
position = 1
|
||||||
|
)
|
||||||
|
default boolean animationIdle()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "interactionidle",
|
||||||
|
name = "Idle Interaction Notifications",
|
||||||
|
description = "Configures if idle interaction notifications are enabled e.g. combat, fishing",
|
||||||
|
position = 2
|
||||||
|
)
|
||||||
|
default boolean interactionIdle()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "movementidle",
|
||||||
|
name = "Idle Movement Notifications",
|
||||||
|
description = "Configures if idle movement notifications are enabled e.g. running, walking",
|
||||||
|
position = 3
|
||||||
|
)
|
||||||
|
default boolean movementIdle()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "logoutidle",
|
||||||
|
name = "Idle Logout Notifications",
|
||||||
|
description = "Configures if the idle logout notifications are enabled",
|
||||||
|
position = 4
|
||||||
|
)
|
||||||
|
default boolean logoutIdle()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "timeout",
|
||||||
|
name = "Idle Notification Delay",
|
||||||
|
description = "The notification delay after the player is idle",
|
||||||
|
position = 5
|
||||||
|
)
|
||||||
|
@Units(Units.MILLISECONDS)
|
||||||
|
default int getIdleNotificationDelay()
|
||||||
|
{
|
||||||
|
return 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "hitpoints",
|
||||||
|
name = "Hitpoints Notification Threshold",
|
||||||
|
description = "The amount of hitpoints to send a notification at. A value of 0 will disable notification.",
|
||||||
|
position = 6
|
||||||
|
)
|
||||||
|
default int getHitpointsThreshold()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "prayer",
|
||||||
|
name = "Prayer Notification Threshold",
|
||||||
|
description = "The amount of prayer points to send a notification at. A value of 0 will disable notification.",
|
||||||
|
position = 7
|
||||||
|
)
|
||||||
|
default int getPrayerThreshold()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "oxygen",
|
||||||
|
name = "Oxygen Notification Threshold",
|
||||||
|
position = 8,
|
||||||
|
description = "The amount of remaining oxygen to send a notification at. A value of 0 will disable notification."
|
||||||
|
)
|
||||||
|
@Units(Units.PERCENT)
|
||||||
|
default int getOxygenThreshold()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "spec",
|
||||||
|
name = "Special Attack Energy Notification Threshold",
|
||||||
|
position = 9,
|
||||||
|
description = "The amount of spec energy reached to send a notification at. A value of 0 will disable notification."
|
||||||
|
)
|
||||||
|
@Units(Units.PERCENT)
|
||||||
|
default int getSpecEnergyThreshold()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,746 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2017, Abel Briggs
|
||||||
|
* Copyright (c) 2017, Kronos <https://github.com/KronosDesign>
|
||||||
|
* 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.idlenotifier;
|
||||||
|
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import net.runelite.api.Actor;
|
||||||
|
import static net.runelite.api.AnimationID.*;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.Constants;
|
||||||
|
import net.runelite.api.GameState;
|
||||||
|
import net.runelite.api.GraphicID;
|
||||||
|
import net.runelite.api.Hitsplat;
|
||||||
|
import net.runelite.api.NPC;
|
||||||
|
import net.runelite.api.NPCComposition;
|
||||||
|
import net.runelite.api.Player;
|
||||||
|
import net.runelite.api.Skill;
|
||||||
|
import net.runelite.api.VarPlayer;
|
||||||
|
import net.runelite.api.Varbits;
|
||||||
|
import net.runelite.api.coords.WorldPoint;
|
||||||
|
import net.runelite.api.events.AnimationChanged;
|
||||||
|
import net.runelite.api.events.GameStateChanged;
|
||||||
|
import net.runelite.api.events.GameTick;
|
||||||
|
import net.runelite.api.events.GraphicChanged;
|
||||||
|
import net.runelite.api.events.HitsplatApplied;
|
||||||
|
import net.runelite.api.events.InteractingChanged;
|
||||||
|
import net.runelite.client.Notifier;
|
||||||
|
import net.runelite.client.config.ConfigManager;
|
||||||
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
|
import net.runelite.client.plugins.Plugin;
|
||||||
|
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"}
|
||||||
|
)
|
||||||
|
public class IdleNotifierPlugin extends Plugin
|
||||||
|
{
|
||||||
|
// This must be more than 500 client ticks (10 seconds) before you get AFK kicked
|
||||||
|
private static final int LOGOUT_WARNING_MILLIS = (4 * 60 + 40) * 1000; // 4 minutes and 40 seconds
|
||||||
|
private static final int COMBAT_WARNING_MILLIS = 19 * 60 * 1000; // 19 minutes
|
||||||
|
private static final int LOGOUT_WARNING_CLIENT_TICKS = LOGOUT_WARNING_MILLIS / Constants.CLIENT_TICK_LENGTH;
|
||||||
|
private static final int COMBAT_WARNING_CLIENT_TICKS = COMBAT_WARNING_MILLIS / Constants.CLIENT_TICK_LENGTH;
|
||||||
|
|
||||||
|
private static final int HIGHEST_MONSTER_ATTACK_SPEED = 8; // Except Scarab Mage, but they are with other monsters
|
||||||
|
private static final Duration SIX_HOUR_LOGOUT_WARNING_AFTER_DURATION = Duration.ofMinutes(340);
|
||||||
|
|
||||||
|
private static final String FISHING_SPOT = "Fishing spot";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Notifier notifier;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private IdleNotifierConfig config;
|
||||||
|
|
||||||
|
private Instant lastAnimating;
|
||||||
|
private int lastAnimation = IDLE;
|
||||||
|
private Instant lastInteracting;
|
||||||
|
private Actor lastInteract;
|
||||||
|
private Instant lastMoving;
|
||||||
|
private WorldPoint lastPosition;
|
||||||
|
private boolean notifyPosition = false;
|
||||||
|
private boolean notifyHitpoints = true;
|
||||||
|
private boolean notifyPrayer = true;
|
||||||
|
private boolean notifyOxygen = true;
|
||||||
|
private boolean notifyIdleLogout = true;
|
||||||
|
private boolean notify6HourLogout = true;
|
||||||
|
private int lastSpecEnergy = 1000;
|
||||||
|
private int lastCombatCountdown = 0;
|
||||||
|
private Instant sixHourWarningTime;
|
||||||
|
private boolean ready;
|
||||||
|
private boolean lastInteractWasCombat;
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
IdleNotifierConfig provideConfig(ConfigManager configManager)
|
||||||
|
{
|
||||||
|
return configManager.getConfig(IdleNotifierConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onAnimationChanged(AnimationChanged event)
|
||||||
|
{
|
||||||
|
if (client.getGameState() != GameState.LOGGED_IN)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player localPlayer = client.getLocalPlayer();
|
||||||
|
if (localPlayer != event.getActor())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int graphic = localPlayer.getGraphic();
|
||||||
|
int animation = localPlayer.getAnimation();
|
||||||
|
switch (animation)
|
||||||
|
{
|
||||||
|
/* Woodcutting */
|
||||||
|
case WOODCUTTING_BRONZE:
|
||||||
|
case WOODCUTTING_IRON:
|
||||||
|
case WOODCUTTING_STEEL:
|
||||||
|
case WOODCUTTING_BLACK:
|
||||||
|
case WOODCUTTING_MITHRIL:
|
||||||
|
case WOODCUTTING_ADAMANT:
|
||||||
|
case WOODCUTTING_RUNE:
|
||||||
|
case WOODCUTTING_GILDED:
|
||||||
|
case WOODCUTTING_DRAGON:
|
||||||
|
case WOODCUTTING_INFERNAL:
|
||||||
|
case WOODCUTTING_3A_AXE:
|
||||||
|
case WOODCUTTING_CRYSTAL:
|
||||||
|
case WOODCUTTING_TRAILBLAZER:
|
||||||
|
/* Cooking(Fire, Range) */
|
||||||
|
case COOKING_FIRE:
|
||||||
|
case COOKING_RANGE:
|
||||||
|
case COOKING_WINE:
|
||||||
|
/* Crafting(Gem Cutting, Glassblowing, Spinning, Battlestaves, Pottery) */
|
||||||
|
case GEM_CUTTING_OPAL:
|
||||||
|
case GEM_CUTTING_JADE:
|
||||||
|
case GEM_CUTTING_REDTOPAZ:
|
||||||
|
case GEM_CUTTING_SAPPHIRE:
|
||||||
|
case GEM_CUTTING_EMERALD:
|
||||||
|
case GEM_CUTTING_RUBY:
|
||||||
|
case GEM_CUTTING_DIAMOND:
|
||||||
|
case GEM_CUTTING_AMETHYST:
|
||||||
|
case CRAFTING_GLASSBLOWING:
|
||||||
|
case CRAFTING_SPINNING:
|
||||||
|
case CRAFTING_BATTLESTAVES:
|
||||||
|
case CRAFTING_LEATHER:
|
||||||
|
case CRAFTING_POTTERS_WHEEL:
|
||||||
|
case CRAFTING_POTTERY_OVEN:
|
||||||
|
/* Fletching(Cutting, Stringing, Adding feathers and heads) */
|
||||||
|
case FLETCHING_BOW_CUTTING:
|
||||||
|
case FLETCHING_STRING_NORMAL_SHORTBOW:
|
||||||
|
case FLETCHING_STRING_OAK_SHORTBOW:
|
||||||
|
case FLETCHING_STRING_WILLOW_SHORTBOW:
|
||||||
|
case FLETCHING_STRING_MAPLE_SHORTBOW:
|
||||||
|
case FLETCHING_STRING_YEW_SHORTBOW:
|
||||||
|
case FLETCHING_STRING_MAGIC_SHORTBOW:
|
||||||
|
case FLETCHING_STRING_NORMAL_LONGBOW:
|
||||||
|
case FLETCHING_STRING_OAK_LONGBOW:
|
||||||
|
case FLETCHING_STRING_WILLOW_LONGBOW:
|
||||||
|
case FLETCHING_STRING_MAPLE_LONGBOW:
|
||||||
|
case FLETCHING_STRING_YEW_LONGBOW:
|
||||||
|
case FLETCHING_STRING_MAGIC_LONGBOW:
|
||||||
|
case FLETCHING_ATTACH_FEATHERS_TO_ARROWSHAFT:
|
||||||
|
case FLETCHING_ATTACH_HEADS:
|
||||||
|
case FLETCHING_ATTACH_BOLT_TIPS_TO_BRONZE_BOLT:
|
||||||
|
case FLETCHING_ATTACH_BOLT_TIPS_TO_IRON_BROAD_BOLT:
|
||||||
|
case FLETCHING_ATTACH_BOLT_TIPS_TO_BLURITE_BOLT:
|
||||||
|
case FLETCHING_ATTACH_BOLT_TIPS_TO_STEEL_BOLT:
|
||||||
|
case FLETCHING_ATTACH_BOLT_TIPS_TO_MITHRIL_BOLT:
|
||||||
|
case FLETCHING_ATTACH_BOLT_TIPS_TO_ADAMANT_BOLT:
|
||||||
|
case FLETCHING_ATTACH_BOLT_TIPS_TO_RUNE_BOLT:
|
||||||
|
case FLETCHING_ATTACH_BOLT_TIPS_TO_DRAGON_BOLT:
|
||||||
|
/* Smithing(Anvil, Furnace, Cannonballs */
|
||||||
|
case SMITHING_ANVIL:
|
||||||
|
case SMITHING_SMELTING:
|
||||||
|
case SMITHING_CANNONBALL:
|
||||||
|
/* Fishing */
|
||||||
|
case FISHING_CRUSHING_INFERNAL_EELS:
|
||||||
|
case FISHING_CUTTING_SACRED_EELS:
|
||||||
|
case FISHING_BIG_NET:
|
||||||
|
case FISHING_NET:
|
||||||
|
case FISHING_POLE_CAST:
|
||||||
|
case FISHING_CAGE:
|
||||||
|
case FISHING_HARPOON:
|
||||||
|
case FISHING_BARBTAIL_HARPOON:
|
||||||
|
case FISHING_DRAGON_HARPOON:
|
||||||
|
case FISHING_INFERNAL_HARPOON:
|
||||||
|
case FISHING_CRYSTAL_HARPOON:
|
||||||
|
case FISHING_TRAILBLAZER_HARPOON:
|
||||||
|
case FISHING_TRAILBLAZER_HARPOON_2:
|
||||||
|
case FISHING_OILY_ROD:
|
||||||
|
case FISHING_KARAMBWAN:
|
||||||
|
case FISHING_BAREHAND:
|
||||||
|
case FISHING_PEARL_ROD:
|
||||||
|
case FISHING_PEARL_FLY_ROD:
|
||||||
|
case FISHING_PEARL_BARBARIAN_ROD:
|
||||||
|
case FISHING_PEARL_ROD_2:
|
||||||
|
case FISHING_PEARL_FLY_ROD_2:
|
||||||
|
case FISHING_PEARL_BARBARIAN_ROD_2:
|
||||||
|
case FISHING_PEARL_OILY_ROD:
|
||||||
|
/* Mining(Normal) */
|
||||||
|
case MINING_BRONZE_PICKAXE:
|
||||||
|
case MINING_IRON_PICKAXE:
|
||||||
|
case MINING_STEEL_PICKAXE:
|
||||||
|
case MINING_BLACK_PICKAXE:
|
||||||
|
case MINING_MITHRIL_PICKAXE:
|
||||||
|
case MINING_ADAMANT_PICKAXE:
|
||||||
|
case MINING_RUNE_PICKAXE:
|
||||||
|
case MINING_GILDED_PICKAXE:
|
||||||
|
case MINING_DRAGON_PICKAXE:
|
||||||
|
case MINING_DRAGON_PICKAXE_UPGRADED:
|
||||||
|
case MINING_DRAGON_PICKAXE_OR:
|
||||||
|
case MINING_INFERNAL_PICKAXE:
|
||||||
|
case MINING_3A_PICKAXE:
|
||||||
|
case MINING_CRYSTAL_PICKAXE:
|
||||||
|
case MINING_TRAILBLAZER_PICKAXE:
|
||||||
|
case MINING_TRAILBLAZER_PICKAXE_2:
|
||||||
|
case MINING_TRAILBLAZER_PICKAXE_3:
|
||||||
|
case DENSE_ESSENCE_CHIPPING:
|
||||||
|
case DENSE_ESSENCE_CHISELING:
|
||||||
|
/* Mining(Motherlode) */
|
||||||
|
case MINING_MOTHERLODE_BRONZE:
|
||||||
|
case MINING_MOTHERLODE_IRON:
|
||||||
|
case MINING_MOTHERLODE_STEEL:
|
||||||
|
case MINING_MOTHERLODE_BLACK:
|
||||||
|
case MINING_MOTHERLODE_MITHRIL:
|
||||||
|
case MINING_MOTHERLODE_ADAMANT:
|
||||||
|
case MINING_MOTHERLODE_RUNE:
|
||||||
|
case MINING_MOTHERLODE_GILDED:
|
||||||
|
case MINING_MOTHERLODE_DRAGON:
|
||||||
|
case MINING_MOTHERLODE_DRAGON_UPGRADED:
|
||||||
|
case MINING_MOTHERLODE_DRAGON_OR:
|
||||||
|
case MINING_MOTHERLODE_INFERNAL:
|
||||||
|
case MINING_MOTHERLODE_3A:
|
||||||
|
case MINING_MOTHERLODE_CRYSTAL:
|
||||||
|
case MINING_MOTHERLODE_TRAILBLAZER:
|
||||||
|
/* Herblore */
|
||||||
|
case HERBLORE_PESTLE_AND_MORTAR:
|
||||||
|
case HERBLORE_POTIONMAKING:
|
||||||
|
case HERBLORE_MAKE_TAR:
|
||||||
|
/* Magic */
|
||||||
|
case MAGIC_CHARGING_ORBS:
|
||||||
|
case MAGIC_LUNAR_PLANK_MAKE:
|
||||||
|
case MAGIC_LUNAR_STRING_JEWELRY:
|
||||||
|
case MAGIC_MAKE_TABLET:
|
||||||
|
case MAGIC_ENCHANTING_JEWELRY:
|
||||||
|
case MAGIC_ENCHANTING_AMULET_1:
|
||||||
|
case MAGIC_ENCHANTING_AMULET_2:
|
||||||
|
case MAGIC_ENCHANTING_AMULET_3:
|
||||||
|
case MAGIC_ENCHANTING_BOLTS:
|
||||||
|
/* Prayer */
|
||||||
|
case USING_GILDED_ALTAR:
|
||||||
|
/* Farming */
|
||||||
|
case FARMING_MIX_ULTRACOMPOST:
|
||||||
|
case FARMING_HARVEST_BUSH:
|
||||||
|
case FARMING_HARVEST_HERB:
|
||||||
|
case FARMING_HARVEST_FRUIT_TREE:
|
||||||
|
case FARMING_HARVEST_FLOWER:
|
||||||
|
case FARMING_HARVEST_ALLOTMENT:
|
||||||
|
/* Misc */
|
||||||
|
case PISCARILIUS_CRANE_REPAIR:
|
||||||
|
case HOME_MAKE_TABLET:
|
||||||
|
case SAND_COLLECTION:
|
||||||
|
resetTimers();
|
||||||
|
lastAnimation = animation;
|
||||||
|
lastAnimating = Instant.now();
|
||||||
|
break;
|
||||||
|
case MAGIC_LUNAR_SHARED:
|
||||||
|
if (graphic == GraphicID.BAKE_PIE)
|
||||||
|
{
|
||||||
|
resetTimers();
|
||||||
|
lastAnimation = animation;
|
||||||
|
lastAnimating = Instant.now();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IDLE:
|
||||||
|
lastAnimating = Instant.now();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// On unknown animation simply assume the animation is invalid and dont throw notification
|
||||||
|
lastAnimation = IDLE;
|
||||||
|
lastAnimating = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onInteractingChanged(InteractingChanged event)
|
||||||
|
{
|
||||||
|
final Actor source = event.getSource();
|
||||||
|
if (source != client.getLocalPlayer())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Actor target = event.getTarget();
|
||||||
|
|
||||||
|
// Reset last interact
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
lastInteract = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastInteracting = Instant.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean isNpc = target instanceof NPC;
|
||||||
|
|
||||||
|
// If this is not NPC, do not process as we are not interested in other entities
|
||||||
|
if (!isNpc)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final NPC npc = (NPC) target;
|
||||||
|
final NPCComposition npcComposition = npc.getComposition();
|
||||||
|
final List<String> npcMenuActions = Arrays.asList(npcComposition.getActions());
|
||||||
|
|
||||||
|
if (npcMenuActions.contains("Attack"))
|
||||||
|
{
|
||||||
|
// Player is most likely in combat with attack-able NPC
|
||||||
|
resetTimers();
|
||||||
|
lastInteract = target;
|
||||||
|
lastInteracting = Instant.now();
|
||||||
|
lastInteractWasCombat = true;
|
||||||
|
}
|
||||||
|
else if (target.getName() != null && target.getName().contains(FISHING_SPOT))
|
||||||
|
{
|
||||||
|
// Player is fishing
|
||||||
|
resetTimers();
|
||||||
|
lastInteract = target;
|
||||||
|
lastInteracting = Instant.now();
|
||||||
|
lastInteractWasCombat = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||||
|
{
|
||||||
|
lastInteracting = null;
|
||||||
|
|
||||||
|
GameState state = gameStateChanged.getGameState();
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case LOGIN_SCREEN:
|
||||||
|
resetTimers();
|
||||||
|
break;
|
||||||
|
case LOGGING_IN:
|
||||||
|
case HOPPING:
|
||||||
|
case CONNECTION_LOST:
|
||||||
|
ready = true;
|
||||||
|
break;
|
||||||
|
case LOGGED_IN:
|
||||||
|
if (ready)
|
||||||
|
{
|
||||||
|
sixHourWarningTime = Instant.now().plus(SIX_HOUR_LOGOUT_WARNING_AFTER_DURATION);
|
||||||
|
ready = false;
|
||||||
|
resetTimers();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onHitsplatApplied(HitsplatApplied event)
|
||||||
|
{
|
||||||
|
if (event.getActor() != client.getLocalPlayer())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Hitsplat hitsplat = event.getHitsplat();
|
||||||
|
|
||||||
|
if (hitsplat.getHitsplatType() == Hitsplat.HitsplatType.DAMAGE_ME
|
||||||
|
|| hitsplat.getHitsplatType() == Hitsplat.HitsplatType.BLOCK_ME)
|
||||||
|
{
|
||||||
|
lastCombatCountdown = HIGHEST_MONSTER_ATTACK_SPEED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onGraphicChanged(GraphicChanged event)
|
||||||
|
{
|
||||||
|
Actor actor = event.getActor();
|
||||||
|
|
||||||
|
if (actor != client.getLocalPlayer())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.getGraphic() == GraphicID.SPLASH)
|
||||||
|
{
|
||||||
|
lastCombatCountdown = HIGHEST_MONSTER_ATTACK_SPEED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onGameTick(GameTick event)
|
||||||
|
{
|
||||||
|
final Player local = client.getLocalPlayer();
|
||||||
|
final Duration waitDuration = Duration.ofMillis(config.getIdleNotificationDelay());
|
||||||
|
lastCombatCountdown = Math.max(lastCombatCountdown - 1, 0);
|
||||||
|
|
||||||
|
if (client.getGameState() != GameState.LOGGED_IN
|
||||||
|
|| local == null
|
||||||
|
// If user has clicked in the last second then they're not idle so don't send idle notification
|
||||||
|
|| System.currentTimeMillis() - client.getMouseLastPressedMillis() < 1000
|
||||||
|
|| client.getKeyboardIdleTicks() < 10)
|
||||||
|
{
|
||||||
|
resetTimers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.logoutIdle() && checkIdleLogout())
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] is about to log out from idling too long!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check6hrLogout())
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] is about to log out from being online for 6 hours!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.animationIdle() && checkAnimationIdle(waitDuration, local))
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] is now idle!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.movementIdle() && checkMovementIdle(waitDuration, local))
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] has stopped moving!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.interactionIdle() && checkInteractionIdle(waitDuration, local))
|
||||||
|
{
|
||||||
|
if (lastInteractWasCombat)
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] is now out of combat!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] is now idle!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkLowHitpoints())
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] has low hitpoints!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkLowPrayer())
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] has low prayer!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkLowOxygen())
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] has low oxygen!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkFullSpecEnergy())
|
||||||
|
{
|
||||||
|
notifier.notify("[" + local.getName() + "] has restored spec energy!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkFullSpecEnergy()
|
||||||
|
{
|
||||||
|
int currentSpecEnergy = client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT);
|
||||||
|
|
||||||
|
int threshold = config.getSpecEnergyThreshold() * 10;
|
||||||
|
if (threshold == 0)
|
||||||
|
{
|
||||||
|
lastSpecEnergy = currentSpecEnergy;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have regenerated over the threshold, and that the
|
||||||
|
// regen was small enough.
|
||||||
|
boolean notify = lastSpecEnergy < threshold && currentSpecEnergy >= threshold
|
||||||
|
&& currentSpecEnergy - lastSpecEnergy <= 100;
|
||||||
|
lastSpecEnergy = currentSpecEnergy;
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkLowOxygen()
|
||||||
|
{
|
||||||
|
if (config.getOxygenThreshold() == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (config.getOxygenThreshold() >= client.getVar(Varbits.OXYGEN_LEVEL) * 0.1)
|
||||||
|
{
|
||||||
|
if (!notifyOxygen)
|
||||||
|
{
|
||||||
|
notifyOxygen = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notifyOxygen = false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkLowHitpoints()
|
||||||
|
{
|
||||||
|
if (config.getHitpointsThreshold() == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (client.getRealSkillLevel(Skill.HITPOINTS) > config.getHitpointsThreshold())
|
||||||
|
{
|
||||||
|
if (client.getBoostedSkillLevel(Skill.HITPOINTS) + client.getVar(Varbits.NMZ_ABSORPTION) <= config.getHitpointsThreshold())
|
||||||
|
{
|
||||||
|
if (!notifyHitpoints)
|
||||||
|
{
|
||||||
|
notifyHitpoints = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notifyHitpoints = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkLowPrayer()
|
||||||
|
{
|
||||||
|
if (config.getPrayerThreshold() == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (client.getRealSkillLevel(Skill.PRAYER) > config.getPrayerThreshold())
|
||||||
|
{
|
||||||
|
if (client.getBoostedSkillLevel(Skill.PRAYER) <= config.getPrayerThreshold())
|
||||||
|
{
|
||||||
|
if (!notifyPrayer)
|
||||||
|
{
|
||||||
|
notifyPrayer = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notifyPrayer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkInteractionIdle(Duration waitDuration, Player local)
|
||||||
|
{
|
||||||
|
if (lastInteract == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Actor interact = local.getInteracting();
|
||||||
|
|
||||||
|
if (interact == null)
|
||||||
|
{
|
||||||
|
if (lastInteracting != null
|
||||||
|
&& Instant.now().compareTo(lastInteracting.plus(waitDuration)) >= 0
|
||||||
|
&& lastCombatCountdown == 0)
|
||||||
|
{
|
||||||
|
lastInteract = null;
|
||||||
|
lastInteracting = null;
|
||||||
|
|
||||||
|
// prevent animation notifications from firing too
|
||||||
|
lastAnimation = IDLE;
|
||||||
|
lastAnimating = null;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastInteracting = Instant.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkIdleLogout()
|
||||||
|
{
|
||||||
|
// Check clientside AFK first, because this is required for the server to disconnect you for being first
|
||||||
|
int idleClientTicks = client.getKeyboardIdleTicks();
|
||||||
|
if (client.getMouseIdleTicks() < idleClientTicks)
|
||||||
|
{
|
||||||
|
idleClientTicks = client.getMouseIdleTicks();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idleClientTicks < LOGOUT_WARNING_CLIENT_TICKS)
|
||||||
|
{
|
||||||
|
notifyIdleLogout = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are not receiving hitsplats then we can be afk kicked
|
||||||
|
if (lastCombatCountdown <= 0)
|
||||||
|
{
|
||||||
|
boolean warn = notifyIdleLogout;
|
||||||
|
notifyIdleLogout = false;
|
||||||
|
return warn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are in combat, so now we have to check for the timer that knocks you out of combat
|
||||||
|
// I think there are other conditions that I don't know about, because during testing I just didn't
|
||||||
|
// get removed from combat sometimes.
|
||||||
|
final long lastInteractionAgo = System.currentTimeMillis() - client.getMouseLastPressedMillis();
|
||||||
|
if (lastInteractionAgo < COMBAT_WARNING_MILLIS || client.getKeyboardIdleTicks() < COMBAT_WARNING_CLIENT_TICKS)
|
||||||
|
{
|
||||||
|
notifyIdleLogout = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean warn = notifyIdleLogout;
|
||||||
|
notifyIdleLogout = false;
|
||||||
|
return warn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean check6hrLogout()
|
||||||
|
{
|
||||||
|
if (sixHourWarningTime == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Instant.now().compareTo(sixHourWarningTime) >= 0)
|
||||||
|
{
|
||||||
|
if (notify6HourLogout)
|
||||||
|
{
|
||||||
|
notify6HourLogout = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notify6HourLogout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkAnimationIdle(Duration waitDuration, Player local)
|
||||||
|
{
|
||||||
|
if (lastAnimation == IDLE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int animation = local.getAnimation();
|
||||||
|
|
||||||
|
if (animation == IDLE)
|
||||||
|
{
|
||||||
|
if (lastAnimating != null && Instant.now().compareTo(lastAnimating.plus(waitDuration)) >= 0)
|
||||||
|
{
|
||||||
|
lastAnimation = IDLE;
|
||||||
|
lastAnimating = null;
|
||||||
|
|
||||||
|
// prevent interaction notifications from firing too
|
||||||
|
lastInteract = null;
|
||||||
|
lastInteracting = null;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastAnimating = Instant.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkMovementIdle(Duration waitDuration, Player local)
|
||||||
|
{
|
||||||
|
if (lastPosition == null)
|
||||||
|
{
|
||||||
|
lastPosition = local.getWorldLocation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldPoint position = local.getWorldLocation();
|
||||||
|
|
||||||
|
if (lastPosition.equals(position))
|
||||||
|
{
|
||||||
|
if (notifyPosition
|
||||||
|
&& local.getAnimation() == IDLE
|
||||||
|
&& Instant.now().compareTo(lastMoving.plus(waitDuration)) >= 0)
|
||||||
|
{
|
||||||
|
notifyPosition = false;
|
||||||
|
// Return true only if we weren't just breaking out of an animation
|
||||||
|
return lastAnimation == IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notifyPosition = true;
|
||||||
|
lastPosition = position;
|
||||||
|
lastMoving = Instant.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetTimers()
|
||||||
|
{
|
||||||
|
final Player local = client.getLocalPlayer();
|
||||||
|
|
||||||
|
// Reset animation idle timer
|
||||||
|
lastAnimating = null;
|
||||||
|
if (client.getGameState() == GameState.LOGIN_SCREEN || local == null || local.getAnimation() != lastAnimation)
|
||||||
|
{
|
||||||
|
lastAnimation = IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset interaction idle timer
|
||||||
|
lastInteracting = null;
|
||||||
|
if (client.getGameState() == GameState.LOGIN_SCREEN || local == null || local.getInteracting() != lastInteract)
|
||||||
|
{
|
||||||
|
lastInteract = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,7 +51,7 @@ public class InventoryTagsOverlay extends WidgetItemOverlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
|
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
|
||||||
{
|
{
|
||||||
final String group = plugin.getTag(itemId);
|
final String group = plugin.getTag(itemId);
|
||||||
if (group != null)
|
if (group != null)
|
||||||
@@ -60,10 +60,10 @@ public class InventoryTagsOverlay extends WidgetItemOverlay
|
|||||||
final DisplayMode displayMode = config.getDisplayMode();
|
final DisplayMode displayMode = config.getDisplayMode();
|
||||||
if (color != null)
|
if (color != null)
|
||||||
{
|
{
|
||||||
Rectangle bounds = itemWidget.getCanvasBounds();
|
Rectangle bounds = widgetItem.getCanvasBounds();
|
||||||
if (displayMode == DisplayMode.OUTLINE)
|
if (displayMode == DisplayMode.OUTLINE)
|
||||||
{
|
{
|
||||||
final BufferedImage outline = itemManager.getItemOutline(itemId, itemWidget.getQuantity(), color);
|
final BufferedImage outline = itemManager.getItemOutline(itemId, widgetItem.getQuantity(), color);
|
||||||
graphics.drawImage(outline, (int) bounds.getX(), (int) bounds.getY(), null);
|
graphics.drawImage(outline, (int) bounds.getX(), (int) bounds.getY(), null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class ItemChargeOverlay extends WidgetItemOverlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
|
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
|
||||||
{
|
{
|
||||||
if (!displayOverlay())
|
if (!displayOverlay())
|
||||||
{
|
{
|
||||||
@@ -153,7 +153,7 @@ class ItemChargeOverlay extends WidgetItemOverlay
|
|||||||
charges = chargeItem.getCharges();
|
charges = chargeItem.getCharges();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Rectangle bounds = itemWidget.getCanvasBounds();
|
final Rectangle bounds = widgetItem.getCanvasBounds();
|
||||||
final TextComponent textComponent = new TextComponent();
|
final TextComponent textComponent = new TextComponent();
|
||||||
textComponent.setPosition(new Point(bounds.x - 1, bounds.y + 15));
|
textComponent.setPosition(new Point(bounds.x - 1, bounds.y + 15));
|
||||||
textComponent.setText(charges < 0 ? "?" : String.valueOf(charges));
|
textComponent.setText(charges < 0 ? "?" : String.valueOf(charges));
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class ItemIdentificationOverlay extends WidgetItemOverlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
|
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
|
||||||
{
|
{
|
||||||
ItemIdentification iden = findItemIdentification(itemId);
|
ItemIdentification iden = findItemIdentification(itemId);
|
||||||
if (iden == null)
|
if (iden == null)
|
||||||
@@ -116,7 +116,7 @@ class ItemIdentificationOverlay extends WidgetItemOverlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
graphics.setFont(FontManager.getRunescapeSmallFont());
|
graphics.setFont(FontManager.getRunescapeSmallFont());
|
||||||
renderText(graphics, itemWidget.getCanvasBounds(), iden);
|
renderText(graphics, widgetItem.getCanvasBounds(), iden);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderText(Graphics2D graphics, Rectangle bounds, ItemIdentification iden)
|
private void renderText(Graphics2D graphics, Rectangle bounds, ItemIdentification iden)
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ class ItemPricesOverlay extends Overlay
|
|||||||
}
|
}
|
||||||
else if (id == ItemID.PLATINUM_TOKEN)
|
else if (id == ItemID.PLATINUM_TOKEN)
|
||||||
{
|
{
|
||||||
return QuantityFormatter.formatNumber(qty * 1000) + " gp";
|
return QuantityFormatter.formatNumber(qty * 1000L) + " gp";
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemComposition itemDef = itemManager.getItemComposition(id);
|
ItemComposition itemDef = itemManager.getItemComposition(id);
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public class ItemStatOverlay extends Overlay
|
|||||||
|
|
||||||
final MenuEntry entry = menu[menuSize - 1];
|
final MenuEntry entry = menu[menuSize - 1];
|
||||||
final int group = WidgetInfo.TO_GROUP(entry.getParam1());
|
final int group = WidgetInfo.TO_GROUP(entry.getParam1());
|
||||||
final int child = WidgetInfo.getChildFromID(entry.getParam1());
|
final int child = WidgetInfo.TO_CHILD(entry.getParam1());
|
||||||
final Widget widget = client.getWidget(group, child);
|
final Widget widget = client.getWidget(group, child);
|
||||||
|
|
||||||
if (widget == null
|
if (widget == null
|
||||||
|
|||||||
@@ -28,11 +28,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.Varbits;
|
import net.runelite.api.Varbits;
|
||||||
import net.runelite.client.plugins.itemstats.Effect;
|
import net.runelite.client.plugins.itemstats.*;
|
||||||
import net.runelite.client.plugins.itemstats.Positivity;
|
|
||||||
import net.runelite.client.plugins.itemstats.RangeStatChange;
|
|
||||||
import net.runelite.client.plugins.itemstats.StatChange;
|
|
||||||
import net.runelite.client.plugins.itemstats.StatsChanges;
|
|
||||||
import net.runelite.client.plugins.itemstats.stats.Stat;
|
import net.runelite.client.plugins.itemstats.stats.Stat;
|
||||||
import net.runelite.client.plugins.itemstats.stats.Stats;
|
import net.runelite.client.plugins.itemstats.stats.Stats;
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import javax.inject.Singleton;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
|
|
||||||
import static net.runelite.client.plugins.kourendlibrary.Book.*;
|
import static net.runelite.client.plugins.kourendlibrary.Book.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2018, OpenOSRS <https://github.com/open-osrs>
|
|
||||||
* 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.neverlogout;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import net.runelite.api.Client;
|
|
||||||
import net.runelite.api.events.GameTick;
|
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
|
||||||
import net.runelite.client.plugins.Plugin;
|
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
|
||||||
|
|
||||||
@PluginDescriptor(
|
|
||||||
name = "Never Logout",
|
|
||||||
enabledByDefault = false,
|
|
||||||
description = "Overrides the 5 minute AFK logout timer.",
|
|
||||||
tags = {"openosrs", "never log", "idle", "logout", "log", "never"}
|
|
||||||
)
|
|
||||||
public class NeverLogoutPlugin extends Plugin
|
|
||||||
{
|
|
||||||
@Inject
|
|
||||||
private Client client;
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
private void onGameTick(GameTick gameTick)
|
|
||||||
{
|
|
||||||
if (client.getKeyboardIdleTicks() > 14900)
|
|
||||||
{
|
|
||||||
client.setKeyboardIdleTicks(0);
|
|
||||||
}
|
|
||||||
if (client.getMouseIdleTicks() > 14900)
|
|
||||||
{
|
|
||||||
client.setMouseIdleTicks(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019, GeChallengeM <https://github.com/GeChallengeM>
|
|
||||||
* 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.nextattack;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import net.runelite.api.Actor;
|
|
||||||
import net.runelite.api.NPC;
|
|
||||||
import net.runelite.api.coords.WorldArea;
|
|
||||||
|
|
||||||
@Getter(AccessLevel.PACKAGE)
|
|
||||||
class MemorizedNPC
|
|
||||||
{
|
|
||||||
private NPC npc;
|
|
||||||
private int npcIndex;
|
|
||||||
private String npcName;
|
|
||||||
private int attackSpeed;
|
|
||||||
@Setter(AccessLevel.PACKAGE)
|
|
||||||
private int combatTimerEnd;
|
|
||||||
@Setter(AccessLevel.PACKAGE)
|
|
||||||
private int timeLeft;
|
|
||||||
@Setter(AccessLevel.PACKAGE)
|
|
||||||
private int flinchTimerEnd;
|
|
||||||
@Setter(AccessLevel.PACKAGE)
|
|
||||||
private Status status;
|
|
||||||
@Setter(AccessLevel.PACKAGE)
|
|
||||||
private WorldArea lastnpcarea;
|
|
||||||
@Setter(AccessLevel.PACKAGE)
|
|
||||||
private Actor lastinteracted;
|
|
||||||
|
|
||||||
MemorizedNPC(final NPC npc, final int attackSpeed, final WorldArea worldArea)
|
|
||||||
{
|
|
||||||
this.npc = npc;
|
|
||||||
this.npcIndex = npc.getIndex();
|
|
||||||
this.npcName = npc.getName();
|
|
||||||
this.attackSpeed = attackSpeed;
|
|
||||||
this.combatTimerEnd = -1;
|
|
||||||
this.flinchTimerEnd = -1;
|
|
||||||
this.timeLeft = 0;
|
|
||||||
this.status = Status.OUT_OF_COMBAT;
|
|
||||||
this.lastnpcarea = worldArea;
|
|
||||||
this.lastinteracted = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter(AccessLevel.PACKAGE)
|
|
||||||
@AllArgsConstructor
|
|
||||||
enum Status
|
|
||||||
{
|
|
||||||
FLINCHING("Flinching", Color.GREEN),
|
|
||||||
IN_COMBAT_DELAY("In Combat Delay", Color.ORANGE),
|
|
||||||
IN_COMBAT("In Combat", Color.RED),
|
|
||||||
OUT_OF_COMBAT("Out of Combat", Color.BLUE);
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
private Color color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019, GeChallengeM <https://github.com/GeChallengeM>
|
|
||||||
* 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.nextattack;
|
|
||||||
|
|
||||||
import net.runelite.client.config.Config;
|
|
||||||
import net.runelite.client.config.ConfigGroup;
|
|
||||||
import net.runelite.client.config.ConfigItem;
|
|
||||||
import net.runelite.client.config.ConfigSection;
|
|
||||||
import net.runelite.client.config.Range;
|
|
||||||
|
|
||||||
@ConfigGroup("nextattack")
|
|
||||||
public interface NextAttackConfig extends Config
|
|
||||||
{
|
|
||||||
@ConfigSection(
|
|
||||||
name = "Attack range",
|
|
||||||
description = "",
|
|
||||||
position = 1
|
|
||||||
)
|
|
||||||
String rangeTitle = "Attack range";
|
|
||||||
|
|
||||||
@Range(
|
|
||||||
min = 1
|
|
||||||
)
|
|
||||||
@ConfigItem(
|
|
||||||
keyName = "AttackRange",
|
|
||||||
name = "NPC attack range",
|
|
||||||
description = "The attack range of the NPC.",
|
|
||||||
position = 2,
|
|
||||||
section = rangeTitle
|
|
||||||
)
|
|
||||||
default int getRange()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfigSection(
|
|
||||||
name = "Attack speed",
|
|
||||||
description = "",
|
|
||||||
position = 3
|
|
||||||
)
|
|
||||||
String speedTitle = "Attack speed";
|
|
||||||
|
|
||||||
@ConfigItem(
|
|
||||||
keyName = "CustomAttSpeedEnabled",
|
|
||||||
name = "Use custom speed",
|
|
||||||
description = "Use this if the timer is wrong.",
|
|
||||||
position = 4,
|
|
||||||
section = speedTitle
|
|
||||||
)
|
|
||||||
default boolean isCustomAttSpeed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Range(
|
|
||||||
min = 1
|
|
||||||
)
|
|
||||||
@ConfigItem(
|
|
||||||
keyName = "CustomAttSpeed",
|
|
||||||
name = "Custom NPC att speed",
|
|
||||||
description = "The attack speed of the NPC (amount of ticks between their attacks).",
|
|
||||||
position = 5,
|
|
||||||
section = speedTitle
|
|
||||||
)
|
|
||||||
default int getCustomAttSpeed()
|
|
||||||
{
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2018, GeChallengeM <https://github.com/GeChallengeM>
|
|
||||||
* 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.nextattack;
|
|
||||||
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
import net.runelite.api.Client;
|
|
||||||
import net.runelite.api.Point;
|
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
|
||||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
|
||||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
|
||||||
import net.runelite.client.ui.overlay.OverlayUtil;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class NextAttackOverlay extends Overlay
|
|
||||||
{
|
|
||||||
private final Client client;
|
|
||||||
private final NextAttackPlugin plugin;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
NextAttackOverlay(final Client client, final NextAttackPlugin plugin)
|
|
||||||
{
|
|
||||||
this.client = client;
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPosition(OverlayPosition.DYNAMIC);
|
|
||||||
setLayer(OverlayLayer.ABOVE_SCENE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension render(Graphics2D graphics)
|
|
||||||
{
|
|
||||||
for (MemorizedNPC npc : plugin.getMemorizedNPCs())
|
|
||||||
{
|
|
||||||
if (npc.getNpc().getInteracting() == client.getLocalPlayer() || client.getLocalPlayer().getInteracting() == npc.getNpc())
|
|
||||||
{
|
|
||||||
switch (npc.getStatus())
|
|
||||||
{
|
|
||||||
case FLINCHING:
|
|
||||||
npc.setTimeLeft(Math.max(0, npc.getFlinchTimerEnd() - client.getTickCount()));
|
|
||||||
break;
|
|
||||||
case IN_COMBAT_DELAY:
|
|
||||||
npc.setTimeLeft(Math.max(0, npc.getCombatTimerEnd() - client.getTickCount() - 7));
|
|
||||||
break;
|
|
||||||
case IN_COMBAT:
|
|
||||||
npc.setTimeLeft(Math.max(0, npc.getCombatTimerEnd() - client.getTickCount()));
|
|
||||||
break;
|
|
||||||
case OUT_OF_COMBAT:
|
|
||||||
default:
|
|
||||||
npc.setTimeLeft(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Point textLocation = npc.getNpc().getCanvasTextLocation(graphics, Integer.toString(npc.getTimeLeft()), npc.getNpc().getLogicalHeight() + 40);
|
|
||||||
|
|
||||||
if (textLocation != null)
|
|
||||||
{
|
|
||||||
OverlayUtil.renderTextLocation(graphics, textLocation, Integer.toString(npc.getTimeLeft()), npc.getStatus().getColor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019, GeChallengeM <https://github.com/GeChallengeM>
|
|
||||||
* 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.nextattack;
|
|
||||||
|
|
||||||
import com.google.inject.Provides;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Getter;
|
|
||||||
import net.runelite.api.Client;
|
|
||||||
import net.runelite.api.GameState;
|
|
||||||
import net.runelite.api.GraphicID;
|
|
||||||
import net.runelite.api.Hitsplat;
|
|
||||||
import net.runelite.api.NPC;
|
|
||||||
import net.runelite.api.coords.WorldArea;
|
|
||||||
import net.runelite.api.events.GameStateChanged;
|
|
||||||
import net.runelite.api.events.GameTick;
|
|
||||||
import net.runelite.api.events.GraphicChanged;
|
|
||||||
import net.runelite.api.events.HitsplatApplied;
|
|
||||||
import net.runelite.api.events.NpcDespawned;
|
|
||||||
import net.runelite.api.events.NpcSpawned;
|
|
||||||
import net.runelite.client.config.ConfigManager;
|
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
|
||||||
import net.runelite.client.game.NPCManager;
|
|
||||||
import net.runelite.client.plugins.Plugin;
|
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
|
||||||
import net.runelite.client.ui.overlay.OverlayManager;
|
|
||||||
|
|
||||||
@PluginDescriptor(
|
|
||||||
name = "Next Attack Timer",
|
|
||||||
enabledByDefault = false,
|
|
||||||
description = "Adds a timer on NPC's for their projected next attack",
|
|
||||||
tags = {"openosrs", "flinch", "npc"}
|
|
||||||
)
|
|
||||||
public class NextAttackPlugin extends Plugin
|
|
||||||
{
|
|
||||||
@Inject
|
|
||||||
private Client client;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private OverlayManager overlayManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private NPCManager npcManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private NextAttackConfig config;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private NextAttackOverlay npcStatusOverlay;
|
|
||||||
|
|
||||||
@Getter(AccessLevel.PACKAGE)
|
|
||||||
private final Set<MemorizedNPC> memorizedNPCs = new HashSet<>();
|
|
||||||
|
|
||||||
private WorldArea lastPlayerLocation;
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
NextAttackConfig provideConfig(ConfigManager configManager)
|
|
||||||
{
|
|
||||||
return configManager.getConfig(NextAttackConfig.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void startUp()
|
|
||||||
{
|
|
||||||
overlayManager.add(npcStatusOverlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void shutDown()
|
|
||||||
{
|
|
||||||
overlayManager.remove(npcStatusOverlay);
|
|
||||||
memorizedNPCs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
private void onNpcSpawned(NpcSpawned npcSpawned)
|
|
||||||
{
|
|
||||||
final NPC npc = npcSpawned.getNpc();
|
|
||||||
final String npcName = npc.getName();
|
|
||||||
|
|
||||||
if (npcName == null || !Arrays.asList(npc.getComposition().getActions()).contains("Attack"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int AttackSpeed = npcManager.getAttackSpeed(npc.getId());
|
|
||||||
if (AttackSpeed == 0)
|
|
||||||
{
|
|
||||||
AttackSpeed = 4;
|
|
||||||
}
|
|
||||||
memorizedNPCs.add(new MemorizedNPC(npc, AttackSpeed, npc.getWorldArea()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
private void onNpcDespawned(NpcDespawned npcDespawned)
|
|
||||||
{
|
|
||||||
final NPC npc = npcDespawned.getNpc();
|
|
||||||
memorizedNPCs.removeIf(c -> c.getNpc() == npc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
private void onGameStateChanged(GameStateChanged event)
|
|
||||||
{
|
|
||||||
if (event.getGameState() == GameState.LOGIN_SCREEN ||
|
|
||||||
event.getGameState() == GameState.HOPPING)
|
|
||||||
{
|
|
||||||
memorizedNPCs.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
private void onHitsplatApplied(HitsplatApplied event)
|
|
||||||
{
|
|
||||||
if (event.getActor().getInteracting() != client.getLocalPlayer())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Hitsplat hitsplat = event.getHitsplat();
|
|
||||||
if ((hitsplat.getHitsplatType() == Hitsplat.HitsplatType.DAMAGE_ME || hitsplat.getHitsplatType() == Hitsplat.HitsplatType.BLOCK_ME) && event.getActor() instanceof NPC)
|
|
||||||
{
|
|
||||||
for (MemorizedNPC mn : memorizedNPCs)
|
|
||||||
{
|
|
||||||
if (mn.getNpcIndex() != ((NPC) event.getActor()).getIndex())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (mn.getStatus() == MemorizedNPC.Status.OUT_OF_COMBAT || (mn.getStatus() == MemorizedNPC.Status.IN_COMBAT && mn.getCombatTimerEnd() - client.getTickCount() < 1) || mn.getLastinteracted() == null)
|
|
||||||
{
|
|
||||||
mn.setStatus(MemorizedNPC.Status.FLINCHING);
|
|
||||||
mn.setCombatTimerEnd(-1);
|
|
||||||
if (config.isCustomAttSpeed())
|
|
||||||
{
|
|
||||||
mn.setFlinchTimerEnd(client.getTickCount() + config.getCustomAttSpeed() / 2 + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mn.setFlinchTimerEnd(client.getTickCount() + mn.getAttackSpeed() / 2 + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
private void onGraphicChanged(GraphicChanged event)
|
|
||||||
{
|
|
||||||
if ((event.getActor().getGraphic() == GraphicID.SPLASH) && event.getActor() instanceof NPC)
|
|
||||||
{
|
|
||||||
for (MemorizedNPC mn : memorizedNPCs)
|
|
||||||
{
|
|
||||||
if (mn.getNpcIndex() != ((NPC) event.getActor()).getIndex())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (mn.getStatus() == MemorizedNPC.Status.OUT_OF_COMBAT || (mn.getStatus() == MemorizedNPC.Status.IN_COMBAT && mn.getCombatTimerEnd() - client.getTickCount() < 2) || event.getActor().getInteracting() == null)
|
|
||||||
{
|
|
||||||
mn.setStatus(MemorizedNPC.Status.FLINCHING);
|
|
||||||
mn.setCombatTimerEnd(-1);
|
|
||||||
if (config.isCustomAttSpeed())
|
|
||||||
{
|
|
||||||
mn.setFlinchTimerEnd(client.getTickCount() + config.getCustomAttSpeed() / 2 + 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mn.setFlinchTimerEnd(client.getTickCount() + mn.getAttackSpeed() / 2 + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkStatus()
|
|
||||||
{
|
|
||||||
if (lastPlayerLocation == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (MemorizedNPC npc : memorizedNPCs)
|
|
||||||
{
|
|
||||||
final double CombatTime = npc.getCombatTimerEnd() - client.getTickCount();
|
|
||||||
final double FlinchTime = npc.getFlinchTimerEnd() - client.getTickCount();
|
|
||||||
if (npc.getNpc().getWorldArea() == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (npc.getNpc().getInteracting() == client.getLocalPlayer())
|
|
||||||
{
|
|
||||||
//Checks: will the NPC attack this tick?
|
|
||||||
if (((npc.getNpc().getWorldArea().canMelee(client, lastPlayerLocation) && config.getRange() == 1) //Separate mechanics for meleerange-only NPC's because they have extra collisiondata checks (fences etc.) and can't attack diagonally
|
|
||||||
|| (lastPlayerLocation.hasLineOfSightTo(client, npc.getNpc().getWorldArea()) && npc.getNpc().getWorldArea().distanceTo(lastPlayerLocation) <= config.getRange() && config.getRange() > 1))
|
|
||||||
&& ((npc.getStatus() != MemorizedNPC.Status.FLINCHING && CombatTime < 9) || (npc.getStatus() == MemorizedNPC.Status.FLINCHING && FlinchTime < 2))
|
|
||||||
&& npc.getNpc().getAnimation() != -1 //Failsafe, attacking NPC's always have an animation.
|
|
||||||
&& !(npc.getLastnpcarea().distanceTo(lastPlayerLocation) == 0 && npc.getLastnpcarea() != npc.getNpc().getWorldArea())) //Weird mechanic: NPC's can't attack on the tick they do a random move
|
|
||||||
{
|
|
||||||
npc.setStatus(MemorizedNPC.Status.IN_COMBAT_DELAY);
|
|
||||||
npc.setLastnpcarea(npc.getNpc().getWorldArea());
|
|
||||||
npc.setLastinteracted(npc.getNpc().getInteracting());
|
|
||||||
if (config.isCustomAttSpeed())
|
|
||||||
{
|
|
||||||
npc.setCombatTimerEnd(client.getTickCount() + config.getCustomAttSpeed() + 8);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
npc.setCombatTimerEnd(client.getTickCount() + npc.getAttackSpeed() + 8);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (npc.getStatus())
|
|
||||||
{
|
|
||||||
case IN_COMBAT:
|
|
||||||
if (CombatTime < 2)
|
|
||||||
{
|
|
||||||
npc.setStatus(MemorizedNPC.Status.OUT_OF_COMBAT);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case IN_COMBAT_DELAY:
|
|
||||||
if (CombatTime < 9)
|
|
||||||
{
|
|
||||||
npc.setStatus(MemorizedNPC.Status.IN_COMBAT);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FLINCHING:
|
|
||||||
if (FlinchTime < 2)
|
|
||||||
{
|
|
||||||
npc.setStatus(MemorizedNPC.Status.IN_COMBAT);
|
|
||||||
npc.setCombatTimerEnd(client.getTickCount() + 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
npc.setLastnpcarea(npc.getNpc().getWorldArea());
|
|
||||||
npc.setLastinteracted(npc.getNpc().getInteracting());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
private void onGameTick(GameTick event)
|
|
||||||
{
|
|
||||||
checkStatus();
|
|
||||||
lastPlayerLocation = client.getLocalPlayer().getWorldArea();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -74,7 +74,7 @@ public class RunepouchOverlay extends WidgetItemOverlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
|
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
|
||||||
{
|
{
|
||||||
if (itemId != ItemID.RUNE_POUCH && itemId != ItemID.RUNE_POUCH_L)
|
if (itemId != ItemID.RUNE_POUCH && itemId != ItemID.RUNE_POUCH_L)
|
||||||
{
|
{
|
||||||
@@ -85,7 +85,7 @@ public class RunepouchOverlay extends WidgetItemOverlay
|
|||||||
|
|
||||||
graphics.setFont(FontManager.getRunescapeSmallFont());
|
graphics.setFont(FontManager.getRunescapeSmallFont());
|
||||||
|
|
||||||
Point location = itemWidget.getCanvasLocation();
|
Point location = widgetItem.getCanvasLocation();
|
||||||
StringBuilder tooltipBuilder = new StringBuilder();
|
StringBuilder tooltipBuilder = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0; i < AMOUNT_VARBITS.length; i++)
|
for (int i = 0; i < AMOUNT_VARBITS.length; i++)
|
||||||
@@ -142,7 +142,7 @@ public class RunepouchOverlay extends WidgetItemOverlay
|
|||||||
String tooltip = tooltipBuilder.toString();
|
String tooltip = tooltipBuilder.toString();
|
||||||
|
|
||||||
if (!tooltip.isEmpty()
|
if (!tooltip.isEmpty()
|
||||||
&& itemWidget.getCanvasBounds().contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY())
|
&& widgetItem.getCanvasBounds().contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY())
|
||||||
&& (config.runePouchOverlayMode() == MOUSE_HOVER || config.runePouchOverlayMode() == BOTH))
|
&& (config.runePouchOverlayMode() == MOUSE_HOVER || config.runePouchOverlayMode() == BOTH))
|
||||||
{
|
{
|
||||||
tooltipManager.add(new Tooltip(tooltip));
|
tooltipManager.add(new Tooltip(tooltip));
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class ScreenMarkerCreationOverlay extends Overlay
|
|||||||
{
|
{
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
setPosition(OverlayPosition.DETACHED);
|
setPosition(OverlayPosition.DETACHED);
|
||||||
setLayer(OverlayLayer.ALWAYS_ON_TOP);
|
setLayer(OverlayLayer.ABOVE_WIDGETS);
|
||||||
setPriority(OverlayPriority.HIGH);
|
setPriority(OverlayPriority.HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class ScreenMarkerWidgetHighlightOverlay extends Overlay
|
|||||||
final int childIdx = menuEntry.getParam0();
|
final int childIdx = menuEntry.getParam0();
|
||||||
final int widgetId = menuEntry.getParam1();
|
final int widgetId = menuEntry.getParam1();
|
||||||
final int groupId = WidgetInfo.TO_GROUP(widgetId);
|
final int groupId = WidgetInfo.TO_GROUP(widgetId);
|
||||||
final int componentId = WidgetInfo.getChildFromID(widgetId);
|
final int componentId = WidgetInfo.TO_CHILD(widgetId);
|
||||||
|
|
||||||
final Widget widget = client.getWidget(groupId, componentId);
|
final Widget widget = client.getWidget(groupId, componentId);
|
||||||
if (widget == null)
|
if (widget == null)
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ class SlayerOverlay extends WidgetItemOverlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
|
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
|
||||||
{
|
{
|
||||||
if (!ALL_SLAYER_ITEMS.contains(itemId))
|
if (!ALL_SLAYER_ITEMS.contains(itemId))
|
||||||
{
|
{
|
||||||
@@ -117,7 +117,7 @@ class SlayerOverlay extends WidgetItemOverlay
|
|||||||
|
|
||||||
graphics.setFont(FontManager.getRunescapeSmallFont());
|
graphics.setFont(FontManager.getRunescapeSmallFont());
|
||||||
|
|
||||||
final Rectangle bounds = itemWidget.getCanvasBounds();
|
final Rectangle bounds = widgetItem.getCanvasBounds();
|
||||||
final TextComponent textComponent = new TextComponent();
|
final TextComponent textComponent = new TextComponent();
|
||||||
|
|
||||||
switch (itemId)
|
switch (itemId)
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import net.runelite.api.ChatMessageType;
|
|||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.Constants;
|
import net.runelite.api.Constants;
|
||||||
import net.runelite.api.EquipmentInventorySlot;
|
import net.runelite.api.EquipmentInventorySlot;
|
||||||
import net.runelite.api.GameState;
|
|
||||||
import net.runelite.api.InventoryID;
|
import net.runelite.api.InventoryID;
|
||||||
import net.runelite.api.Item;
|
import net.runelite.api.Item;
|
||||||
import net.runelite.api.ItemContainer;
|
import net.runelite.api.ItemContainer;
|
||||||
@@ -51,7 +50,6 @@ import net.runelite.api.NpcID;
|
|||||||
import net.runelite.api.Player;
|
import net.runelite.api.Player;
|
||||||
import net.runelite.api.VarPlayer;
|
import net.runelite.api.VarPlayer;
|
||||||
import net.runelite.api.Varbits;
|
import net.runelite.api.Varbits;
|
||||||
import net.runelite.api.WorldType;
|
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import net.runelite.api.events.ActorDeath;
|
import net.runelite.api.events.ActorDeath;
|
||||||
import net.runelite.api.events.AnimationChanged;
|
import net.runelite.api.events.AnimationChanged;
|
||||||
@@ -64,10 +62,7 @@ import net.runelite.api.events.MenuOptionClicked;
|
|||||||
import net.runelite.api.events.NpcChanged;
|
import net.runelite.api.events.NpcChanged;
|
||||||
import net.runelite.api.events.NpcDespawned;
|
import net.runelite.api.events.NpcDespawned;
|
||||||
import net.runelite.api.events.VarbitChanged;
|
import net.runelite.api.events.VarbitChanged;
|
||||||
import net.runelite.api.events.WidgetHiddenChanged;
|
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetID;
|
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
|
||||||
import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE;
|
import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE;
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
@@ -135,15 +130,14 @@ public class TimersPlugin extends Plugin
|
|||||||
private boolean wasWearingEndurance;
|
private boolean wasWearingEndurance;
|
||||||
|
|
||||||
private int lastRaidVarb;
|
private int lastRaidVarb;
|
||||||
private int lastWildernessVarb;
|
|
||||||
private int lastVengCooldownVarb;
|
private int lastVengCooldownVarb;
|
||||||
private int lastIsVengeancedVarb;
|
private int lastIsVengeancedVarb;
|
||||||
private int lastPoisonVarp;
|
private int lastPoisonVarp;
|
||||||
|
private int lastPvpVarb;
|
||||||
private int nextPoisonTick;
|
private int nextPoisonTick;
|
||||||
private WorldPoint lastPoint;
|
private WorldPoint lastPoint;
|
||||||
private TeleportWidget lastTeleportClicked;
|
private TeleportWidget lastTeleportClicked;
|
||||||
private int lastAnimation;
|
private int lastAnimation;
|
||||||
private boolean loggedInRace;
|
|
||||||
private boolean widgetHiddenChangedOnPvpWorld;
|
private boolean widgetHiddenChangedOnPvpWorld;
|
||||||
private ElapsedTimer tzhaarTimer;
|
private ElapsedTimer tzhaarTimer;
|
||||||
|
|
||||||
@@ -176,7 +170,6 @@ public class TimersPlugin extends Plugin
|
|||||||
lastPoint = null;
|
lastPoint = null;
|
||||||
lastTeleportClicked = null;
|
lastTeleportClicked = null;
|
||||||
lastAnimation = -1;
|
lastAnimation = -1;
|
||||||
loggedInRace = false;
|
|
||||||
widgetHiddenChangedOnPvpWorld = false;
|
widgetHiddenChangedOnPvpWorld = false;
|
||||||
lastPoisonVarp = 0;
|
lastPoisonVarp = 0;
|
||||||
nextPoisonTick = 0;
|
nextPoisonTick = 0;
|
||||||
@@ -191,6 +184,7 @@ public class TimersPlugin extends Plugin
|
|||||||
int vengCooldownVarb = client.getVar(Varbits.VENGEANCE_COOLDOWN);
|
int vengCooldownVarb = client.getVar(Varbits.VENGEANCE_COOLDOWN);
|
||||||
int isVengeancedVarb = client.getVar(Varbits.VENGEANCE_ACTIVE);
|
int isVengeancedVarb = client.getVar(Varbits.VENGEANCE_ACTIVE);
|
||||||
int poisonVarp = client.getVar(VarPlayer.POISON);
|
int poisonVarp = client.getVar(VarPlayer.POISON);
|
||||||
|
int pvpVarb = client.getVar(Varbits.PVP_SPEC_ORB);
|
||||||
|
|
||||||
if (lastRaidVarb != raidVarb)
|
if (lastRaidVarb != raidVarb)
|
||||||
{
|
{
|
||||||
@@ -227,22 +221,6 @@ public class TimersPlugin extends Plugin
|
|||||||
lastIsVengeancedVarb = isVengeancedVarb;
|
lastIsVengeancedVarb = isVengeancedVarb;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inWilderness = client.getVar(Varbits.IN_WILDERNESS);
|
|
||||||
|
|
||||||
if (lastWildernessVarb != inWilderness
|
|
||||||
&& client.getGameState() == GameState.LOGGED_IN
|
|
||||||
&& !loggedInRace)
|
|
||||||
{
|
|
||||||
if (!WorldType.isPvpWorld(client.getWorldType())
|
|
||||||
&& inWilderness == 0)
|
|
||||||
{
|
|
||||||
log.debug("Left wilderness in non-PVP world, clearing Teleblock timer.");
|
|
||||||
removeGameTimer(TELEBLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastWildernessVarb = inWilderness;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastPoisonVarp != poisonVarp && config.showAntiPoison())
|
if (lastPoisonVarp != poisonVarp && config.showAntiPoison())
|
||||||
{
|
{
|
||||||
final int tickCount = client.getTickCount();
|
final int tickCount = client.getTickCount();
|
||||||
@@ -272,16 +250,16 @@ public class TimersPlugin extends Plugin
|
|||||||
|
|
||||||
lastPoisonVarp = poisonVarp;
|
lastPoisonVarp = poisonVarp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lastPvpVarb != pvpVarb)
|
||||||
|
{
|
||||||
|
if (pvpVarb == 0)
|
||||||
|
{
|
||||||
|
log.debug("Left a PVP zone, clearing teleblock timer");
|
||||||
|
removeGameTimer(TELEBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
lastPvpVarb = pvpVarb;
|
||||||
public void onWidgetHiddenChanged(WidgetHiddenChanged event)
|
|
||||||
{
|
|
||||||
Widget widget = event.getWidget();
|
|
||||||
if (WorldType.isPvpWorld(client.getWorldType())
|
|
||||||
&& WidgetInfo.TO_GROUP(widget.getId()) == WidgetID.PVP_GROUP_ID)
|
|
||||||
{
|
|
||||||
widgetHiddenChangedOnPvpWorld = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,8 +741,6 @@ public class TimersPlugin extends Plugin
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onGameTick(GameTick event)
|
public void onGameTick(GameTick event)
|
||||||
{
|
{
|
||||||
loggedInRace = false;
|
|
||||||
|
|
||||||
Player player = client.getLocalPlayer();
|
Player player = client.getLocalPlayer();
|
||||||
WorldPoint currentWorldPoint = player.getWorldLocation();
|
WorldPoint currentWorldPoint = player.getWorldLocation();
|
||||||
|
|
||||||
@@ -826,9 +802,6 @@ public class TimersPlugin extends Plugin
|
|||||||
removeTzhaarTimer(); // will be readded by the wave message
|
removeTzhaarTimer(); // will be readded by the wave message
|
||||||
removeGameTimer(TELEBLOCK);
|
removeGameTimer(TELEBLOCK);
|
||||||
break;
|
break;
|
||||||
case LOGGED_IN:
|
|
||||||
loggedInRace = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import net.runelite.api.Client;
|
|||||||
import net.runelite.api.Perspective;
|
import net.runelite.api.Perspective;
|
||||||
import net.runelite.api.Point;
|
import net.runelite.api.Point;
|
||||||
import net.runelite.api.coords.LocalPoint;
|
import net.runelite.api.coords.LocalPoint;
|
||||||
import net.runelite.api.widgets.Widget;
|
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||||
@@ -85,8 +84,6 @@ public class TitheFarmPlantOverlay extends Overlay
|
|||||||
@Override
|
@Override
|
||||||
public Dimension render(Graphics2D graphics)
|
public Dimension render(Graphics2D graphics)
|
||||||
{
|
{
|
||||||
final Widget viewport = client.getViewportWidget();
|
|
||||||
|
|
||||||
for (TitheFarmPlant plant : plugin.getPlants())
|
for (TitheFarmPlant plant : plugin.getPlants())
|
||||||
{
|
{
|
||||||
if (plant.getState() == TitheFarmPlantState.DEAD)
|
if (plant.getState() == TitheFarmPlantState.DEAD)
|
||||||
@@ -103,7 +100,7 @@ public class TitheFarmPlantOverlay extends Overlay
|
|||||||
|
|
||||||
final Point canvasLocation = Perspective.localToCanvas(client, localLocation, client.getPlane());
|
final Point canvasLocation = Perspective.localToCanvas(client, localLocation, client.getPlane());
|
||||||
|
|
||||||
if (viewport != null && canvasLocation != null)
|
if (canvasLocation != null)
|
||||||
{
|
{
|
||||||
final ProgressPieComponent progressPieComponent = new ProgressPieComponent();
|
final ProgressPieComponent progressPieComponent = new ProgressPieComponent();
|
||||||
progressPieComponent.setPosition(canvasLocation);
|
progressPieComponent.setPosition(canvasLocation);
|
||||||
|
|||||||
@@ -36,11 +36,12 @@ import net.runelite.api.MenuEntry;
|
|||||||
import net.runelite.api.NPC;
|
import net.runelite.api.NPC;
|
||||||
import net.runelite.api.NPCComposition;
|
import net.runelite.api.NPCComposition;
|
||||||
import net.runelite.api.ObjectComposition;
|
import net.runelite.api.ObjectComposition;
|
||||||
|
import net.runelite.api.ScriptID;
|
||||||
import net.runelite.api.SpriteID;
|
import net.runelite.api.SpriteID;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import net.runelite.api.events.MenuEntryAdded;
|
import net.runelite.api.events.MenuEntryAdded;
|
||||||
import net.runelite.api.events.MenuOptionClicked;
|
import net.runelite.api.events.MenuOptionClicked;
|
||||||
import net.runelite.api.events.WidgetHiddenChanged;
|
import net.runelite.api.events.ScriptPostFired;
|
||||||
import net.runelite.api.events.WidgetLoaded;
|
import net.runelite.api.events.WidgetLoaded;
|
||||||
import net.runelite.api.widgets.JavaScriptCallback;
|
import net.runelite.api.widgets.JavaScriptCallback;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
@@ -198,11 +199,12 @@ public class WikiPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
private void onWidgetHiddenChanged(WidgetHiddenChanged ev)
|
public void onScriptPostFired(ScriptPostFired scriptPostFired)
|
||||||
{
|
{
|
||||||
if (ev.getWidget().getId() == WidgetInfo.MINIMAP_WIKI_BANNER.getId())
|
if (scriptPostFired.getScriptId() == ScriptID.WIKI_ICON_UPDATE)
|
||||||
{
|
{
|
||||||
ev.getWidget().setHidden(true);
|
Widget w = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER);
|
||||||
|
w.setHidden(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ package net.runelite.client.plugins.xptracker;
|
|||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static net.runelite.client.plugins.xptracker.XpInfoBox.TWO_DECIMAL_FORMAT;
|
import static net.runelite.client.plugins.xptracker.XpInfoBox.TWO_DECIMAL_FORMAT;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import javax.annotation.Nullable;
|
|||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity;
|
import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity;
|
||||||
|
|
||||||
@@ -49,6 +50,7 @@ public abstract class Overlay implements LayoutableRenderableEntity
|
|||||||
private OverlayPosition position = OverlayPosition.TOP_LEFT;
|
private OverlayPosition position = OverlayPosition.TOP_LEFT;
|
||||||
private OverlayPriority priority = OverlayPriority.NONE;
|
private OverlayPriority priority = OverlayPriority.NONE;
|
||||||
private OverlayLayer layer = OverlayLayer.UNDER_WIDGETS;
|
private OverlayLayer layer = OverlayLayer.UNDER_WIDGETS;
|
||||||
|
private final List<Integer> drawHooks = new ArrayList<>();
|
||||||
private final List<OverlayMenuEntry> menuEntries = new ArrayList<>();
|
private final List<OverlayMenuEntry> menuEntries = new ArrayList<>();
|
||||||
private boolean resizable;
|
private boolean resizable;
|
||||||
private int minimumSize = 32;
|
private int minimumSize = 32;
|
||||||
@@ -81,6 +83,16 @@ public abstract class Overlay implements LayoutableRenderableEntity
|
|||||||
return this.getClass().getSimpleName();
|
return this.getClass().getSimpleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void drawAfterInterface(int interfaceId)
|
||||||
|
{
|
||||||
|
drawHooks.add(interfaceId << 16 | 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void drawAfterLayer(WidgetInfo layer)
|
||||||
|
{
|
||||||
|
drawHooks.add(layer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
public void onMouseOver()
|
public void onMouseOver()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,12 @@ package net.runelite.client.ui.overlay;
|
|||||||
|
|
||||||
public enum OverlayLayer
|
public enum OverlayLayer
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Overlay is not rendered. Requires using drawAfterInterface() or drawAfterLayer()
|
||||||
|
* to specify when to draw.
|
||||||
|
*/
|
||||||
|
MANUAL,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render right above the scene (that contains actors and the surface)
|
* Render right above the scene (that contains actors and the surface)
|
||||||
*/
|
*/
|
||||||
@@ -45,9 +51,4 @@ public enum OverlayLayer
|
|||||||
* Render overlay above all game elements
|
* Render overlay above all game elements
|
||||||
*/
|
*/
|
||||||
ALWAYS_ON_TOP,
|
ALWAYS_ON_TOP,
|
||||||
|
|
||||||
/**
|
|
||||||
* Render over the map, even when it's fullscreen
|
|
||||||
*/
|
|
||||||
ABOVE_MAP,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,21 +25,24 @@
|
|||||||
package net.runelite.client.ui.overlay;
|
package net.runelite.client.ui.overlay;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import net.runelite.api.MenuAction;
|
import net.runelite.api.MenuAction;
|
||||||
import net.runelite.api.events.MenuOptionClicked;
|
import net.runelite.api.events.MenuOptionClicked;
|
||||||
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.api.widgets.WidgetItem;
|
import net.runelite.api.widgets.WidgetItem;
|
||||||
import net.runelite.client.config.ConfigGroup;
|
import net.runelite.client.config.ConfigGroup;
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
@@ -66,13 +69,8 @@ public class OverlayManager
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final Comparator<Overlay> OVERLAY_COMPARATOR = (a, b) ->
|
static final Comparator<Overlay> OVERLAY_COMPARATOR = (a, b) ->
|
||||||
{
|
{
|
||||||
final OverlayPosition aPos = a.getPreferredPosition() != null
|
final OverlayPosition aPos = MoreObjects.firstNonNull(a.getPreferredPosition(), a.getPosition());
|
||||||
? a.getPreferredPosition()
|
final OverlayPosition bPos = MoreObjects.firstNonNull(b.getPreferredPosition(), b.getPosition());
|
||||||
: a.getPosition();
|
|
||||||
|
|
||||||
final OverlayPosition bPos = b.getPreferredPosition() != null
|
|
||||||
? b.getPreferredPosition()
|
|
||||||
: b.getPosition();
|
|
||||||
|
|
||||||
if (aPos != bPos)
|
if (aPos != bPos)
|
||||||
{
|
{
|
||||||
@@ -84,7 +82,7 @@ public class OverlayManager
|
|||||||
// For dynamic overlays, higher priority means to
|
// For dynamic overlays, higher priority means to
|
||||||
// draw *later* so it is on top.
|
// draw *later* so it is on top.
|
||||||
// For non-dynamic overlays, higher priority means
|
// For non-dynamic overlays, higher priority means
|
||||||
// draw *first* so that they are closer to their
|
// draw *earlier* so that they are closer to their
|
||||||
// defined position.
|
// defined position.
|
||||||
return aPos == OverlayPosition.DYNAMIC
|
return aPos == OverlayPosition.DYNAMIC
|
||||||
? a.getPriority().compareTo(b.getPriority())
|
? a.getPriority().compareTo(b.getPriority())
|
||||||
@@ -98,9 +96,16 @@ public class OverlayManager
|
|||||||
@Getter(AccessLevel.PACKAGE)
|
@Getter(AccessLevel.PACKAGE)
|
||||||
private final List<Overlay> overlays = new ArrayList<>();
|
private final List<Overlay> overlays = new ArrayList<>();
|
||||||
@Getter
|
@Getter
|
||||||
private final List<WidgetItem> itemWidgets = new ArrayList<>();
|
@Setter
|
||||||
|
private Collection<WidgetItem> widgetItems = Collections.emptyList();
|
||||||
|
|
||||||
private final Map<OverlayLayer, List<Overlay>> overlayLayers = new EnumMap<>(OverlayLayer.class);
|
/**
|
||||||
|
* Valid keys are:
|
||||||
|
* OverlayLayer ABOVE_SCENE, UNDER_WIDGETS, and ALWAYS_ON_TOP
|
||||||
|
* A component id that is a layer
|
||||||
|
* An interface id << 16 | 0xffff
|
||||||
|
*/
|
||||||
|
private ArrayListMultimap<Object, Overlay> overlayMap = ArrayListMultimap.create();
|
||||||
|
|
||||||
private final ConfigManager configManager;
|
private final ConfigManager configManager;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
@@ -143,12 +148,12 @@ public class OverlayManager
|
|||||||
|
|
||||||
event.consume();
|
event.consume();
|
||||||
|
|
||||||
Overlay overlay = overlays.get(event.getType());
|
Overlay overlay = overlays.get(event.getId());
|
||||||
if (overlay != null)
|
if (overlay != null)
|
||||||
{
|
{
|
||||||
List<OverlayMenuEntry> menuEntries = overlay.getMenuEntries();
|
List<OverlayMenuEntry> menuEntries = overlay.getMenuEntries();
|
||||||
OverlayMenuEntry overlayMenuEntry = menuEntries.stream()
|
OverlayMenuEntry overlayMenuEntry = menuEntries.stream()
|
||||||
.filter(me -> me.getOption().equals(event.getOption()))
|
.filter(me -> me.getOption().equals(event.getMenuOption()))
|
||||||
.findAny()
|
.findAny()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
if (overlayMenuEntry != null)
|
if (overlayMenuEntry != null)
|
||||||
@@ -164,9 +169,19 @@ public class OverlayManager
|
|||||||
* @param layer the layer
|
* @param layer the layer
|
||||||
* @return An immutable list of all of the overlays on that layer
|
* @return An immutable list of all of the overlays on that layer
|
||||||
*/
|
*/
|
||||||
synchronized List<Overlay> getLayer(OverlayLayer layer)
|
Collection<Overlay> getLayer(OverlayLayer layer)
|
||||||
{
|
{
|
||||||
return overlayLayers.get(layer);
|
return Collections.unmodifiableCollection(overlayMap.get(layer));
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<Overlay> getForInterface(int interfaceId)
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableCollection(overlayMap.get(interfaceId << 16 | 0xffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<Overlay> getForLayer(int layerId)
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableCollection(overlayMap.get(layerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -282,11 +297,7 @@ public class OverlayManager
|
|||||||
|
|
||||||
synchronized void rebuildOverlayLayers()
|
synchronized void rebuildOverlayLayers()
|
||||||
{
|
{
|
||||||
for (OverlayLayer l : OverlayLayer.values())
|
ArrayListMultimap<Object, Overlay> overlayMap = ArrayListMultimap.create();
|
||||||
{
|
|
||||||
overlayLayers.put(l, new ArrayList<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final Overlay overlay : overlays)
|
for (final Overlay overlay : overlays)
|
||||||
{
|
{
|
||||||
OverlayLayer layer = overlay.getLayer();
|
OverlayLayer layer = overlay.getLayer();
|
||||||
@@ -301,14 +312,33 @@ public class OverlayManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
overlayLayers.get(layer).add(overlay);
|
switch (layer)
|
||||||
|
{
|
||||||
|
case ABOVE_SCENE:
|
||||||
|
case UNDER_WIDGETS:
|
||||||
|
case ALWAYS_ON_TOP:
|
||||||
|
overlayMap.put(layer, overlay);
|
||||||
|
break;
|
||||||
|
case ABOVE_WIDGETS:
|
||||||
|
// draw after each of the top level interfaces
|
||||||
|
overlayMap.put(WidgetID.FIXED_VIEWPORT_GROUP_ID << 16 | 0xffff, overlay);
|
||||||
|
overlayMap.put(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID << 16 | 0xffff, overlay);
|
||||||
|
overlayMap.put(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID << 16 | 0xffff, overlay);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
overlayLayers.forEach((layer, value) ->
|
for (int drawHook : overlay.getDrawHooks())
|
||||||
{
|
{
|
||||||
value.sort(OVERLAY_COMPARATOR);
|
overlayMap.put(drawHook, overlay);
|
||||||
overlayLayers.put(layer, Collections.unmodifiableList(value));
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
for (Object key : overlayMap.keys())
|
||||||
|
{
|
||||||
|
overlayMap.get(key).sort(OVERLAY_COMPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.overlayMap = overlayMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadOverlay(final Overlay overlay)
|
private void loadOverlay(final Overlay overlay)
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ import java.awt.Stroke;
|
|||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -48,11 +50,13 @@ import net.runelite.api.Client;
|
|||||||
import net.runelite.api.GameState;
|
import net.runelite.api.GameState;
|
||||||
import net.runelite.api.KeyCode;
|
import net.runelite.api.KeyCode;
|
||||||
import net.runelite.api.MenuEntry;
|
import net.runelite.api.MenuEntry;
|
||||||
|
import net.runelite.api.Varbits;
|
||||||
import net.runelite.api.events.BeforeRender;
|
import net.runelite.api.events.BeforeRender;
|
||||||
import net.runelite.api.events.ClientTick;
|
import net.runelite.api.events.ClientTick;
|
||||||
import net.runelite.api.events.FocusChanged;
|
import net.runelite.api.events.FocusChanged;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
|
import net.runelite.api.widgets.WidgetItem;
|
||||||
import net.runelite.client.config.RuneLiteConfig;
|
import net.runelite.client.config.RuneLiteConfig;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.input.KeyListener;
|
import net.runelite.client.input.KeyListener;
|
||||||
@@ -98,10 +102,9 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
// Overlay state validation
|
// Overlay state validation
|
||||||
private Rectangle viewportBounds;
|
private Rectangle viewportBounds;
|
||||||
private Rectangle chatboxBounds;
|
private Rectangle chatboxBounds;
|
||||||
private int viewportOffset;
|
|
||||||
private boolean chatboxHidden;
|
private boolean chatboxHidden;
|
||||||
private boolean isResizeable;
|
private boolean isResizeable;
|
||||||
private OverlayBounds snapCorners;
|
private OverlayBounds emptySnapCorners, snapCorners;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private OverlayRenderer(
|
private OverlayRenderer(
|
||||||
@@ -167,35 +170,51 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
public void onBeforeRender(BeforeRender event)
|
public void onBeforeRender(BeforeRender event)
|
||||||
{
|
{
|
||||||
menuEntries = null;
|
menuEntries = null;
|
||||||
}
|
|
||||||
|
|
||||||
public void render(Graphics2D graphics, final OverlayLayer layer)
|
if (client.getGameState() == GameState.LOGGED_IN)
|
||||||
{
|
{
|
||||||
if (layer != OverlayLayer.ABOVE_MAP
|
|
||||||
&& client.getWidget(WidgetInfo.FULLSCREEN_MAP_ROOT) != null
|
|
||||||
&& !client.getWidget(WidgetInfo.FULLSCREEN_MAP_ROOT).isHidden())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Overlay> overlays = overlayManager.getLayer(layer);
|
|
||||||
|
|
||||||
if (overlays == null
|
|
||||||
|| overlays.isEmpty()
|
|
||||||
|| client.getGameState() != GameState.LOGGED_IN
|
|
||||||
|| client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN) != null
|
|
||||||
|| client.getViewportWidget() == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldInvalidateBounds())
|
if (shouldInvalidateBounds())
|
||||||
{
|
{
|
||||||
snapCorners = buildSnapCorners();
|
emptySnapCorners = buildSnapCorners();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create copy of snap corners because overlays will modify them
|
// Create copy of snap corners because overlays will modify them
|
||||||
OverlayBounds snapCorners = new OverlayBounds(this.snapCorners);
|
snapCorners = new OverlayBounds(emptySnapCorners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderOverlayLayer(Graphics2D graphics, final OverlayLayer layer)
|
||||||
|
{
|
||||||
|
final Collection<Overlay> overlays = overlayManager.getLayer(layer);
|
||||||
|
renderOverlays(graphics, overlays, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderAfterInterface(Graphics2D graphics, int interfaceId, Collection<WidgetItem> widgetItems)
|
||||||
|
{
|
||||||
|
Collection<Overlay> overlays = overlayManager.getForInterface(interfaceId);
|
||||||
|
overlayManager.setWidgetItems(widgetItems);
|
||||||
|
renderOverlays(graphics, overlays, OverlayLayer.ABOVE_WIDGETS);
|
||||||
|
overlayManager.setWidgetItems(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderAfterLayer(Graphics2D graphics, Widget layer, Collection<WidgetItem> widgetItems)
|
||||||
|
{
|
||||||
|
Collection<Overlay> overlays = overlayManager.getForLayer(layer.getId());
|
||||||
|
overlayManager.setWidgetItems(widgetItems);
|
||||||
|
renderOverlays(graphics, overlays, OverlayLayer.ABOVE_WIDGETS);
|
||||||
|
overlayManager.setWidgetItems(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderOverlays(Graphics2D graphics, Collection<Overlay> overlays, OverlayLayer layer)
|
||||||
|
{
|
||||||
|
if (overlays == null
|
||||||
|
|| overlays.isEmpty()
|
||||||
|
|| client.getGameState() != GameState.LOGGED_IN)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OverlayUtil.setGraphicProperties(graphics);
|
OverlayUtil.setGraphicProperties(graphics);
|
||||||
|
|
||||||
// Draw snap corners
|
// Draw snap corners
|
||||||
@@ -629,7 +648,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
// Check if the overlay is over a snapcorner and move it if so, unless it is a detached overlay
|
// Check if the overlay is over a snapcorner and move it if so, unless it is a detached overlay
|
||||||
if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode)
|
if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode)
|
||||||
{
|
{
|
||||||
final OverlayBounds snapCorners = this.snapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
|
final OverlayBounds snapCorners = this.emptySnapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
|
||||||
|
|
||||||
for (Rectangle snapCorner : snapCorners.getBounds())
|
for (Rectangle snapCorner : snapCorners.getBounds())
|
||||||
{
|
{
|
||||||
@@ -795,43 +814,53 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean viewportChanged = !client.getViewportWidget().getBounds().equals(viewportBounds);
|
Widget viewportWidget = getViewportLayer();
|
||||||
|
Rectangle viewport = viewportWidget != null ? viewportWidget.getBounds() : new Rectangle();
|
||||||
|
final boolean viewportChanged = !viewport.equals(viewportBounds);
|
||||||
|
|
||||||
if (viewportChanged)
|
if (viewportChanged)
|
||||||
{
|
{
|
||||||
viewportBounds = client.getViewportWidget().getBounds();
|
viewportBounds = viewport;
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean viewportOffsetChanged = client.getViewportXOffset() != viewportOffset;
|
|
||||||
|
|
||||||
if (viewportOffsetChanged)
|
|
||||||
{
|
|
||||||
viewportOffset = client.getViewportXOffset();
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Widget getViewportLayer()
|
||||||
|
{
|
||||||
|
if (client.isResized())
|
||||||
|
{
|
||||||
|
if (client.getVar(Varbits.SIDE_PANELS) == 1)
|
||||||
|
{
|
||||||
|
return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client.getWidget(WidgetInfo.FIXED_VIEWPORT);
|
||||||
|
}
|
||||||
|
|
||||||
private OverlayBounds buildSnapCorners()
|
private OverlayBounds buildSnapCorners()
|
||||||
{
|
{
|
||||||
final Point topLeftPoint = new Point(
|
final Point topLeftPoint = new Point(
|
||||||
viewportOffset + BORDER,
|
viewportBounds.x + BORDER,
|
||||||
viewportOffset + BORDER_TOP);
|
viewportBounds.y + BORDER_TOP);
|
||||||
|
|
||||||
final Point topCenterPoint = new Point(
|
final Point topCenterPoint = new Point(
|
||||||
viewportOffset + viewportBounds.width / 2,
|
viewportBounds.x + viewportBounds.width / 2,
|
||||||
viewportOffset + BORDER
|
viewportBounds.y + BORDER
|
||||||
);
|
);
|
||||||
|
|
||||||
final Point topRightPoint = new Point(
|
final Point topRightPoint = new Point(
|
||||||
viewportOffset + viewportBounds.width - BORDER,
|
viewportBounds.x + viewportBounds.width - BORDER,
|
||||||
topCenterPoint.y);
|
topCenterPoint.y);
|
||||||
|
|
||||||
final Point bottomLeftPoint = new Point(
|
final Point bottomLeftPoint = new Point(
|
||||||
topLeftPoint.x,
|
topLeftPoint.x,
|
||||||
viewportOffset + viewportBounds.height - BORDER);
|
viewportBounds.y + viewportBounds.height - BORDER);
|
||||||
|
|
||||||
final Point bottomRightPoint = new Point(
|
final Point bottomRightPoint = new Point(
|
||||||
topRightPoint.x,
|
topRightPoint.x,
|
||||||
@@ -844,7 +873,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Point rightChatboxPoint = isResizeable ? new Point(
|
final Point rightChatboxPoint = isResizeable ? new Point(
|
||||||
viewportOffset + chatboxBounds.width - BORDER,
|
viewportBounds.x + chatboxBounds.width - BORDER,
|
||||||
bottomLeftPoint.y) : bottomRightPoint;
|
bottomLeftPoint.y) : bottomRightPoint;
|
||||||
|
|
||||||
final Point canvasTopRightPoint = isResizeable ? new Point(
|
final Point canvasTopRightPoint = isResizeable ? new Point(
|
||||||
@@ -880,7 +909,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
entry.setOption(overlayMenuEntry.getOption());
|
entry.setOption(overlayMenuEntry.getOption());
|
||||||
entry.setTarget(ColorUtil.wrapWithColorTag(overlayMenuEntry.getTarget(), JagexColors.MENU_TARGET));
|
entry.setTarget(ColorUtil.wrapWithColorTag(overlayMenuEntry.getTarget(), JagexColors.MENU_TARGET));
|
||||||
entry.setType(overlayMenuEntry.getMenuAction().getId());
|
entry.setType(overlayMenuEntry.getMenuAction().getId());
|
||||||
entry.setType(overlayManager.getOverlays().indexOf(overlay)); // overlay id
|
entry.setIdentifier(overlayManager.getOverlays().indexOf(overlay)); // overlay id
|
||||||
|
|
||||||
entries[i] = entry;
|
entries[i] = entry;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,68 +28,49 @@ import java.awt.Dimension;
|
|||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import static net.runelite.api.widgets.WidgetID.BANK_GROUP_ID;
|
|
||||||
import static net.runelite.api.widgets.WidgetID.BANK_INVENTORY_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.BANK_INVENTORY_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.DEPOSIT_BOX_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.DEPOSIT_BOX_GROUP_ID;
|
||||||
|
import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_GROUP_ID;
|
||||||
|
import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_OTHER_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.EQUIPMENT_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.EQUIPMENT_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.EQUIPMENT_INVENTORY_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.EQUIPMENT_INVENTORY_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.GRAND_EXCHANGE_INVENTORY_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.GRAND_EXCHANGE_INVENTORY_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.GUIDE_PRICES_INVENTORY_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.GUIDE_PRICES_INVENTORY_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.INVENTORY_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.INVENTORY_GROUP_ID;
|
||||||
|
import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_INVENTORY_GROUP_ID;
|
||||||
|
import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_SCREEN_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.SEED_VAULT_INVENTORY_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.SEED_VAULT_INVENTORY_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.SHOP_INVENTORY_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.SHOP_INVENTORY_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_GROUP_ID;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_OTHER_GROUP_ID;
|
|
||||||
import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_SCREEN_GROUP_ID;
|
|
||||||
import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_INVENTORY_GROUP_ID;
|
|
||||||
import static net.runelite.api.widgets.WidgetInfo.BANK_CONTENT_CONTAINER;
|
|
||||||
import static net.runelite.api.widgets.WidgetInfo.BANK_TAB_CONTAINER;
|
|
||||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
|
||||||
import net.runelite.api.widgets.WidgetItem;
|
import net.runelite.api.widgets.WidgetItem;
|
||||||
|
|
||||||
public abstract class WidgetItemOverlay extends Overlay
|
public abstract class WidgetItemOverlay extends Overlay
|
||||||
{
|
{
|
||||||
@Setter(AccessLevel.PACKAGE)
|
@Setter(AccessLevel.PACKAGE)
|
||||||
private OverlayManager overlayManager;
|
private OverlayManager overlayManager;
|
||||||
/**
|
|
||||||
* Interfaces to draw overlay over.
|
|
||||||
*/
|
|
||||||
private final Set<Integer> interfaceGroups = new HashSet<>();
|
|
||||||
|
|
||||||
protected WidgetItemOverlay()
|
protected WidgetItemOverlay()
|
||||||
{
|
{
|
||||||
super.setPosition(OverlayPosition.DYNAMIC);
|
super.setPosition(OverlayPosition.DYNAMIC);
|
||||||
super.setPriority(OverlayPriority.LOW);
|
super.setPriority(OverlayPriority.LOW);
|
||||||
super.setLayer(OverlayLayer.ABOVE_WIDGETS);
|
super.setLayer(OverlayLayer.MANUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget);
|
public abstract void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension render(Graphics2D graphics)
|
public Dimension render(Graphics2D graphics)
|
||||||
{
|
{
|
||||||
final List<WidgetItem> itemWidgets = overlayManager.getItemWidgets();
|
final Collection<WidgetItem> widgetItems = overlayManager.getWidgetItems();
|
||||||
final Rectangle originalClipBounds = graphics.getClipBounds();
|
final Rectangle originalClipBounds = graphics.getClipBounds();
|
||||||
Widget curClipParent = null;
|
Widget curClipParent = null;
|
||||||
for (WidgetItem widgetItem : itemWidgets)
|
for (WidgetItem widgetItem : widgetItems)
|
||||||
{
|
{
|
||||||
Widget widget = widgetItem.getWidget();
|
Widget widget = widgetItem.getWidget();
|
||||||
int interfaceGroup = TO_GROUP(widget.getId());
|
|
||||||
|
|
||||||
// Don't draw if this widget isn't one of the allowed nor in tag tab/item tab
|
|
||||||
if (!interfaceGroups.contains(interfaceGroup) ||
|
|
||||||
(interfaceGroup == BANK_GROUP_ID
|
|
||||||
&& (widget.getParentId() == BANK_CONTENT_CONTAINER.getId() || widget.getParentId() == BANK_TAB_CONTAINER.getId())))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget parent = widget.getParent();
|
Widget parent = widget.getParent();
|
||||||
Rectangle parentBounds = parent.getBounds();
|
Rectangle parentBounds = parent.getBounds();
|
||||||
Rectangle itemCanvasBounds = widgetItem.getCanvasBounds();
|
Rectangle itemCanvasBounds = widgetItem.getCanvasBounds();
|
||||||
@@ -151,7 +132,7 @@ public abstract class WidgetItemOverlay extends Overlay
|
|||||||
|
|
||||||
protected void showOnBank()
|
protected void showOnBank()
|
||||||
{
|
{
|
||||||
showOnInterfaces(BANK_GROUP_ID);
|
drawAfterLayer(WidgetInfo.BANK_ITEM_CONTAINER);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void showOnEquipment()
|
protected void showOnEquipment()
|
||||||
@@ -161,7 +142,7 @@ public abstract class WidgetItemOverlay extends Overlay
|
|||||||
|
|
||||||
protected void showOnInterfaces(int... ids)
|
protected void showOnInterfaces(int... ids)
|
||||||
{
|
{
|
||||||
Arrays.stream(ids).forEach(interfaceGroups::add);
|
Arrays.stream(ids).forEach(this::drawAfterInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow setting position, priority, or layer
|
// Don't allow setting position, priority, or layer
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ public class WidgetOverlay extends Overlay
|
|||||||
setPriority(OverlayPriority.HIGHEST);
|
setPriority(OverlayPriority.HIGHEST);
|
||||||
setLayer(OverlayLayer.UNDER_WIDGETS);
|
setLayer(OverlayLayer.UNDER_WIDGETS);
|
||||||
setPosition(overlayPosition);
|
setPosition(overlayPosition);
|
||||||
|
// It's almost possible to drawAfterInterface(widgetInfo.getGroupId()) here, but that fires
|
||||||
|
// *after* the native components are drawn, which is too late.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ public class InfoBoxOverlay extends OverlayPanel
|
|||||||
|
|
||||||
InfoBox infoBox = hoveredComponent.getInfoBox();
|
InfoBox infoBox = hoveredComponent.getInfoBox();
|
||||||
OverlayMenuEntry overlayMenuEntry = infoBox.getMenuEntries().stream()
|
OverlayMenuEntry overlayMenuEntry = infoBox.getMenuEntries().stream()
|
||||||
.filter(me -> me.getOption().equals(menuOptionClicked.getOption()))
|
.filter(me -> me.getOption().equals(menuOptionClicked.getMenuOption()))
|
||||||
.findAny()
|
.findAny()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
if (overlayMenuEntry != null)
|
if (overlayMenuEntry != null)
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import java.util.List;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.client.config.RuneLiteConfig;
|
import net.runelite.client.config.RuneLiteConfig;
|
||||||
import net.runelite.client.config.TooltipPositionType;
|
import net.runelite.client.config.TooltipPositionType;
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
@@ -59,7 +60,9 @@ public class TooltipOverlay extends Overlay
|
|||||||
this.runeLiteConfig = runeLiteConfig;
|
this.runeLiteConfig = runeLiteConfig;
|
||||||
setPosition(OverlayPosition.TOOLTIP);
|
setPosition(OverlayPosition.TOOLTIP);
|
||||||
setPriority(OverlayPriority.HIGHEST);
|
setPriority(OverlayPriority.HIGHEST);
|
||||||
setLayer(OverlayLayer.ALWAYS_ON_TOP);
|
setLayer(OverlayLayer.ABOVE_WIDGETS);
|
||||||
|
// additionally allow tooltips above the world map
|
||||||
|
drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import net.runelite.api.Point;
|
|||||||
import net.runelite.api.RenderOverview;
|
import net.runelite.api.RenderOverview;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import net.runelite.client.input.MouseManager;
|
import net.runelite.client.input.MouseManager;
|
||||||
import net.runelite.client.ui.FontManager;
|
import net.runelite.client.ui.FontManager;
|
||||||
@@ -73,7 +74,8 @@ public class WorldMapOverlay extends Overlay
|
|||||||
this.worldMapPointManager = worldMapPointManager;
|
this.worldMapPointManager = worldMapPointManager;
|
||||||
setPosition(OverlayPosition.DYNAMIC);
|
setPosition(OverlayPosition.DYNAMIC);
|
||||||
setPriority(OverlayPriority.HIGHEST);
|
setPriority(OverlayPriority.HIGHEST);
|
||||||
setLayer(OverlayLayer.ABOVE_MAP);
|
setLayer(OverlayLayer.MANUAL);
|
||||||
|
drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID);
|
||||||
mouseManager.registerMouseListener(worldMapOverlayMouseListener);
|
mouseManager.registerMouseListener(worldMapOverlayMouseListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,10 +65,7 @@ public class ObsidianSkin extends SubstanceSkin
|
|||||||
|
|
||||||
final SubstanceColorSchemeBundle defaultSchemeBundle = new SubstanceColorSchemeBundle(
|
final SubstanceColorSchemeBundle defaultSchemeBundle = new SubstanceColorSchemeBundle(
|
||||||
activeScheme, enabledScheme, enabledScheme);
|
activeScheme, enabledScheme, enabledScheme);
|
||||||
//defaultSchemeBundle.registerColorScheme(enabledScheme, 0.6f,
|
|
||||||
// ComponentState.DISABLED_UNSELECTED);
|
|
||||||
//defaultSchemeBundle.registerColorScheme(activeScheme, 0.6f,
|
|
||||||
// ComponentState.DISABLED_SELECTED);
|
|
||||||
|
|
||||||
// borders
|
// borders
|
||||||
final SubstanceColorScheme borderDisabledSelectedScheme = schemes
|
final SubstanceColorScheme borderDisabledSelectedScheme = schemes
|
||||||
@@ -82,9 +79,7 @@ public class ObsidianSkin extends SubstanceSkin
|
|||||||
final SubstanceColorScheme markActiveScheme = schemes.get("RuneLite Mark Active");
|
final SubstanceColorScheme markActiveScheme = schemes.get("RuneLite Mark Active");
|
||||||
defaultSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK,
|
defaultSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK,
|
||||||
ComponentState.getActiveStates());
|
ComponentState.getActiveStates());
|
||||||
//defaultSchemeBundle.registerColorScheme(markActiveScheme, 0.6f,
|
|
||||||
// ColorSchemeAssociationKind.MARK, ComponentState.DISABLED_SELECTED,
|
|
||||||
// ComponentState.DISABLED_UNSELECTED);
|
|
||||||
|
|
||||||
// separators
|
// separators
|
||||||
final SubstanceColorScheme separatorScheme = schemes.get("RuneLite Separator");
|
final SubstanceColorScheme separatorScheme = schemes.get("RuneLite Separator");
|
||||||
@@ -102,8 +97,7 @@ public class ObsidianSkin extends SubstanceSkin
|
|||||||
|
|
||||||
final SubstanceColorSchemeBundle decorationsSchemeBundle = new SubstanceColorSchemeBundle(
|
final SubstanceColorSchemeBundle decorationsSchemeBundle = new SubstanceColorSchemeBundle(
|
||||||
activeScheme, enabledScheme, enabledScheme);
|
activeScheme, enabledScheme, enabledScheme);
|
||||||
//decorationsSchemeBundle.registerColorScheme(enabledScheme, 0.5f,
|
|
||||||
// ComponentState.DISABLED_UNSELECTED);
|
|
||||||
|
|
||||||
// borders
|
// borders
|
||||||
decorationsSchemeBundle.registerColorScheme(borderDisabledSelectedScheme,
|
decorationsSchemeBundle.registerColorScheme(borderDisabledSelectedScheme,
|
||||||
@@ -129,8 +123,7 @@ public class ObsidianSkin extends SubstanceSkin
|
|||||||
|
|
||||||
final SubstanceColorSchemeBundle headerSchemeBundle = new SubstanceColorSchemeBundle(activeScheme,
|
final SubstanceColorSchemeBundle headerSchemeBundle = new SubstanceColorSchemeBundle(activeScheme,
|
||||||
enabledScheme, enabledScheme);
|
enabledScheme, enabledScheme);
|
||||||
//headerSchemeBundle.registerColorScheme(enabledScheme, 0.5f,
|
|
||||||
// ComponentState.DISABLED_UNSELECTED);
|
|
||||||
|
|
||||||
// borders
|
// borders
|
||||||
final SubstanceColorScheme headerBorderScheme = schemes.get("RuneLite Header Border");
|
final SubstanceColorScheme headerBorderScheme = schemes.get("RuneLite Header Border");
|
||||||
@@ -142,14 +135,6 @@ public class ObsidianSkin extends SubstanceSkin
|
|||||||
headerSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK,
|
headerSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK,
|
||||||
ComponentState.getActiveStates());
|
ComponentState.getActiveStates());
|
||||||
|
|
||||||
//headerSchemeBundle.registerHighlightColorScheme(activeScheme, 0.7f,
|
|
||||||
// ComponentState.ROLLOVER_UNSELECTED, ComponentState.ROLLOVER_ARMED,
|
|
||||||
// ComponentState.ARMED);
|
|
||||||
//headerSchemeBundle.registerHighlightColorScheme(activeScheme, 0.8f,
|
|
||||||
// ComponentState.SELECTED);
|
|
||||||
//headerSchemeBundle.registerHighlightColorScheme(activeScheme, 1.0f,
|
|
||||||
// ComponentState.ROLLOVER_SELECTED);
|
|
||||||
|
|
||||||
final SubstanceColorScheme headerWatermarkScheme = schemes.get("RuneLite Header Watermark");
|
final SubstanceColorScheme headerWatermarkScheme = schemes.get("RuneLite Header Watermark");
|
||||||
|
|
||||||
this.registerDecorationAreaSchemeBundle(headerSchemeBundle, headerWatermarkScheme,
|
this.registerDecorationAreaSchemeBundle(headerSchemeBundle, headerWatermarkScheme,
|
||||||
|
|||||||
@@ -594,7 +594,7 @@ public abstract class RSClientMixin implements RSClient
|
|||||||
@Override
|
@Override
|
||||||
public Widget getWidget(int id)
|
public Widget getWidget(int id)
|
||||||
{
|
{
|
||||||
return getWidget(WidgetInfo.TO_GROUP(id), WidgetInfo.getChildFromID(id));
|
return getWidget(WidgetInfo.TO_GROUP(id), WidgetInfo.TO_CHILD(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -1552,16 +1552,16 @@ public abstract class RSClientMixin implements RSClient
|
|||||||
if (renderX >= minX && renderX <= maxX && renderY >= minY && renderY <= maxY)
|
if (renderX >= minX && renderX <= maxX && renderY >= minY && renderY <= maxY)
|
||||||
{
|
{
|
||||||
WidgetItem widgetItem = new WidgetItem(widget.getItemId(), widget.getItemQuantity(), -1, widget.getBounds(), widget, null);
|
WidgetItem widgetItem = new WidgetItem(widget.getItemId(), widget.getItemQuantity(), -1, widget.getBounds(), widget, null);
|
||||||
callbacks.drawItem(widget.getItemId(), widgetItem);
|
//TODO:IMPLEMENT
|
||||||
|
//callbacks.drawItem(widget.getItemId(), widgetItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (widgetType == WidgetType.INVENTORY)
|
else if (widgetType == WidgetType.INVENTORY)
|
||||||
{
|
{
|
||||||
Collection<WidgetItem> widgetItems = widget.getWidgetItems();
|
|
||||||
for (WidgetItem widgetItem : widgetItems)
|
List<WidgetItem> widgetItems = widget.getWidgetItems();
|
||||||
{
|
//TODO:IMPLEMENT
|
||||||
callbacks.drawItem(widgetItem.getId(), widgetItem);
|
//callbacks.drawLayer(rlWidget, widgetItems);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetNode childNode = componentTable.get(widget.getId());
|
WidgetNode childNode = componentTable.get(widget.getId());
|
||||||
@@ -1579,6 +1579,10 @@ public abstract class RSClientMixin implements RSClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
|
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||||
|
|
||||||
@Mixin(RSWidget.class)
|
@Mixin(RSWidget.class)
|
||||||
@@ -107,7 +107,7 @@ public abstract class RSWidgetMixin implements RSWidget
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.getWidget(TO_GROUP(id), getChildFromID(id));
|
return client.getWidget(TO_GROUP(id), TO_CHILD(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -240,7 +240,7 @@ public abstract class RSWidgetMixin implements RSWidget
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@Override
|
@Override
|
||||||
public Collection<WidgetItem> getWidgetItems()
|
public List<WidgetItem> getWidgetItems()
|
||||||
{
|
{
|
||||||
int[] itemIds = getItemIds();
|
int[] itemIds = getItemIds();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user