diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeInterface.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeInterface.java index b2c4349fa4..3383653de2 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeInterface.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeInterface.java @@ -57,7 +57,8 @@ public class InvokeInterface extends Instruction implements InvokeInstruction super(instructions, type); } - public InvokeInterface(Instructions instructions, Method method) { + public InvokeInterface(Instructions instructions, Method method) + { super(instructions, InstructionType.INVOKEINTERFACE); this.method = method; } diff --git a/openosrs-injector/openosrs-injector.gradle.kts b/openosrs-injector/openosrs-injector.gradle.kts index acb5a73f1e..d4ea924fb9 100644 --- a/openosrs-injector/openosrs-injector.gradle.kts +++ b/openosrs-injector/openosrs-injector.gradle.kts @@ -40,7 +40,7 @@ dependencies { implementation("com.google.guava:guava:29.0-jre") implementation(project(":deobfuscator")) - testCompileOnly("com.openosrs:injection-annotations:1.0") + testCompileOnly(project(":injection-annotations")) testImplementation("junit:junit:4.13") } diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/InjectUtil.java b/openosrs-injector/src/main/java/com/openosrs/injector/InjectUtil.java index b924d035e6..f55539fb34 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/InjectUtil.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/InjectUtil.java @@ -62,11 +62,10 @@ public interface InjectUtil /** * Finds a static method in deob and converts it to ob * - * @param data InjectData instance - * @param name The name of the method you want to find + * @param data InjectData instance + * @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 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 */ static Method findMethod( @@ -81,8 +80,8 @@ public interface InjectUtil /** * Finds a method in injectData's deobfuscated classes. * - * @param data InjectData instance - * @param name (Exported) method name + * @param data InjectData instance + * @param name (Exported) method name * @param classHint The (exported) name of a class you expect (or know) the method to be in, or null, if you're not sure * @throws InjectException If the hint class couldn't be found, or no method matching the settings was found */ @@ -90,7 +89,7 @@ public interface InjectUtil InjectData data, String name, @Nullable String classHint) - throws InjectException + throws InjectException { return findMethod(data, name, classHint, null, false, false); } @@ -98,13 +97,12 @@ public interface InjectUtil /** * Finds a method in injectData's deobfuscated classes. * - * @param data InjectData instance - * @param name (Exported) method name - * @param classHint The (exported) name of a class you expect (or know) the method to be in, or null, if you're not sure - * @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 data InjectData instance + * @param name (Exported) method name + * @param classHint The (exported) name of a class you expect (or know) the method to be in, or null, if you're not sure + * @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 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 */ static Method findMethod( @@ -114,7 +112,7 @@ public interface InjectUtil @Nullable Predicate sig, boolean notStatic, boolean returnDeob) - throws InjectException + throws InjectException { final ClassGroup deob = data.getDeobfuscated(); if (classHint != null) @@ -125,23 +123,41 @@ public interface InjectUtil if (notStatic) { if (sig == null) + { m = InjectUtil.findMethodDeep(cf, name, s -> true); + } else + { m = InjectUtil.findMethodDeep(cf, name, sig); + } } else + { m = cf.findMethod(name); + } if (m != null) + { return returnDeob ? m : data.toVanilla(m); + } } for (ClassFile cf : deob) + { for (Method m : cf.getMethods()) + { if (m.getName().equals(name)) + { if (!notStatic || !m.isStatic()) + { if (sig == null || sig.test(m.getDescriptor())) + { return returnDeob ? m : data.toVanilla(m); + } + } + } + } + } throw new InjectException(String.format("Couldn't find %s", name)); } @@ -150,7 +166,9 @@ public interface InjectUtil { ClassFile clazz = group.findClass(name); if (clazz == null) + { throw new InjectException("Hint class " + name + " doesn't exist"); + } return clazz; } @@ -161,10 +179,18 @@ public interface InjectUtil static Method findMethodDeep(ClassFile clazz, String name, Predicate type) { do + { for (Method method : clazz.getMethods()) + { if (method.getName().equals(name)) + { if (type.test(method.getDescriptor())) + { return method; + } + } + } + } while ((clazz = clazz.getParent()) != null); 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 - * + *

* well... */ static Field findStaticField(ClassGroup group, String name) @@ -181,7 +207,9 @@ public interface InjectUtil { Field f = clazz.findField(name); if (f != null && f.isStatic()) + { return f; + } } throw new InjectException("Couldn't find static field " + name); @@ -190,11 +218,10 @@ public interface InjectUtil /** * Finds a static field in deob and converts it to ob * - * @param data InjectData instance - * @param name The name of the field you want to find + * @param data InjectData instance + * @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 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 */ static Field findStaticField(InjectData data, String name, String classHint, Type type) @@ -207,23 +234,35 @@ public interface InjectUtil ClassFile clazz = findClassOrThrow(deob, classHint); if (type == null) + { field = clazz.findField(name); + } else + { field = clazz.findField(name, type); + } if (field != null) + { return field; + } } for (ClassFile clazz : deob) { if (type == null) + { field = clazz.findField(name); + } else + { field = clazz.findField(name, type); + } if (field != null) + { return field; + } } throw new InjectException(String.format("Static field %s doesn't exist", (type != null ? type + " " : "") + name)); @@ -237,8 +276,12 @@ public interface InjectUtil Field f; do + { if ((f = clazz.findField(name)) != null) + { return f; + } + } while ((clazz = clazz.getParent()) != null); throw new InjectException("Couldn't find field " + name); @@ -259,12 +302,18 @@ public interface InjectUtil field = clazz.findField(name); if (field != null) + { return field; + } } for (ClassFile clazz : group) + { if ((field = clazz.findField(name)) != null) + { return field; + } + } throw new InjectException("Field " + name + " doesn't exist"); } @@ -293,11 +342,15 @@ public interface InjectUtil static Type apiToDeob(InjectData data, Type api) { if (api.isPrimitive()) + { return api; + } final String internalName = api.getInternalName(); if (internalName.startsWith(API_BASE)) + { return Type.getType("L" + api.getInternalName().substring(API_BASE.length()) + ";", api.getDimensions()); + } else if (internalName.startsWith(RL_API_BASE)) { Class rlApiC = new Class(internalName); @@ -332,11 +385,15 @@ public interface InjectUtil static Type deobToVanilla(InjectData data, Type deobT) { if (deobT.isPrimitive()) + { return deobT; + } final ClassFile deobClass = data.getDeobfuscated().findClass(deobT.getInternalName()); if (deobClass == null) + { return deobT; + } return Type.getType("L" + data.toVanilla(deobClass).getName() + ";", deobT.getDimensions()); } @@ -352,18 +409,24 @@ public interface InjectUtil List bb = b.getArguments(); if (aa.size() != bb.size()) + { return false; + } for (int i = 0; i < aa.size(); i++) + { if (!aa.get(i).equals(bb.get(i))) + { return false; + } + } return true; } /** * Gets the obfuscated name from something's annotations. - * + *

* If the annotation doesn't exist return the current name instead. */ static String getObfuscatedName(T from) @@ -387,7 +450,9 @@ public interface InjectUtil static Instruction createLoadForTypeIndex(Instructions instructions, Type type, int index) { if (type.getDimensions() > 0 || !type.isPrimitive()) + { return new ALoad(instructions, index); + } switch (type.toString()) { @@ -414,7 +479,9 @@ public interface InjectUtil static Instruction createReturnForType(Instructions instructions, Type type) { if (!type.isPrimitive()) + { return new Return(instructions, InstructionType.ARETURN); + } switch (type.toString()) { @@ -440,9 +507,13 @@ public interface InjectUtil static Instruction createInvokeFor(Instructions instructions, net.runelite.asm.pool.Method method, boolean isStatic) { if (isStatic) + { return new InvokeStatic(instructions, method); + } else + { return new InvokeVirtual(instructions, method); + } } /** @@ -463,9 +534,13 @@ public interface InjectUtil into.accept(new LDC(instrs, getter)); if (getter instanceof Integer) + { into.accept(new IMul(instrs)); + } else if (getter instanceof Long) + { into.accept(new LMul(instrs)); + } } /** diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/Injection.java b/openosrs-injector/src/main/java/com/openosrs/injector/Injection.java index 307697b1df..9678681ba1 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/Injection.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/Injection.java @@ -67,7 +67,7 @@ public class Injection extends InjectData implements InjectTaskHandler inject(new RSApiInjector(this)); - inject(new DrawAfterWidgets(this)); + //inject(new DrawAfterWidgets(this)); inject(new ScriptVM(this)); @@ -107,7 +107,9 @@ public class Injection extends InjectData implements InjectTaskHandler log.lifecycle("{} {}", name, injector.getCompletionMsg()); if (injector instanceof Validator) + { validate((Validator) injector); + } } private void validate(Validator validator) diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/InjectorValidator.java b/openosrs-injector/src/main/java/com/openosrs/injector/InjectorValidator.java index 4a606a4a22..d97aca000c 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/InjectorValidator.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/InjectorValidator.java @@ -35,7 +35,9 @@ public class InjectorValidator implements Validator for (Class intf : cf.getInterfaces()) { if (!intf.getName().startsWith(API_BASE)) + { continue; + } RSApiClass apiC = rsApi.findClass(intf.getName()); if (apiC == null) @@ -61,7 +63,9 @@ public class InjectorValidator implements Validator for (RSApiMethod apiMethod : apiClass) { if (apiMethod.isSynthetic() || apiMethod.isDefault()) + { continue; + } if (clazz.findMethodDeep(apiMethod.getName(), apiMethod.getSignature()) == null) { diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injection/InjectData.java b/openosrs-injector/src/main/java/com/openosrs/injector/injection/InjectData.java index 8adfb205d3..bac8b3e2f6 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injection/InjectData.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injection/InjectData.java @@ -149,7 +149,7 @@ public abstract class InjectData /** * Do something with all paired classes. - * + *

* Key = deobfuscated, Value = vanilla */ public void forEachPair(BiConsumer action) diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/CreateAnnotations.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/CreateAnnotations.java index bfabccdd20..4bdc647cf3 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/CreateAnnotations.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/CreateAnnotations.java @@ -42,38 +42,40 @@ import net.runelite.deob.DeobAnnotations; public class CreateAnnotations extends AbstractInjector { - public CreateAnnotations(InjectData inject) - { - super(inject); - } + public CreateAnnotations(InjectData inject) + { + super(inject); + } - public void inject() - { - for (final ClassFile deobClass : inject.getDeobfuscated()) - { - injectFields(deobClass); - injectMethods(deobClass); + public void inject() + { + for (final ClassFile deobClass : inject.getDeobfuscated()) + { + injectFields(deobClass); + injectMethods(deobClass); - if (deobClass.getName().startsWith("class")) - continue; + if (deobClass.getName().startsWith("class")) + { + continue; + } - deobClass.addAnnotation(DeobAnnotations.IMPLEMENTS, deobClass.getName()); - } - } + deobClass.addAnnotation(DeobAnnotations.IMPLEMENTS, deobClass.getName()); + } + } - private void injectFields(ClassFile deobClass) - { - for (Field deobField : deobClass.getFields()) - { - deobField.addAnnotation(DeobAnnotations.EXPORT, deobField.getName()); - } - } + private void injectFields(ClassFile deobClass) + { + for (Field deobField : deobClass.getFields()) + { + deobField.addAnnotation(DeobAnnotations.EXPORT, deobField.getName()); + } + } - private void injectMethods(ClassFile deobClass) - { - for (Method deobMethod : deobClass.getMethods()) - { - deobMethod.addAnnotation(DeobAnnotations.EXPORT, deobMethod.getName()); - } - } + private void injectMethods(ClassFile deobClass) + { + for (Method deobMethod : deobClass.getMethods()) + { + deobMethod.addAnnotation(DeobAnnotations.EXPORT, deobMethod.getName()); + } + } } diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectConstruct.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectConstruct.java index ef1b8e7db0..0dde556645 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectConstruct.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectConstruct.java @@ -69,7 +69,9 @@ public class InjectConstruct extends AbstractInjector { Annotation construct = apiMethod.findAnnotation(CONSTRUCT); if (construct == null) + { continue; + } final Method method = apiMethod.getMethod(); final Class clazz = method.getClazz(); @@ -103,7 +105,9 @@ public class InjectConstruct extends AbstractInjector final net.runelite.asm.Method constructor = classToConstruct.findMethod("", constr); if (constructor == null) + { throw new InjectException("Unable to find constructor for " + classToConstruct.getName() + "." + constr); + } net.runelite.asm.Method setterMethod = new net.runelite.asm.Method(targetClass, apiMethod.getName(), apiMethod.getType()); diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectHook.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectHook.java index c2d8cde855..a7e74e848d 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectHook.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectHook.java @@ -86,7 +86,9 @@ public class InjectHook extends AbstractInjector public void inject() { for (Map.Entry, List> entry : mixinTargets.entrySet()) + { injectMethods(entry.getKey(), entry.getValue()); + } injectHooks(); @@ -103,7 +105,9 @@ public class InjectHook extends AbstractInjector { final Annotation fieldHook = mixinMethod.findAnnotation(FIELDHOOK); if (fieldHook == null) + { continue; + } final String hookName = fieldHook.getValueString(); final boolean before = isBefore(fieldHook); @@ -141,7 +145,7 @@ public class InjectHook extends AbstractInjector Set doneIh = new HashSet<>(); e.addExecutionVisitor(( - InstructionContext ic) -> + InstructionContext ic) -> { Instruction i = ic.getInstruction(); Instructions ins = i.getInstructions(); @@ -149,23 +153,33 @@ public class InjectHook extends AbstractInjector Method method = code.getMethod(); if (method.getName().equals(CLINIT)) + { return; + } if (!(i instanceof SetFieldInstruction)) + { return; + } if (!done.add(i)) + { return; + } SetFieldInstruction sfi = (SetFieldInstruction) i; Field fieldBeingSet = sfi.getMyField(); if (fieldBeingSet == null) + { return; + } HookInfo hookInfo = hooked.get(fieldBeingSet); if (hookInfo == null) + { return; + } log.trace("Found injection location for hook {} at instruction {}", hookInfo.method.getName(), sfi); ++injectedHooks; @@ -174,7 +188,9 @@ public class InjectHook extends AbstractInjector StackContext objectStackContext = null; if (sfi instanceof PutField) + { objectStackContext = ic.getPops().get(1); + } int idx = ins.getInstructions().indexOf(sfi); assert idx != -1; @@ -182,10 +198,14 @@ public class InjectHook extends AbstractInjector try { if (hookInfo.before) + { injectCallbackBefore(ins, idx, hookInfo, null, objectStackContext, value); + } else - // idx + 1 to insert after the set + // idx + 1 to insert after the set + { injectCallback(ins, idx + 1, hookInfo, null, objectStackContext); + } } catch (InjectException ex) { @@ -206,23 +226,33 @@ public class InjectHook extends AbstractInjector Method method = code.getMethod(); if (method.getName().equals(CLINIT)) + { return; + } if (!(i instanceof ArrayStore)) + { return; + } if (!doneIh.add(i)) + { return; + } ArrayStore as = (ArrayStore) i; Field fieldBeingSet = as.getMyField(ic); if (fieldBeingSet == null) + { return; + } HookInfo hookInfo = hooked.get(fieldBeingSet); if (hookInfo == null) + { return; + } StackContext value = ic.getPops().get(0); StackContext index = ic.getPops().get(1); @@ -232,7 +262,9 @@ public class InjectHook extends AbstractInjector StackContext objectStackContext = null; if (arrayReferencePushed.getInstruction().getType() == InstructionType.GETFIELD) + { objectStackContext = arrayReferencePushed.getPops().get(0); + } // inject hook after 'i' log.debug("[DEBUG] Found array injection location for hook {} at instruction {}", hookInfo.method.getName(), i); @@ -244,9 +276,13 @@ public class InjectHook extends AbstractInjector try { if (hookInfo.before) + { injectCallbackBefore(ins, idx, hookInfo, index, objectStackContext, value); + } else + { injectCallback(ins, idx + 1, hookInfo, index, objectStackContext); + } } catch (InjectException ex) { @@ -265,7 +301,9 @@ public class InjectHook extends AbstractInjector if (!hookInfo.method.isStatic()) { if (object == null) + { throw new InjectException("null object"); + } ins.getInstructions().add(idx++, new Dup(ins)); // dup value idx = recursivelyPush(ins, idx, object); @@ -313,7 +351,9 @@ public class InjectHook extends AbstractInjector } for (StackContext s : Lists.reverse(ctx.getPops())) + { idx = recursivelyPush(ins, idx, s); + } ins.getInstructions().add(idx++, ctx.getInstruction().clone()); return idx; @@ -324,15 +364,21 @@ public class InjectHook extends AbstractInjector if (!hookInfo.method.isStatic()) { if (objectPusher == null) + { throw new InjectException("Null object pusher"); + } idx = recursivelyPush(ins, idx, objectPusher); } if (index != null) + { idx = recursivelyPush(ins, idx, index); + } else + { ins.getInstructions().add(idx++, new LDC(ins, -1)); + } Instruction invoke = hookInfo.getInvoke(ins); ins.getInstructions().add(idx, invoke); diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectHookMethod.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectHookMethod.java index 1ca49ac707..b4ca566c3d 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectHookMethod.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InjectHookMethod.java @@ -65,7 +65,9 @@ public class InjectHookMethod extends AbstractInjector public void inject() { for (Map.Entry, List> entry : mixinTargets.entrySet()) + { injectMethods(entry.getKey(), entry.getValue()); + } log.info("[INFO] Injected {} method hooks", injected); } @@ -80,10 +82,14 @@ public class InjectHookMethod extends AbstractInjector { final Annotation methodHook = mixinMethod.findAnnotation(METHODHOOK); if (methodHook == null) + { continue; + } if (!mixinMethod.getDescriptor().isVoid()) + { throw new InjectException("Method hook " + mixinMethod.getPoolMethod() + " doesn't have void return type"); + } final String hookName = methodHook.getValueString(); final boolean end = isEnd(methodHook); @@ -116,8 +122,12 @@ public class InjectHookMethod extends AbstractInjector { it = ins.listIterator(ins.size()); while (it.hasPrevious()) + { if (it.previous() instanceof ReturnInstruction) + { insertVoke(method, hookMethod, it); + } + } return; } @@ -126,8 +136,12 @@ public class InjectHookMethod extends AbstractInjector if (method.getName().equals("")) { while (it.hasNext()) + { if (it.next() instanceof InvokeSpecial) + { break; + } + } assert it.hasNext() : "Constructor without invokespecial"; } @@ -141,7 +155,9 @@ public class InjectHookMethod extends AbstractInjector int varIdx = 0; if (!method.isStatic()) + { iterator.add(new ALoad(instructions, varIdx++)); + } for (Type type : hookMethod.getType().getArguments()) { diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InterfaceInjector.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InterfaceInjector.java index e96c0393cd..ea861ad437 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InterfaceInjector.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/InterfaceInjector.java @@ -36,7 +36,9 @@ public class InterfaceInjector extends AbstractInjector final String impls = DeobAnnotations.getImplements(deobCf); if (impls == null) + { return; + } final String fullName = API_BASE + impls; if (!inject.getRsApi().hasClass(fullName)) diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/MixinInjector.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/MixinInjector.java index 502d09f67d..467a200ab3 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/MixinInjector.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/MixinInjector.java @@ -179,13 +179,19 @@ public class MixinInjector extends AbstractInjector copy.setValue(field.getValue()); for (Map.Entry e : field.getAnnotations().entrySet()) + { if (!e.getKey().toString().startsWith("Lnet/runelite/api/mixins")) + { copy.addAnnotation(e.getValue()); + } + } targetClass.addField(copy); if (injectedFields.containsKey(field.getName()) && !ASSERTION_FIELD.equals(field.getName())) + { throw new InjectException("Duplicate field: " + field.getName()); + } injectedFields.put(field.getName(), copy); } @@ -207,10 +213,14 @@ public class MixinInjector extends AbstractInjector Annotation shadow = field.findAnnotation(SHADOW); if (shadow == null) + { continue; + } if (!field.isStatic()) + { throw new InjectException("Shadowed fields must be static"); + } String shadowed = shadow.getValueString(); @@ -226,7 +236,9 @@ public class MixinInjector extends AbstractInjector } if ((targetField.getAccessFlags() & Opcodes.ACC_PRIVATE) != 0) + { throw new InjectException("Shadowed fields can't be private"); + } shadowFields.put( field.getPoolField(), @@ -249,7 +261,9 @@ public class MixinInjector extends AbstractInjector { Annotation copyA = mixinMethod.findAnnotation(COPY); if (copyA == null) + { continue; + } String copiedName = copyA.getValueString(); 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); if (mixinMethod.isStatic() != deobSourceMethod.isStatic()) + { throw new InjectException("Mixin method " + mixinMethod + " should be " + (deobSourceMethod.isStatic() ? "static" : "non-static")); + } // The actual method we're copying, including code etc Method sourceMethod = inject.toVanilla(deobSourceMethod); if (mixinMethod.getDescriptor().size() > sourceMethod.getDescriptor().size()) + { throw new InjectException("Mixin methods cannot have more parameters than their corresponding ob method"); + } Method copy = new Method(targetClass, "copy$" + copiedName, sourceMethod.getDescriptor()); moveCode(copy, sourceMethod.getCode()); @@ -272,7 +290,9 @@ public class MixinInjector extends AbstractInjector copy.setPublic(); copy.getExceptions().getExceptions().addAll(sourceMethod.getExceptions().getExceptions()); for (var a : sourceMethod.getAnnotations().values()) + { copy.addAnnotation(a); + } targetClass.addMethod(copy); ++copied; @@ -280,7 +300,7 @@ public class MixinInjector extends AbstractInjector * If the desc for the mixin method and the desc for the ob method * are the same in length, assume that the mixin method is taking * care of the garbage parameter itself. - */ + */ boolean hasGarbageValue = mixinMethod.getDescriptor().size() != sourceMethod.getDescriptor().size() && deobSourceMethod.getDescriptor().size() < copy.getDescriptor().size(); @@ -298,7 +318,9 @@ public class MixinInjector extends AbstractInjector if ((hasInject && isInit) || isClinit) { if (!"()V".equals(mixinMethod.getDescriptor().toString())) + { throw new InjectException("Injected constructors cannot have arguments"); + } Method[] originalMethods = targetClass.getMethods().stream() .filter(m -> m.getName().equals(mixinMethod.getName())) @@ -309,11 +331,15 @@ public class MixinInjector extends AbstractInjector // If there isn't a already just inject ours, otherwise rename it // This is always true for if (originalMethods.length > 0) + { name = "rl$$" + (isInit ? "init" : "clinit"); + } String numberlessName = name; for (int i = 1; targetClass.findMethod(name, mixinMethod.getDescriptor()) != null; i++) + { name = numberlessName + i; + } Method copy = new Method(targetClass, name, mixinMethod.getDescriptor()); moveCode(copy, mixinMethod.getCode()); @@ -337,7 +363,9 @@ public class MixinInjector extends AbstractInjector int pops = invoke.getMethod().getType().getArguments().size() + 1; for (int i = 0; i < pops; i++) + { listIter.add(new Pop(instructions)); + } break; } @@ -503,11 +531,15 @@ public class MixinInjector extends AbstractInjector // Update instructions for each instruction for (Instruction i : newCode.getInstructions()) + { i.setInstructions(newCode.getInstructions()); + } newCode.getExceptions().getExceptions().addAll(sourceCode.getExceptions().getExceptions()); for (net.runelite.asm.attributes.code.Exception e : newCode.getExceptions().getExceptions()) + { e.setExceptions(newCode.getExceptions()); + } targetMethod.setCode(newCode); } @@ -598,7 +630,9 @@ public class MixinInjector extends AbstractInjector PushConstantInstruction pi = (PushConstantInstruction) i; if (mixinCf.getPoolClass().equals(pi.getConstant())) + { pi.setConstant(cf.getPoolClass()); + } } verify(mixinCf, i); @@ -614,11 +648,15 @@ public class MixinInjector extends AbstractInjector if (fi.getField().getClazz().getName().equals(mixinCf.getName())) { if (i instanceof PutField || i instanceof GetField) + { throw new InjectException("Access to non static member field of mixin"); + } Field field = fi.getMyField(); if (field != null && !field.isPublic()) + { throw new InjectException("Static access to non public field " + field); + } } } else if (i instanceof InvokeStatic) @@ -627,12 +665,16 @@ public class MixinInjector extends AbstractInjector if (is.getMethod().getClazz() != mixinCf.getPoolClass() && is.getMethod().getClazz().getName().startsWith(MIXIN_BASE)) + { throw new InjectException("Invoking static methods of other mixins is not supported"); + } } else if (i instanceof InvokeDynamic) - // RS classes don't verify under java 7+ due to the - // super() invokespecial being inside of a try{} + // RS classes don't verify under java 7+ due to the + // super() invokespecial being inside of a try{} + { throw new InjectException("Injected bytecode must be Java 6 compatible"); + } } private Method findDeobMatching(ClassFile deobClass, Method mixinMethod, String deobName) @@ -642,18 +684,26 @@ public class MixinInjector extends AbstractInjector for (Method method : deobClass.getMethods()) { if (!deobName.equals(method.getName())) + { continue; + } if (InjectUtil.apiToDeobSigEquals(inject, method.getDescriptor(), mixinMethod.getDescriptor())) + { matching.add(method); + } } if (matching.size() > 1) - // 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 + // 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 + { throw new InjectException("There are several matching methods when there should only be one"); + } else if (matching.size() == 1) + { return matching.get(0); + } return inject.getDeobfuscated().findStaticMethod(deobName); } @@ -695,15 +745,17 @@ public class MixinInjector extends AbstractInjector @Value private static class CopiedMethod { - @Nonnull Method copy; - @Nullable Integer garbage; + @Nonnull + Method copy; + @Nullable Integer garbage; } @Value private static class ShadowField { - @Nonnull Field targetField; - @Nullable Number obfuscatedGetter; + @Nonnull + Field targetField; + @Nullable Number obfuscatedGetter; } private static Provider mixinProvider(ClassFile mixin) @@ -716,7 +768,9 @@ public class MixinInjector extends AbstractInjector public ClassFile get() { if (bytes != null) + { return JarUtil.loadClass(bytes); + } bytes = JarUtil.writeClass(mixin.getGroup(), mixin); return mixin; diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/RSApiInjector.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/RSApiInjector.java index e5a9c4e0d9..a9b4bf6b26 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/RSApiInjector.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/RSApiInjector.java @@ -84,7 +84,9 @@ public class RSApiInjector extends AbstractInjector final List matching = findImportsFor(deobField, deobField.isStatic(), implementingClass); if (matching == null) + { continue; + } final Type deobType = deobField.getType(); @@ -153,7 +155,9 @@ public class RSApiInjector extends AbstractInjector final Number getter = DeobAnnotations.getObfuscatedGetter(deobField); 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"); + } inject(matching, deobField, vanillaField, getter); } @@ -166,7 +170,9 @@ public class RSApiInjector extends AbstractInjector final List matching = findImportsFor(deobMethod, deobMethod.isStatic(), implementingClass); if (matching == null) + { continue; + } final Signature deobSig = deobMethod.getDescriptor(); @@ -211,7 +217,9 @@ public class RSApiInjector extends AbstractInjector apiMethod.setInjected(true); } else if (matching.size() != 0) + { throw new InjectException("Multiple api imports matching method " + deobMethod.getPoolMethod()); + } } } @@ -225,7 +233,9 @@ public class RSApiInjector extends AbstractInjector matched.removeIf(RSApiMethod::isInjected); if (matched.size() > 2) + { throw new InjectException("More than 2 imported api methods for field " + deobField.getPoolField()); + } final Field vanillaField = inject.toVanilla(deobField); final Number getter = DeobAnnotations.getObfuscatedGetter(deobField); @@ -238,7 +248,9 @@ public class RSApiInjector extends AbstractInjector { final String exportedName = InjectUtil.getExportedName(object); if (exportedName == null) + { return null; + } final List matching = new ArrayList<>(); diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/DrawAfterWidgets.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/DrawAfterWidgets.java index 864b5a59b0..5f6d8c2d40 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/DrawAfterWidgets.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/DrawAfterWidgets.java @@ -271,10 +271,12 @@ public class DrawAfterWidgets extends AbstractInjector for (Field f : c.getFields()) { if (f.isStatic()) + { if (f.getName().equals(s)) { return inject.toVanilla(f); } + } } } return null; @@ -287,10 +289,12 @@ public class DrawAfterWidgets extends AbstractInjector for (Field f : c.getFields()) { if (!f.isStatic()) + { if (f.getName().equals(s)) { return f; } + } } } return null; diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/DrawMenu.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/DrawMenu.java index b22937673d..b54c568be1 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/DrawMenu.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/DrawMenu.java @@ -87,7 +87,9 @@ public class DrawMenu extends AbstractInjector { Instruction instruction = ic.getInstruction(); if (!(instruction instanceof GetStatic)) + { continue; + } 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 // else it's the other way around, obviously if (isMenuOpenPopI instanceof IfNe) + { injectInvokeAfter = ((IfNe) isMenuOpenPopI).getTo(); + } else + { injectInvokeAfter = isMenuOpenPopI; + } } else if (((GetStatic) instruction).getField().equals(gameDrawMode)) { List instrL = instruction.getInstructions().getInstructions(); for (int i = instrL.indexOf(instruction); !(instruction instanceof Label); i--) + { instruction = instrL.get(i); + } labelToJumpTo = (Label) instruction; } if (injectInvokeAfter != null && labelToJumpTo != null) + { break; + } } if (injectInvokeAfter == null || labelToJumpTo == null) + { throw new InjectException("Couldn't find the right location for DrawMenu to inject"); + } final Instructions instrs = mc.getMethod().getCode().getInstructions(); int idx = instrs.getInstructions().indexOf(injectInvokeAfter); diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/Occluder.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/Occluder.java index f1ed0d6d3f..14d44773c5 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/Occluder.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/Occluder.java @@ -49,12 +49,16 @@ public class Occluder extends AbstractInjector Instruction i = it.next(); if (!(i instanceof BiPush)) + { continue; + } boolean shouldChange = (byte) ((BiPush) i).getConstant() == OLDVALUE; if (!shouldChange) + { continue; + } replaced++; @@ -64,6 +68,8 @@ public class Occluder extends AbstractInjector } if (replaced != 10) + { throw new InjectException("Only found " + replaced + " 25's to replace in occlude instead of expected 10"); + } } } diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/RasterizerAlpha.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/RasterizerAlpha.java index f76960598e..bf38cd42d5 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/RasterizerAlpha.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/RasterizerAlpha.java @@ -74,7 +74,9 @@ public class RasterizerAlpha extends AbstractInjector { Instructions instrs = getInstrs(mc); if (instrs == null) + { return; + } int count = 0; int orCount = 0; @@ -84,14 +86,18 @@ public class RasterizerAlpha extends AbstractInjector { Instruction instruction = ic.getInstruction(); if (!(instruction instanceof IAStore)) + { continue; + } // Field field = astore.getMyField(ic); // doesn't track into methods so doing it here StackContext array = ic.getPops().get(2); if (!isSameField(r2dPx, array)) + { continue; + } // This is the colour that's being set StackContext colour = ic.getPops().get(0); @@ -111,15 +117,21 @@ public class RasterizerAlpha extends AbstractInjector for (InstructionContext ins : mc.getInstructionContexts()) { if (!(ins.getInstruction() instanceof SiPush)) + { continue; + } SiPush pci = (SiPush) ins.getInstruction(); if ((short) pci.getConstant() != (short) 256) + { continue; + } InstructionContext isub = ins.getPushes().get(0).getPopped().get(0); if (!(isub.getInstruction() instanceof ISub)) + { continue; + } StackContext alphaPop = isub.getPops().get(0); 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 (colPushI instanceof IALoad && isSameField(r2dPx, colPusher.getPops().get(1))) + { continue; + } // If the value is 0, it's supposed to be transparent, not black if (colPushI instanceof PushConstantInstruction && ((PushConstantInstruction) colPushI).getConstant().equals(0)) + { continue; + } // rasterPx[idx] = color | 0xff000000 (the | 0xff000000 is what's added) int storeIdx = instrs.getInstructions().indexOf(instruction); @@ -217,7 +233,9 @@ public class RasterizerAlpha extends AbstractInjector { Code c = mc.getMethod().getCode(); if (c == null) + { return null; + } return c.getInstructions(); } @@ -226,11 +244,15 @@ public class RasterizerAlpha extends AbstractInjector { InstructionContext pusher = stackContext.getPushed().resolve(stackContext); if (pusher.getInstruction() instanceof GetFieldInstruction) + { return pusher; + } // No field I wanna trace, rn at least if (!(pusher.getInstruction() instanceof LVTInstruction)) + { return null; + } int vidx = ((LVTInstruction) pusher.getInstruction()).getVariableIndex(); @@ -245,7 +267,9 @@ public class RasterizerAlpha extends AbstractInjector InstructionContext ic = resolveFieldThroughInvokes(array); if (ic == null) + { return false; + } return ((GetFieldInstruction) ic.getInstruction()).getMyField() == f; } diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/RenderDraw.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/RenderDraw.java index b9f32a2dc4..c31802a391 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/RenderDraw.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/raw/RenderDraw.java @@ -64,6 +64,8 @@ public class RenderDraw extends AbstractInjector } if (replaced != EXPECTED) + { throw new InjectException("Didn't replace the expected amount of method calls"); + } } } diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectGetter.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectGetter.java index 5ef6b257dd..696753b2b0 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectGetter.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectGetter.java @@ -50,7 +50,9 @@ public class InjectGetter public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter) { if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null) + { throw new InjectException("Duplicate getter method " + apiMethod.getMethod().toString()); + } final String name = apiMethod.getName(); final Signature sig = apiMethod.getSignature(); @@ -75,7 +77,9 @@ public class InjectGetter } if (getter != null) + { InjectUtil.injectObfuscatedGetter(getter, instructions, ins::add); + } ins.add(InjectUtil.createReturnForType(instructions, field.getType())); diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectSetter.java b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectSetter.java index 2ff9adb2d1..492c5649f1 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectSetter.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectSetter.java @@ -53,7 +53,9 @@ public class InjectSetter public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter) { if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null) + { throw new InjectException("Duplicate setter method " + apiMethod.getMethod().toString()); + } final String name = apiMethod.getName(); final Signature sig = apiMethod.getSignature(); @@ -69,7 +71,9 @@ public class InjectSetter // load this if (!field.isStatic()) + { ins.add(new ALoad(instructions, 0)); + } // load argument final Type argumentType = sig.getTypeOfArg(0); @@ -85,12 +89,18 @@ public class InjectSetter } if (getter != null) + { InjectUtil.injectObfuscatedSetter(getter, instructions, ins::add); + } if (field.isStatic()) + { ins.add(new PutStatic(instructions, field)); + } else + { ins.add(new PutField(instructions, field)); + } ins.add(new VReturn(instructions)); diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApi.java b/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApi.java index abee6c0c4b..3e9bbae3c9 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApi.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApi.java @@ -45,7 +45,9 @@ public class RSApi implements Iterable for (File file : classes) { if (!file.getName().startsWith("RS")) + { continue; + } try (InputStream is = new FileInputStream(file)) { @@ -72,7 +74,9 @@ public class RSApi implements Iterable final ImmutableMap.Builder builder = ImmutableMap.builder(); for (RSApiClass clazz : this) + { builder.put(clazz.getName(), clazz); + } this.map = builder.build(); @@ -112,11 +116,17 @@ public class RSApi implements Iterable { RSApiClass clazz = findClass(interf.getName()); if (clazz != null) + { return clazz; + } for (RSApiClass apiC : this) + { if (apiC.getInterfaces().contains(interf)) + { return apiC; + } + } return null; } diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApiClass.java b/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApiClass.java index 88c4c2af9d..5283095a72 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApiClass.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApiClass.java @@ -46,7 +46,9 @@ public class RSApiClass extends ClassVisitor implements Iterable for (RSApiMethod method : this) { if (method.isSynthetic()) + { continue; + } if (method.findAnnotation(CONSTRUCT) != null) { @@ -56,10 +58,12 @@ public class RSApiClass extends ClassVisitor implements Iterable final Annotation imported = method.findAnnotation(IMPORT); if (imported != null) + { imports.computeIfAbsent( imported.getValueString(), (str) -> new ArrayList<>() ).add(method); + } } } @@ -79,7 +83,9 @@ public class RSApiClass extends ClassVisitor implements Iterable { List imported = imports.get(str); if (imported == null) + { return; + } to.addAll(imported); } @@ -95,7 +101,9 @@ public class RSApiClass extends ClassVisitor implements Iterable clazz = new Class(name); for (String s : interfaces) + { this.interfaces.add(new Class(s)); + } } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) diff --git a/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApiMethod.java b/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApiMethod.java index 4b58c778de..9700f25330 100644 --- a/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApiMethod.java +++ b/openosrs-injector/src/main/java/com/openosrs/injector/rsapi/RSApiMethod.java @@ -9,9 +9,7 @@ package com.openosrs.injector.rsapi; import java.util.HashMap; import java.util.Map; -import lombok.Data; import lombok.Getter; -import lombok.RequiredArgsConstructor; import lombok.Setter; import net.runelite.asm.Annotation; import net.runelite.asm.Named; diff --git a/openosrs-injector/src/main/kotlin/com/openosrs/injector/Inject.kt b/openosrs-injector/src/main/kotlin/com/openosrs/injector/Inject.kt index e04f1e0a6f..82b6c132bd 100644 --- a/openosrs-injector/src/main/kotlin/com/openosrs/injector/Inject.kt +++ b/openosrs-injector/src/main/kotlin/com/openosrs/injector/Inject.kt @@ -16,7 +16,7 @@ import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction @CacheableTask -abstract class Inject: DefaultTask() { +abstract class Inject : DefaultTask() { @get:Nested abstract val extension: InjectExtension diff --git a/openosrs-injector/src/main/kotlin/com/openosrs/injector/InjectExtension.kt b/openosrs-injector/src/main/kotlin/com/openosrs/injector/InjectExtension.kt index 91d462e49e..efbb9b74ac 100644 --- a/openosrs-injector/src/main/kotlin/com/openosrs/injector/InjectExtension.kt +++ b/openosrs-injector/src/main/kotlin/com/openosrs/injector/InjectExtension.kt @@ -15,10 +15,13 @@ import org.gradle.api.tasks.PathSensitivity interface InjectExtension { @get:[InputFile PathSensitive(PathSensitivity.NONE)] val vanilla: RegularFileProperty + @get:[InputFile PathSensitive(PathSensitivity.NONE)] val rsclient: RegularFileProperty + @get:[InputFile PathSensitive(PathSensitivity.NONE)] val mixins: RegularFileProperty + @get:[InputFile PathSensitive(PathSensitivity.NONE)] val rsapi: RegularFileProperty } diff --git a/openosrs-injector/src/main/kotlin/com/openosrs/injector/InjectPlugin.kt b/openosrs-injector/src/main/kotlin/com/openosrs/injector/InjectPlugin.kt index 9aeaef51c4..803ec5fdb8 100644 --- a/openosrs-injector/src/main/kotlin/com/openosrs/injector/InjectPlugin.kt +++ b/openosrs-injector/src/main/kotlin/com/openosrs/injector/InjectPlugin.kt @@ -10,19 +10,21 @@ package com.openosrs.injector import org.gradle.api.Plugin import org.gradle.api.Project -class InjectPlugin: Plugin { - override fun apply(project: Project) { with(project) { - val task = tasks.create("inject", Inject::class.java) - task.output.convention { file("$buildDir/libs/$name-$version.jar") } +class InjectPlugin : Plugin { + override fun apply(project: Project) { + with(project) { + val task = tasks.create("inject", Inject::class.java) + task.output.convention { file("$buildDir/libs/$name-$version.jar") } - artifacts { - it.add("runtimeElements", task.output) + artifacts { + it.add("runtimeElements", task.output) + } + + tasks.getByName("assemble") { + it.finalizedBy("inject") + } + + extensions.add(InjectExtension::class.java, "injector", task.extension) } - - tasks.getByName("assemble") { - it.finalizedBy("inject") - } - - extensions.add(InjectExtension::class.java, "injector", task.extension) - }} + } } \ No newline at end of file diff --git a/openosrs-injector/src/test/java/com/openosrs/injector/injectors/MixinInjectorTest.java b/openosrs-injector/src/test/java/com/openosrs/injector/injectors/MixinInjectorTest.java index 1665f69613..fa8b3fd556 100644 --- a/openosrs-injector/src/test/java/com/openosrs/injector/injectors/MixinInjectorTest.java +++ b/openosrs-injector/src/test/java/com/openosrs/injector/injectors/MixinInjectorTest.java @@ -283,12 +283,15 @@ public class MixinInjectorTest Instruction i; while (it.hasNext() && !((i = it.next()) instanceof GetStatic && - ((GetStatic) i).getField().getName().equals(gottenField))); + ((GetStatic) i).getField().getName().equals(gottenField))) + { + ; + } return (i = it.next()) instanceof LDC && - ((LDC) i).getConstantAsInt() == 1157381415 && - it.next() instanceof IMul; + ((LDC) i).getConstantAsInt() == 1157381415 && + it.next() instanceof IMul; } private static ClassFile loadClass(Class clazz) diff --git a/openosrs-injector/src/test/java/com/openosrs/injector/injectors/raw/DrawAfterWidgetsTest.java b/openosrs-injector/src/test/java/com/openosrs/injector/injectors/raw/DrawAfterWidgetsTest.java deleted file mode 100644 index 6b905d52a6..0000000000 --- a/openosrs-injector/src/test/java/com/openosrs/injector/injectors/raw/DrawAfterWidgetsTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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(); - } -} diff --git a/openosrs-injector/src/test/java/com/openosrs/injector/transformers/SourceChangerTest.java b/openosrs-injector/src/test/java/com/openosrs/injector/transformers/SourceChangerTest.java index 18a1fcc0aa..dee0cbdec5 100644 --- a/openosrs-injector/src/test/java/com/openosrs/injector/transformers/SourceChangerTest.java +++ b/openosrs-injector/src/test/java/com/openosrs/injector/transformers/SourceChangerTest.java @@ -36,9 +36,11 @@ public class SourceChangerTest new ClassReader(PACKAGE + "OldName").accept(vann, ClassReader.SKIP_FRAMES); 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 - {} + { + } @Override public void forEachPair(BiConsumer consumer) @@ -54,8 +56,8 @@ public class SourceChangerTest vann.getClassFile().accept(cw); OldName obj = (OldName) MethodHandles.privateLookupIn( - NewName.class, - MethodHandles.lookup()) + NewName.class, + MethodHandles.lookup()) .defineClass(cw.toByteArray()) .getDeclaredConstructor() .newInstance(); diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java index d064ea5900..40c5e09cc9 100644 --- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java +++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java @@ -350,4 +350,10 @@ public final class ScriptID @ScriptArguments(integer = 7) 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; } diff --git a/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java b/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java index 7cad194077..4a1e9dd8de 100644 --- a/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java +++ b/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java @@ -29,7 +29,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import javax.annotation.Nullable; import lombok.Value; import net.runelite.api.Client; import static net.runelite.api.Constants.CHUNK_SIZE; diff --git a/runelite-api/src/main/java/net/runelite/api/hooks/Callbacks.java b/runelite-api/src/main/java/net/runelite/api/hooks/Callbacks.java index 51faedb49b..59111a5eda 100644 --- a/runelite-api/src/main/java/net/runelite/api/hooks/Callbacks.java +++ b/runelite-api/src/main/java/net/runelite/api/hooks/Callbacks.java @@ -28,7 +28,9 @@ import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; +import java.util.List; import net.runelite.api.MainBufferProvider; +import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetItem; /** @@ -70,8 +72,9 @@ public interface Callbacks */ void drawAboveOverheads(); - void drawAfterWidgets(); + void drawLayer(Widget layer, List widgetItems); + void drawInterface(int interfaceId, List widgetItems); /** * 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); - /** - * 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. * diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java index 1d7e9f714c..d521d67870 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java @@ -26,6 +26,7 @@ package net.runelite.api.widgets; import java.awt.Rectangle; import java.util.Collection; +import java.util.List; import net.runelite.api.FontTypeFace; import net.runelite.api.Point; import net.runelite.api.SpritePixels; @@ -475,7 +476,7 @@ public interface Widget * * @return any items displayed, or null if there are no items */ - Collection getWidgetItems(); + List getWidgetItems(); /** * Gets a widget item at a specific index. diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index b69c6d45b7..ea614afd36 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -974,6 +974,11 @@ public enum WidgetInfo 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 * to its group ID. @@ -993,7 +998,7 @@ public enum WidgetInfo * @param id passed group-child ID * @return the child ID */ - public static int getChildFromID(int id) + public static int TO_CHILD(int id) { return id & 0xFFFF; } diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java index 9894e41492..ab0911c1f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java @@ -28,7 +28,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.Properties; import javax.annotation.Nullable; -import net.runelite.http.api.RuneLiteAPI; import okhttp3.HttpUrl; public class RuneLiteProperties @@ -145,7 +144,7 @@ public class RuneLiteProperties public static HttpUrl getPluginHubBase() { 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() diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java index 1b92d18ac5..fe58833496 100644 --- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java +++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java @@ -37,15 +37,15 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.BufferProvider; import net.runelite.api.Client; -import net.runelite.api.Renderable; import net.runelite.api.MainBufferProvider; -import net.runelite.api.NullItemID; import net.runelite.api.RenderOverview; +import net.runelite.api.Renderable; import net.runelite.api.Skill; import net.runelite.api.WorldMapManager; import net.runelite.api.events.BeforeMenuRender; @@ -331,7 +331,7 @@ public class Hooks implements Callbacks try { - renderer.render(graphics2d, OverlayLayer.ALWAYS_ON_TOP); + renderer.renderOverlayLayer(graphics2d, OverlayLayer.ALWAYS_ON_TOP); } catch (Exception ex) { @@ -426,7 +426,7 @@ public class Hooks implements Callbacks try { - renderer.render(graphics2d, OverlayLayer.ABOVE_SCENE); + renderer.renderOverlayLayer(graphics2d, OverlayLayer.ABOVE_SCENE); } catch (Exception ex) { @@ -442,7 +442,7 @@ public class Hooks implements Callbacks try { - renderer.render(graphics2d, OverlayLayer.UNDER_WIDGETS); + renderer.renderOverlayLayer(graphics2d, OverlayLayer.UNDER_WIDGETS); } 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 public void onGameStateChanged(GameStateChanged gameStateChanged) { @@ -508,12 +487,34 @@ public class Hooks implements Callbacks } @Override - public void drawItem(int itemId, WidgetItem widgetItem) + public void drawInterface(int interfaceId, List widgetItems) { - // Empty bank item - if (widgetItem.getId() != NullItemID.NULL_6512) + MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider(); + 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 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); } + public static void clearColorBuffer(int x, int y, int width, int height, int color) { BufferProvider bp = client.getBufferProvider(); diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java index d207e6af5a..0c33297e11 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java @@ -1041,7 +1041,7 @@ public class ConfigManager { updateRSProfile(); } - + @Subscribe private void onPlayerChanged(PlayerChanged ev) { diff --git a/runelite-client/src/main/java/net/runelite/client/config/FontType.java b/runelite-client/src/main/java/net/runelite/client/config/FontType.java index 36e5363eb8..8ed57bd302 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/FontType.java +++ b/runelite-client/src/main/java/net/runelite/client/config/FontType.java @@ -27,6 +27,7 @@ package net.runelite.client.config; import lombok.RequiredArgsConstructor; import lombok.Getter; import net.runelite.client.ui.FontManager; + import java.awt.Font; @Getter diff --git a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java index 4a1cb05c7c..0df12bf1ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java +++ b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java @@ -67,13 +67,12 @@ public class ExternalPluginClient { HttpUrl manifest = RuneLiteProperties.getPluginHubBase() .newBuilder() - .addPathSegment("manifest.js") + .addPathSegments("manifest.js") .build(); try (Response res = okHttpClient.newCall(new Request.Builder().url(manifest).build()).execute()) { if (res.code() != 200) { - System.out.println(manifest.url().toString()); throw new IOException("Non-OK response code: " + res.code()); } diff --git a/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java b/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java index d7a50592f6..ad6c5e0925 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java +++ b/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java @@ -118,10 +118,10 @@ public enum AgilityShortcut 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), 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_SOUTHEAST(40, "Rope Bridge", null, ROPE_BRIDGE_21308, ROPE_BRIDGE_21309), - NEITIZNOT_BRIDGE_NORTHWEST(40, "Rope Bridge", null, ROPE_BRIDGE_21310, ROPE_BRIDGE_21311), - NEITIZNOT_BRIDGE_NORTH(40, "Rope Bridge", null, ROPE_BRIDGE_21312, ROPE_BRIDGE_21313), + NEITIZNOT_BRIDGE_REPAIR(0, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307), + NEITIZNOT_BRIDGE_SOUTHEAST(0, "Rope Bridge", null, ROPE_BRIDGE_21308, ROPE_BRIDGE_21309), + NEITIZNOT_BRIDGE_NORTHWEST(0, "Rope Bridge", null, ROPE_BRIDGE_21310, ROPE_BRIDGE_21311), + 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), 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), diff --git a/runelite-client/src/main/java/net/runelite/client/game/NPCManager.java b/runelite-client/src/main/java/net/runelite/client/game/NPCManager.java index 1251db7350..1a51afea3f 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/NPCManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/NPCManager.java @@ -24,11 +24,7 @@ */ package net.runelite.client.game; -import com.google.common.collect.ImmutableMap; -import com.google.gson.stream.JsonReader; import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; @@ -46,14 +42,12 @@ public class NPCManager { private final OkHttpClient okHttpClient; private Map npcMap = Collections.emptyMap(); - private ImmutableMap statsMap; @Inject private NPCManager(OkHttpClient okHttpClient, ScheduledExecutorService scheduledExecutorService) { this.okHttpClient = okHttpClient; scheduledExecutorService.execute(this::loadNpcs); - loadStats(); } @Nullable @@ -80,45 +74,4 @@ public class NPCManager 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 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(); - } } diff --git a/runelite-client/src/main/java/net/runelite/client/game/NPCStats.java b/runelite-client/src/main/java/net/runelite/client/game/NPCStats.java deleted file mode 100644 index 49a5f11002..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/game/NPCStats.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2019, 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 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(); - } - }; -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/menus/MenuManager.java b/runelite-client/src/main/java/net/runelite/client/menus/MenuManager.java index d4c77068e2..67129b0ba5 100644 --- a/runelite-client/src/main/java/net/runelite/client/menus/MenuManager.java +++ b/runelite-client/src/main/java/net/runelite/client/menus/MenuManager.java @@ -140,7 +140,7 @@ public class MenuManager MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); menuEntry.setOption(currentMenu.getMenuOption()); - menuEntry.setActionParam1(widgetId); + menuEntry.setParam1(widgetId); menuEntry.setTarget(currentMenu.getMenuTarget()); menuEntry.setType(MenuAction.RUNELITE.getId()); @@ -241,17 +241,17 @@ public class MenuManager return; // not a managed widget option or custom player option } - int widgetId = event.getActionParam1(); + int widgetId = event.getWidgetId(); Collection options = managedMenuOptions.get(widgetId); for (WidgetMenuOption curMenuOption : options) { - if (curMenuOption.getMenuTarget().equals(event.getTarget()) - && curMenuOption.getMenuOption().equals(event.getOption())) + if (curMenuOption.getMenuTarget().equals(event.getMenuTarget()) + && curMenuOption.getMenuOption().equals(event.getMenuOption())) { WidgetMenuOptionClicked customMenu = new WidgetMenuOptionClicked(); - customMenu.setMenuOption(event.getOption()); - customMenu.setMenuTarget(event.getTarget()); + customMenu.setMenuOption(event.getMenuOption()); + customMenu.setMenuTarget(event.getMenuTarget()); customMenu.setWidget(curMenuOption.getWidget()); eventBus.post(customMenu); 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: // "username5 (level-42)" -> "username (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: // username (level-42) or username String username = Text.removeTags(target).split("[(]")[0].trim(); PlayerMenuOptionClicked playerMenuOptionClicked = new PlayerMenuOptionClicked(); - playerMenuOptionClicked.setMenuOption(event.getOption()); + playerMenuOptionClicked.setMenuOption(event.getMenuOption()); playerMenuOptionClicked.setMenuTarget(username); eventBus.post(playerMenuOptionClicked); diff --git a/runelite-client/src/main/java/net/runelite/client/menus/WidgetMenuOption.java b/runelite-client/src/main/java/net/runelite/client/menus/WidgetMenuOption.java index 3adbe3ec2f..307551542c 100644 --- a/runelite-client/src/main/java/net/runelite/client/menus/WidgetMenuOption.java +++ b/runelite-client/src/main/java/net/runelite/client/menus/WidgetMenuOption.java @@ -25,6 +25,7 @@ package net.runelite.client.menus; import net.runelite.api.widgets.WidgetInfo; + import java.awt.Color; import net.runelite.client.ui.JagexColors; import net.runelite.client.util.ColorUtil; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMinePluginConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMinePluginConfig.java index df92a32a56..76848a66e2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMinePluginConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMinePluginConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.blastmine; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; + import java.awt.Color; @ConfigGroup("blastmine") diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineRockOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineRockOverlay.java index 92fbdfe221..316ffec8c0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineRockOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineRockOverlay.java @@ -42,7 +42,6 @@ import net.runelite.api.Point; import net.runelite.api.Tile; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.widgets.Widget; import net.runelite.client.game.ItemManager; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -91,12 +90,10 @@ public class BlastMineRockOverlay extends Overlay } final Tile[][][] tiles = client.getScene().getTiles(); - final Widget viewport = client.getViewportWidget(); for (final BlastMineRock rock : rocks.values()) { - if (viewport == null || - rock.getGameObject().getCanvasLocation() == null || + if (rock.getGameObject().getCanvasLocation() == null || rock.getGameObject().getWorldLocation().distanceTo(client.getLocalPlayer().getWorldLocation()) > MAX_DISTANCE) { continue; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java index 4e0ee6b16e..7f7224f940 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java @@ -136,10 +136,6 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT); 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); if (settingsInit != null) { - throw new UnsupportedOperationException("Implement"); - //client.createScriptEvent(settingsInit.getOnLoadListener()) - //.setSource(settingsInit) - //.run(); } }); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java index 6526cce6eb..8305c40bde 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java @@ -53,7 +53,7 @@ import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.vars.InputType; import net.runelite.api.widgets.Widget; 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 net.runelite.client.callback.ClientThread; 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 childId = getChildFromID(entry.getParam1()); + final int childId = TO_CHILD(entry.getParam1()); if (groupId != WidgetInfo.CHATBOX.getGroupId()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginHubPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginHubPanel.java index aa5dbd5074..978be1b4c5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginHubPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginHubPanel.java @@ -280,6 +280,8 @@ class PluginHubPanel extends PluginPanel return; } } + addrm.setText("Installing"); + addrm.setBackground(ColorScheme.MEDIUM_GRAY_COLOR); externalPluginManager.install(manifest.getInternalName()); }); } @@ -287,14 +289,24 @@ class PluginHubPanel extends PluginPanel { addrm.setText("Remove"); 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 { assert update; addrm.setText("Update"); 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.setFocusPainted(false); @@ -313,7 +325,7 @@ class PluginHubPanel extends PluginPanel .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, 100) .addComponent(help, 0, 24, 24) .addComponent(configure, 0, 24, 24) - .addComponent(addrm, 0, 50, GroupLayout.PREFERRED_SIZE) + .addComponent(addrm, 0, 57, GroupLayout.PREFERRED_SIZE) .addGap(5)))); int lineHeight = description.getFontMetrics(description.getFont()).getHeight(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListPanel.java index 9564bf40f7..8894b0fcc9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListPanel.java @@ -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 PINNED_PLUGINS_CONFIG_KEY = "pinnedPlugins"; private static final ImmutableList CATEGORY_TAGS = ImmutableList.of( - "OpenOSRS", "Combat", "Chat", "Item", @@ -165,16 +164,10 @@ class PluginListPanel extends PluginPanel setLayout(new BorderLayout()); 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(); topPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); topPanel.setLayout(new BorderLayout(0, BORDER_OFFSET)); topPanel.add(searchBar, BorderLayout.CENTER); - topPanel.add(externalPluginOPRSButton, BorderLayout.SOUTH); add(topPanel, BorderLayout.NORTH); mainPanel = new FixedWidthPanel(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MovementFlag.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MovementFlag.java index add2260e70..487c255673 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MovementFlag.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/MovementFlag.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.devtools; import lombok.AllArgsConstructor; import lombok.Getter; import net.runelite.api.CollisionDataFlag; + import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/ScriptInspector.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/ScriptInspector.java index 5dacdc556f..5956baed72 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/ScriptInspector.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/ScriptInspector.java @@ -63,7 +63,7 @@ import net.runelite.api.events.ScriptPostFired; import net.runelite.api.events.ScriptPreFired; import net.runelite.api.widgets.Widget; 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 net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.EventBus; @@ -120,7 +120,7 @@ public class ScriptInspector extends JFrame if (source != null) { int id = source.getId(); - output += " - " + TO_GROUP(id) + "." + getChildFromID(id); + output += " - " + TO_GROUP(id) + "." + TO_CHILD(id); if (source.getIndex() != -1) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspector.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspector.java index 4e7cb56d66..986ebb996a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspector.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspector.java @@ -59,7 +59,7 @@ import net.runelite.api.Client; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; 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 net.runelite.client.events.ConfigChanged; import net.runelite.api.events.MenuEntryAdded; @@ -464,7 +464,7 @@ class WidgetInspector extends JFrame 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.setOriginalWidth(15); @@ -538,7 +538,7 @@ class WidgetInspector extends JFrame { 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) { @@ -584,7 +584,7 @@ class WidgetInspector extends JFrame public static String getWidgetIdentifier(Widget widget) { int id = widget.getId(); - String str = TO_GROUP(id) + "." + getChildFromID(id); + String str = TO_GROUP(id) + "." + TO_CHILD(id); if (widget.getIndex() != -1) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspectorOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspectorOverlay.java index c0ceab94a8..27b83f0f2a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspectorOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspectorOverlay.java @@ -37,6 +37,7 @@ import javax.inject.Singleton; import net.runelite.api.Client; import net.runelite.api.MenuEntry; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetItem; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -61,6 +62,7 @@ public class WidgetInspectorOverlay extends Overlay setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_WIDGETS); setPriority(OverlayPriority.HIGHEST); + drawAfterInterface(WidgetID.FULLSCREEN_MAP_GROUP_ID); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java index c0ee198533..fbeedbedfe 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java @@ -35,6 +35,7 @@ import net.runelite.api.Point; import net.runelite.api.RenderOverview; import net.runelite.api.coords.WorldPoint; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -56,7 +57,8 @@ public class WorldMapLocationOverlay extends Overlay this.plugin = plugin; setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGHEST); - setLayer(OverlayLayer.ABOVE_MAP); + setLayer(OverlayLayer.MANUAL); + drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java index 1e136267b8..8bfbf54398 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java @@ -35,6 +35,7 @@ import net.runelite.api.Client; import net.runelite.api.Point; import net.runelite.api.RenderOverview; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -56,7 +57,8 @@ class WorldMapRegionOverlay extends Overlay { setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGH); - setLayer(OverlayLayer.ABOVE_MAP); + setLayer(OverlayLayer.MANUAL); + drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID); this.client = client; this.plugin = plugin; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java index 6db8c8512b..976082dcd7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java @@ -45,7 +45,7 @@ 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.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 net.runelite.api.widgets.WidgetItem; import net.runelite.client.chat.ChatColorType; @@ -124,7 +124,7 @@ public class ExaminePlugin extends Plugin int widgetId = event.getWidgetId(); int widgetGroup = TO_GROUP(widgetId); - int widgetChild = getChildFromID(widgetId); + int widgetChild = TO_CHILD(widgetId); Widget widget = client.getWidget(widgetGroup, widgetChild); WidgetItem widgetItem = widget.getWidgetItem(event.getActionParam()); 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) { int widgetGroup = TO_GROUP(widgetId); - int widgetChild = getChildFromID(widgetId); + int widgetChild = TO_CHILD(widgetId); Widget widget = client.getWidget(widgetGroup, widgetChild); if (widget == null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index b6ee03e21d..240ea3b8d4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -563,7 +563,7 @@ public class GrandExchangePlugin extends Plugin { case WidgetID.BANK_GROUP_ID: // 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; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index ec1d0527c2..dbd1db7ddd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -111,7 +111,7 @@ public class GroundItemsOverlay extends Overlay final FontMetrics fm = graphics.getFontMetrics(); final Player player = client.getLocalPlayer(); - if (player == null || client.getViewportWidget() == null) + if (player == null) { return null; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java new file mode 100644 index 0000000000..564cbb609b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017, Devin French + * 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; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java new file mode 100644 index 0000000000..93566d4c22 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java @@ -0,0 +1,746 @@ +/* + * Copyright (c) 2016-2017, Abel Briggs + * Copyright (c) 2017, Kronos + * 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 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; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/inventorytags/InventoryTagsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/inventorytags/InventoryTagsOverlay.java index c6fafc9466..03857e185c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/inventorytags/InventoryTagsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/inventorytags/InventoryTagsOverlay.java @@ -51,7 +51,7 @@ public class InventoryTagsOverlay extends WidgetItemOverlay } @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); if (group != null) @@ -60,10 +60,10 @@ public class InventoryTagsOverlay extends WidgetItemOverlay final DisplayMode displayMode = config.getDisplayMode(); if (color != null) { - Rectangle bounds = itemWidget.getCanvasBounds(); + Rectangle bounds = widgetItem.getCanvasBounds(); 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); } else diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java index fc91487230..07e213d1d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java @@ -52,7 +52,7 @@ class ItemChargeOverlay extends WidgetItemOverlay } @Override - public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget) + public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem) { if (!displayOverlay()) { @@ -153,7 +153,7 @@ class ItemChargeOverlay extends WidgetItemOverlay charges = chargeItem.getCharges(); } - final Rectangle bounds = itemWidget.getCanvasBounds(); + final Rectangle bounds = widgetItem.getCanvasBounds(); final TextComponent textComponent = new TextComponent(); textComponent.setPosition(new Point(bounds.x - 1, bounds.y + 15)); textComponent.setText(charges < 0 ? "?" : String.valueOf(charges)); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationOverlay.java index 8d332ac837..eaf7824ff6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationOverlay.java @@ -55,7 +55,7 @@ class ItemIdentificationOverlay extends WidgetItemOverlay } @Override - public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget) + public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem) { ItemIdentification iden = findItemIdentification(itemId); if (iden == null) @@ -116,7 +116,7 @@ class ItemIdentificationOverlay extends WidgetItemOverlay } graphics.setFont(FontManager.getRunescapeSmallFont()); - renderText(graphics, itemWidget.getCanvasBounds(), iden); + renderText(graphics, widgetItem.getCanvasBounds(), iden); } private void renderText(Graphics2D graphics, Rectangle bounds, ItemIdentification iden) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java index c614665401..887ed04199 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java @@ -198,7 +198,7 @@ class ItemPricesOverlay extends Overlay } else if (id == ItemID.PLATINUM_TOKEN) { - return QuantityFormatter.formatNumber(qty * 1000) + " gp"; + return QuantityFormatter.formatNumber(qty * 1000L) + " gp"; } ItemComposition itemDef = itemManager.getItemComposition(id); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java index e6315c89ce..ff3922fd92 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java @@ -93,7 +93,7 @@ public class ItemStatOverlay extends Overlay final MenuEntry entry = menu[menuSize - 1]; 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); if (widget == null diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java index 0abf693a3f..7eee548751 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java @@ -28,11 +28,7 @@ import java.util.ArrayList; import java.util.List; import net.runelite.api.Client; import net.runelite.api.Varbits; -import net.runelite.client.plugins.itemstats.Effect; -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.*; import net.runelite.client.plugins.itemstats.stats.Stat; import net.runelite.client.plugins.itemstats.stats.Stats; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java index f8c3acb082..a77473853b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java @@ -36,6 +36,7 @@ import javax.inject.Singleton; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.coords.WorldPoint; + import static net.runelite.client.plugins.kourendlibrary.Book.*; /** diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/neverlogout/NeverLogoutPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/neverlogout/NeverLogoutPlugin.java deleted file mode 100644 index 0b1bc8804e..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/neverlogout/NeverLogoutPlugin.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2018, OpenOSRS - * 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); - } - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/MemorizedNPC.java b/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/MemorizedNPC.java deleted file mode 100644 index 7c8e84c6f2..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/MemorizedNPC.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2019, 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; - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackConfig.java deleted file mode 100644 index f1f77d8b8d..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackConfig.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2019, 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; - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackOverlay.java deleted file mode 100644 index 6ad8fdf3ca..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackOverlay.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2018, 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; - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackPlugin.java deleted file mode 100644 index 5825892dc7..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/nextattack/NextAttackPlugin.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2019, 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 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(); - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java index 8b8131cb7d..255f3f9ac1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java @@ -74,7 +74,7 @@ public class RunepouchOverlay extends WidgetItemOverlay } @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) { @@ -85,7 +85,7 @@ public class RunepouchOverlay extends WidgetItemOverlay graphics.setFont(FontManager.getRunescapeSmallFont()); - Point location = itemWidget.getCanvasLocation(); + Point location = widgetItem.getCanvasLocation(); StringBuilder tooltipBuilder = new StringBuilder(); for (int i = 0; i < AMOUNT_VARBITS.length; i++) @@ -142,7 +142,7 @@ public class RunepouchOverlay extends WidgetItemOverlay String tooltip = tooltipBuilder.toString(); 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)) { tooltipManager.add(new Tooltip(tooltip)); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java index ed60dd119a..98b2c9a73b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java @@ -43,7 +43,7 @@ class ScreenMarkerCreationOverlay extends Overlay { this.plugin = plugin; setPosition(OverlayPosition.DETACHED); - setLayer(OverlayLayer.ALWAYS_ON_TOP); + setLayer(OverlayLayer.ABOVE_WIDGETS); setPriority(OverlayPriority.HIGH); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerWidgetHighlightOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerWidgetHighlightOverlay.java index 09c08af6f0..718ea93903 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerWidgetHighlightOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerWidgetHighlightOverlay.java @@ -75,7 +75,7 @@ class ScreenMarkerWidgetHighlightOverlay extends Overlay final int childIdx = menuEntry.getParam0(); final int widgetId = menuEntry.getParam1(); 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); if (widget == null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java index 4d70d82f53..6e5ecd72eb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java @@ -94,7 +94,7 @@ class SlayerOverlay extends WidgetItemOverlay } @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)) { @@ -117,7 +117,7 @@ class SlayerOverlay extends WidgetItemOverlay graphics.setFont(FontManager.getRunescapeSmallFont()); - final Rectangle bounds = itemWidget.getCanvasBounds(); + final Rectangle bounds = widgetItem.getCanvasBounds(); final TextComponent textComponent = new TextComponent(); switch (itemId) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java index ec45039942..92d6b87893 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java @@ -39,7 +39,6 @@ import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.Constants; import net.runelite.api.EquipmentInventorySlot; -import net.runelite.api.GameState; import net.runelite.api.InventoryID; import net.runelite.api.Item; import net.runelite.api.ItemContainer; @@ -51,7 +50,6 @@ import net.runelite.api.NpcID; import net.runelite.api.Player; import net.runelite.api.VarPlayer; import net.runelite.api.Varbits; -import net.runelite.api.WorldType; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ActorDeath; 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.NpcDespawned; import net.runelite.api.events.VarbitChanged; -import net.runelite.api.events.WidgetHiddenChanged; 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 net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; @@ -135,15 +130,14 @@ public class TimersPlugin extends Plugin private boolean wasWearingEndurance; private int lastRaidVarb; - private int lastWildernessVarb; private int lastVengCooldownVarb; private int lastIsVengeancedVarb; private int lastPoisonVarp; + private int lastPvpVarb; private int nextPoisonTick; private WorldPoint lastPoint; private TeleportWidget lastTeleportClicked; private int lastAnimation; - private boolean loggedInRace; private boolean widgetHiddenChangedOnPvpWorld; private ElapsedTimer tzhaarTimer; @@ -176,7 +170,6 @@ public class TimersPlugin extends Plugin lastPoint = null; lastTeleportClicked = null; lastAnimation = -1; - loggedInRace = false; widgetHiddenChangedOnPvpWorld = false; lastPoisonVarp = 0; nextPoisonTick = 0; @@ -191,6 +184,7 @@ public class TimersPlugin extends Plugin int vengCooldownVarb = client.getVar(Varbits.VENGEANCE_COOLDOWN); int isVengeancedVarb = client.getVar(Varbits.VENGEANCE_ACTIVE); int poisonVarp = client.getVar(VarPlayer.POISON); + int pvpVarb = client.getVar(Varbits.PVP_SPEC_ORB); if (lastRaidVarb != raidVarb) { @@ -227,22 +221,6 @@ public class TimersPlugin extends Plugin 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()) { final int tickCount = client.getTickCount(); @@ -272,16 +250,16 @@ public class TimersPlugin extends Plugin lastPoisonVarp = poisonVarp; } - } - @Subscribe - public void onWidgetHiddenChanged(WidgetHiddenChanged event) - { - Widget widget = event.getWidget(); - if (WorldType.isPvpWorld(client.getWorldType()) - && WidgetInfo.TO_GROUP(widget.getId()) == WidgetID.PVP_GROUP_ID) + if (lastPvpVarb != pvpVarb) { - widgetHiddenChangedOnPvpWorld = true; + if (pvpVarb == 0) + { + log.debug("Left a PVP zone, clearing teleblock timer"); + removeGameTimer(TELEBLOCK); + } + + lastPvpVarb = pvpVarb; } } @@ -763,8 +741,6 @@ public class TimersPlugin extends Plugin @Subscribe public void onGameTick(GameTick event) { - loggedInRace = false; - Player player = client.getLocalPlayer(); WorldPoint currentWorldPoint = player.getWorldLocation(); @@ -826,9 +802,6 @@ public class TimersPlugin extends Plugin removeTzhaarTimer(); // will be readded by the wave message removeGameTimer(TELEBLOCK); break; - case LOGGED_IN: - loggedInRace = true; - break; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tithefarm/TitheFarmPlantOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/tithefarm/TitheFarmPlantOverlay.java index 5e39d3b452..288893d466 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tithefarm/TitheFarmPlantOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tithefarm/TitheFarmPlantOverlay.java @@ -34,7 +34,6 @@ import net.runelite.api.Client; import net.runelite.api.Perspective; import net.runelite.api.Point; 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.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; @@ -85,8 +84,6 @@ public class TitheFarmPlantOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - final Widget viewport = client.getViewportWidget(); - for (TitheFarmPlant plant : plugin.getPlants()) { if (plant.getState() == TitheFarmPlantState.DEAD) @@ -103,7 +100,7 @@ public class TitheFarmPlantOverlay extends Overlay final Point canvasLocation = Perspective.localToCanvas(client, localLocation, client.getPlane()); - if (viewport != null && canvasLocation != null) + if (canvasLocation != null) { final ProgressPieComponent progressPieComponent = new ProgressPieComponent(); progressPieComponent.setPosition(canvasLocation); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java index 2f0609bcfe..bf7498a25e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java @@ -36,11 +36,12 @@ import net.runelite.api.MenuEntry; import net.runelite.api.NPC; import net.runelite.api.NPCComposition; import net.runelite.api.ObjectComposition; +import net.runelite.api.ScriptID; import net.runelite.api.SpriteID; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.MenuEntryAdded; 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.widgets.JavaScriptCallback; import net.runelite.api.widgets.Widget; @@ -198,11 +199,12 @@ public class WikiPlugin extends Plugin } @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); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpProgressBarLabel.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpProgressBarLabel.java index 0f884135c7..35d19a63db 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpProgressBarLabel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpProgressBarLabel.java @@ -26,7 +26,9 @@ package net.runelite.client.plugins.xptracker; import lombok.AllArgsConstructor; import lombok.Getter; + import java.util.function.Function; + import static net.runelite.client.plugins.xptracker.XpInfoBox.TWO_DECIMAL_FORMAT; @Getter diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java index 405fe28080..151c5eae97 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java @@ -33,6 +33,7 @@ import javax.annotation.Nullable; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; +import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.plugins.Plugin; 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 OverlayPriority priority = OverlayPriority.NONE; private OverlayLayer layer = OverlayLayer.UNDER_WIDGETS; + private final List drawHooks = new ArrayList<>(); private final List menuEntries = new ArrayList<>(); private boolean resizable; private int minimumSize = 32; @@ -81,6 +83,16 @@ public abstract class Overlay implements LayoutableRenderableEntity 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() { } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayLayer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayLayer.java index ac75932ad6..35b72220f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayLayer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayLayer.java @@ -26,6 +26,12 @@ package net.runelite.client.ui.overlay; 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) */ @@ -45,9 +51,4 @@ public enum OverlayLayer * Render overlay above all game elements */ ALWAYS_ON_TOP, - - /** - * Render over the map, even when it's fullscreen - */ - ABOVE_MAP, } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java index 2cb0b1641e..6e3c770b37 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java @@ -25,21 +25,24 @@ package net.runelite.client.ui.overlay; 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.Point; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.EnumMap; import java.util.List; -import java.util.Map; import java.util.function.Predicate; import javax.inject.Inject; import javax.inject.Singleton; import lombok.AccessLevel; import lombok.Getter; +import lombok.Setter; import net.runelite.api.MenuAction; import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetItem; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigManager; @@ -66,13 +69,8 @@ public class OverlayManager @VisibleForTesting static final Comparator OVERLAY_COMPARATOR = (a, b) -> { - final OverlayPosition aPos = a.getPreferredPosition() != null - ? a.getPreferredPosition() - : a.getPosition(); - - final OverlayPosition bPos = b.getPreferredPosition() != null - ? b.getPreferredPosition() - : b.getPosition(); + final OverlayPosition aPos = MoreObjects.firstNonNull(a.getPreferredPosition(), a.getPosition()); + final OverlayPosition bPos = MoreObjects.firstNonNull(b.getPreferredPosition(), b.getPosition()); if (aPos != bPos) { @@ -84,7 +82,7 @@ public class OverlayManager // For dynamic overlays, higher priority means to // draw *later* so it is on top. // 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. return aPos == OverlayPosition.DYNAMIC ? a.getPriority().compareTo(b.getPriority()) @@ -98,9 +96,16 @@ public class OverlayManager @Getter(AccessLevel.PACKAGE) private final List overlays = new ArrayList<>(); @Getter - private final List itemWidgets = new ArrayList<>(); + @Setter + private Collection widgetItems = Collections.emptyList(); - private final Map> 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 overlayMap = ArrayListMultimap.create(); private final ConfigManager configManager; private final EventBus eventBus; @@ -143,12 +148,12 @@ public class OverlayManager event.consume(); - Overlay overlay = overlays.get(event.getType()); + Overlay overlay = overlays.get(event.getId()); if (overlay != null) { List menuEntries = overlay.getMenuEntries(); OverlayMenuEntry overlayMenuEntry = menuEntries.stream() - .filter(me -> me.getOption().equals(event.getOption())) + .filter(me -> me.getOption().equals(event.getMenuOption())) .findAny() .orElse(null); if (overlayMenuEntry != null) @@ -164,9 +169,19 @@ public class OverlayManager * @param layer the layer * @return An immutable list of all of the overlays on that layer */ - synchronized List getLayer(OverlayLayer layer) + Collection getLayer(OverlayLayer layer) { - return overlayLayers.get(layer); + return Collections.unmodifiableCollection(overlayMap.get(layer)); + } + + Collection getForInterface(int interfaceId) + { + return Collections.unmodifiableCollection(overlayMap.get(interfaceId << 16 | 0xffff)); + } + + Collection getForLayer(int layerId) + { + return Collections.unmodifiableCollection(overlayMap.get(layerId)); } /** @@ -282,11 +297,7 @@ public class OverlayManager synchronized void rebuildOverlayLayers() { - for (OverlayLayer l : OverlayLayer.values()) - { - overlayLayers.put(l, new ArrayList<>()); - } - + ArrayListMultimap overlayMap = ArrayListMultimap.create(); for (final Overlay overlay : overlays) { 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; + } + + for (int drawHook : overlay.getDrawHooks()) + { + overlayMap.put(drawHook, overlay); + } } - overlayLayers.forEach((layer, value) -> + for (Object key : overlayMap.keys()) { - value.sort(OVERLAY_COMPARATOR); - overlayLayers.put(layer, Collections.unmodifiableList(value)); - }); + overlayMap.get(key).sort(OVERLAY_COMPARATOR); + } + + this.overlayMap = overlayMap; } private void loadOverlay(final Overlay overlay) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java index 74987536fc..e1666d8b14 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java @@ -39,6 +39,8 @@ import java.awt.Stroke; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; +import java.util.Collection; +import java.util.Collections; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -48,11 +50,13 @@ import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.KeyCode; import net.runelite.api.MenuEntry; +import net.runelite.api.Varbits; import net.runelite.api.events.BeforeRender; import net.runelite.api.events.ClientTick; import net.runelite.api.events.FocusChanged; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetItem; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.input.KeyListener; @@ -98,10 +102,9 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener // Overlay state validation private Rectangle viewportBounds; private Rectangle chatboxBounds; - private int viewportOffset; private boolean chatboxHidden; private boolean isResizeable; - private OverlayBounds snapCorners; + private OverlayBounds emptySnapCorners, snapCorners; @Inject private OverlayRenderer( @@ -167,35 +170,51 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener public void onBeforeRender(BeforeRender event) { menuEntries = null; + + if (client.getGameState() == GameState.LOGGED_IN) + { + + if (shouldInvalidateBounds()) + { + emptySnapCorners = buildSnapCorners(); + } + + // Create copy of snap corners because overlays will modify them + snapCorners = new OverlayBounds(emptySnapCorners); + } } - public void render(Graphics2D graphics, final OverlayLayer layer) + public void renderOverlayLayer(Graphics2D graphics, final OverlayLayer layer) { - if (layer != OverlayLayer.ABOVE_MAP - && client.getWidget(WidgetInfo.FULLSCREEN_MAP_ROOT) != null - && !client.getWidget(WidgetInfo.FULLSCREEN_MAP_ROOT).isHidden()) - { - return; - } + final Collection overlays = overlayManager.getLayer(layer); + renderOverlays(graphics, overlays, layer); + } - final List overlays = overlayManager.getLayer(layer); + public void renderAfterInterface(Graphics2D graphics, int interfaceId, Collection widgetItems) + { + Collection 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 widgetItems) + { + Collection overlays = overlayManager.getForLayer(layer.getId()); + overlayManager.setWidgetItems(widgetItems); + renderOverlays(graphics, overlays, OverlayLayer.ABOVE_WIDGETS); + overlayManager.setWidgetItems(Collections.emptyList()); + } + + private void renderOverlays(Graphics2D graphics, Collection overlays, OverlayLayer layer) + { if (overlays == null || overlays.isEmpty() - || client.getGameState() != GameState.LOGGED_IN - || client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN) != null - || client.getViewportWidget() == null) + || client.getGameState() != GameState.LOGGED_IN) { return; } - if (shouldInvalidateBounds()) - { - snapCorners = buildSnapCorners(); - } - - // Create copy of snap corners because overlays will modify them - OverlayBounds snapCorners = new OverlayBounds(this.snapCorners); OverlayUtil.setGraphicProperties(graphics); // 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 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()) { @@ -795,43 +814,53 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener 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) { - viewportBounds = client.getViewportWidget().getBounds(); - changed = true; - } - - final boolean viewportOffsetChanged = client.getViewportXOffset() != viewportOffset; - - if (viewportOffsetChanged) - { - viewportOffset = client.getViewportXOffset(); + viewportBounds = viewport; changed = true; } 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() { final Point topLeftPoint = new Point( - viewportOffset + BORDER, - viewportOffset + BORDER_TOP); + viewportBounds.x + BORDER, + viewportBounds.y + BORDER_TOP); final Point topCenterPoint = new Point( - viewportOffset + viewportBounds.width / 2, - viewportOffset + BORDER + viewportBounds.x + viewportBounds.width / 2, + viewportBounds.y + BORDER ); final Point topRightPoint = new Point( - viewportOffset + viewportBounds.width - BORDER, + viewportBounds.x + viewportBounds.width - BORDER, topCenterPoint.y); final Point bottomLeftPoint = new Point( topLeftPoint.x, - viewportOffset + viewportBounds.height - BORDER); + viewportBounds.y + viewportBounds.height - BORDER); final Point bottomRightPoint = new Point( topRightPoint.x, @@ -844,7 +873,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener } final Point rightChatboxPoint = isResizeable ? new Point( - viewportOffset + chatboxBounds.width - BORDER, + viewportBounds.x + chatboxBounds.width - BORDER, bottomLeftPoint.y) : bottomRightPoint; final Point canvasTopRightPoint = isResizeable ? new Point( @@ -880,7 +909,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener entry.setOption(overlayMenuEntry.getOption()); entry.setTarget(ColorUtil.wrapWithColorTag(overlayMenuEntry.getTarget(), JagexColors.MENU_TARGET)); entry.setType(overlayMenuEntry.getMenuAction().getId()); - entry.setType(overlayManager.getOverlays().indexOf(overlay)); // overlay id + entry.setIdentifier(overlayManager.getOverlays().indexOf(overlay)); // overlay id entries[i] = entry; } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java index 295c1d618b..066c52402a 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java @@ -28,68 +28,49 @@ import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.Collection; import lombok.AccessLevel; import lombok.Setter; 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.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_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.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.SHOP_INVENTORY_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.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.WidgetInfo; import net.runelite.api.widgets.WidgetItem; public abstract class WidgetItemOverlay extends Overlay { @Setter(AccessLevel.PACKAGE) private OverlayManager overlayManager; - /** - * Interfaces to draw overlay over. - */ - private final Set interfaceGroups = new HashSet<>(); protected WidgetItemOverlay() { super.setPosition(OverlayPosition.DYNAMIC); 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 public Dimension render(Graphics2D graphics) { - final List itemWidgets = overlayManager.getItemWidgets(); + final Collection widgetItems = overlayManager.getWidgetItems(); final Rectangle originalClipBounds = graphics.getClipBounds(); Widget curClipParent = null; - for (WidgetItem widgetItem : itemWidgets) + for (WidgetItem widgetItem : widgetItems) { 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(); Rectangle parentBounds = parent.getBounds(); Rectangle itemCanvasBounds = widgetItem.getCanvasBounds(); @@ -151,7 +132,7 @@ public abstract class WidgetItemOverlay extends Overlay protected void showOnBank() { - showOnInterfaces(BANK_GROUP_ID); + drawAfterLayer(WidgetInfo.BANK_ITEM_CONTAINER); } protected void showOnEquipment() @@ -161,7 +142,7 @@ public abstract class WidgetItemOverlay extends Overlay 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 diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java index d5f57d6590..c1c1028375 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java @@ -80,6 +80,8 @@ public class WidgetOverlay extends Overlay setPriority(OverlayPriority.HIGHEST); setLayer(OverlayLayer.UNDER_WIDGETS); 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 diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java index b2a072a100..9e85df2edd 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java @@ -197,7 +197,7 @@ public class InfoBoxOverlay extends OverlayPanel InfoBox infoBox = hoveredComponent.getInfoBox(); OverlayMenuEntry overlayMenuEntry = infoBox.getMenuEntries().stream() - .filter(me -> me.getOption().equals(menuOptionClicked.getOption())) + .filter(me -> me.getOption().equals(menuOptionClicked.getMenuOption())) .findAny() .orElse(null); if (overlayMenuEntry != null) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java index 1f68a348f4..002af12c34 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java @@ -32,6 +32,7 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.Client; +import net.runelite.api.widgets.WidgetID; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.config.TooltipPositionType; import net.runelite.client.ui.overlay.Overlay; @@ -59,7 +60,9 @@ public class TooltipOverlay extends Overlay this.runeLiteConfig = runeLiteConfig; setPosition(OverlayPosition.TOOLTIP); 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 diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java index 7e301c8e61..8b2fc1d187 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java @@ -39,6 +39,7 @@ import net.runelite.api.Point; import net.runelite.api.RenderOverview; import net.runelite.api.coords.WorldPoint; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.input.MouseManager; import net.runelite.client.ui.FontManager; @@ -73,7 +74,8 @@ public class WorldMapOverlay extends Overlay this.worldMapPointManager = worldMapPointManager; setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGHEST); - setLayer(OverlayLayer.ABOVE_MAP); + setLayer(OverlayLayer.MANUAL); + drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID); mouseManager.registerMouseListener(worldMapOverlayMouseListener); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/skin/ObsidianSkin.java b/runelite-client/src/main/java/net/runelite/client/ui/skin/ObsidianSkin.java index 271d2127b9..92620713fc 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/skin/ObsidianSkin.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/skin/ObsidianSkin.java @@ -65,10 +65,7 @@ public class ObsidianSkin extends SubstanceSkin final SubstanceColorSchemeBundle defaultSchemeBundle = new SubstanceColorSchemeBundle( activeScheme, enabledScheme, enabledScheme); - //defaultSchemeBundle.registerColorScheme(enabledScheme, 0.6f, - // ComponentState.DISABLED_UNSELECTED); - //defaultSchemeBundle.registerColorScheme(activeScheme, 0.6f, - // ComponentState.DISABLED_SELECTED); + // borders final SubstanceColorScheme borderDisabledSelectedScheme = schemes @@ -82,9 +79,7 @@ public class ObsidianSkin extends SubstanceSkin final SubstanceColorScheme markActiveScheme = schemes.get("RuneLite Mark Active"); defaultSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK, ComponentState.getActiveStates()); - //defaultSchemeBundle.registerColorScheme(markActiveScheme, 0.6f, - // ColorSchemeAssociationKind.MARK, ComponentState.DISABLED_SELECTED, - // ComponentState.DISABLED_UNSELECTED); + // separators final SubstanceColorScheme separatorScheme = schemes.get("RuneLite Separator"); @@ -102,8 +97,7 @@ public class ObsidianSkin extends SubstanceSkin final SubstanceColorSchemeBundle decorationsSchemeBundle = new SubstanceColorSchemeBundle( activeScheme, enabledScheme, enabledScheme); - //decorationsSchemeBundle.registerColorScheme(enabledScheme, 0.5f, - // ComponentState.DISABLED_UNSELECTED); + // borders decorationsSchemeBundle.registerColorScheme(borderDisabledSelectedScheme, @@ -129,8 +123,7 @@ public class ObsidianSkin extends SubstanceSkin final SubstanceColorSchemeBundle headerSchemeBundle = new SubstanceColorSchemeBundle(activeScheme, enabledScheme, enabledScheme); - //headerSchemeBundle.registerColorScheme(enabledScheme, 0.5f, - // ComponentState.DISABLED_UNSELECTED); + // borders final SubstanceColorScheme headerBorderScheme = schemes.get("RuneLite Header Border"); @@ -142,14 +135,6 @@ public class ObsidianSkin extends SubstanceSkin headerSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK, 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"); this.registerDecorationAreaSchemeBundle(headerSchemeBundle, headerWatermarkScheme, diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java index 8893d234df..6c080ff8b8 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -594,7 +594,7 @@ public abstract class RSClientMixin implements RSClient @Override 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 @@ -1552,16 +1552,16 @@ public abstract class RSClientMixin implements RSClient if (renderX >= minX && renderX <= maxX && renderY >= minY && renderY <= maxY) { 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) { - Collection widgetItems = widget.getWidgetItems(); - for (WidgetItem widgetItem : widgetItems) - { - callbacks.drawItem(widgetItem.getId(), widgetItem); - } + + List widgetItems = widget.getWidgetItems(); + //TODO:IMPLEMENT + //callbacks.drawLayer(rlWidget, widgetItems); } WidgetNode childNode = componentTable.get(widget.getId()); @@ -1579,6 +1579,10 @@ public abstract class RSClientMixin implements RSClient } } } + else + { + + } } } diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java index 837c7fef53..29a0755358 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java @@ -50,7 +50,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; 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; @Mixin(RSWidget.class) @@ -107,7 +107,7 @@ public abstract class RSWidgetMixin implements RSWidget return null; } - return client.getWidget(TO_GROUP(id), getChildFromID(id)); + return client.getWidget(TO_GROUP(id), TO_CHILD(id)); } @Inject @@ -240,7 +240,7 @@ public abstract class RSWidgetMixin implements RSWidget @Inject @Override - public Collection getWidgetItems() + public List getWidgetItems() { int[] itemIds = getItemIds();