From 195b4a94dd390176b53fdd279a7f22cf557c8219 Mon Sep 17 00:00:00 2001 From: ThatGamerBlue Date: Fri, 19 Feb 2021 15:00:07 +0000 Subject: [PATCH] make injected client java8-compliant, dumb mixin --- .../java/com/openosrs/injector/Injector.java | 3 + .../injectors/rsapi/InjectInvoke.java | 5 + .../injector/transformers/Java8Ifier.java | 101 ++++++++++++++++++ .../net/runelite/mixins/RSClientMixin.java | 59 +++++----- .../net/runelite/rs/api/RSEnumerated.java | 8 +- .../java/net/runelite/rs/api/RSWidget.java | 3 + .../net/runelite/rs/api/RSWidgetFillMode.java | 29 +++++ runescape-client/src/main/java/NetSocket.java | 4 +- runescape-client/src/main/java/Widget.java | 4 +- .../{class333.java => WidgetFillMode.java} | 6 +- .../src/main/java/WorldMapData_1.java | 2 +- 11 files changed, 186 insertions(+), 38 deletions(-) create mode 100644 injector/src/main/java/com/openosrs/injector/transformers/Java8Ifier.java create mode 100644 runescape-api/src/main/java/net/runelite/rs/api/RSWidgetFillMode.java rename runescape-client/src/main/java/{class333.java => WidgetFillMode.java} (85%) diff --git a/injector/src/main/java/com/openosrs/injector/Injector.java b/injector/src/main/java/com/openosrs/injector/Injector.java index 08294eb0d1..e83ee1ce0b 100644 --- a/injector/src/main/java/com/openosrs/injector/Injector.java +++ b/injector/src/main/java/com/openosrs/injector/Injector.java @@ -23,6 +23,7 @@ import com.openosrs.injector.injectors.raw.RenderDraw; import com.openosrs.injector.injectors.raw.ScriptVM; import com.openosrs.injector.rsapi.RSApi; import com.openosrs.injector.transformers.InjectTransformer; +import com.openosrs.injector.transformers.Java8Ifier; import com.openosrs.injector.transformers.SourceChanger; import static net.runelite.deob.util.JarUtil.load; import static net.runelite.deob.util.JarUtil.save; @@ -57,6 +58,8 @@ public class Injector extends InjectData implements InjectTaskHandler { log.debug("[DEBUG] Starting injection"); + transform(new Java8Ifier(this)); + inject(new CreateAnnotations(this)); inject(new InterfaceInjector(this)); diff --git a/injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectInvoke.java b/injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectInvoke.java index 61a273d673..b87e6385ad 100644 --- a/injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectInvoke.java +++ b/injector/src/main/java/com/openosrs/injector/injectors/rsapi/InjectInvoke.java @@ -43,6 +43,7 @@ import net.runelite.asm.attributes.code.Instructions; import net.runelite.asm.attributes.code.instructions.ALoad; import net.runelite.asm.attributes.code.instructions.BiPush; import net.runelite.asm.attributes.code.instructions.CheckCast; +import net.runelite.asm.attributes.code.instructions.InvokeInterface; import net.runelite.asm.attributes.code.instructions.InvokeStatic; import net.runelite.asm.attributes.code.instructions.InvokeVirtual; import net.runelite.asm.attributes.code.instructions.LDC; @@ -131,6 +132,10 @@ public class InjectInvoke { ins.add(new InvokeStatic(instructions, vanillaMethod.getPoolMethod())); } + else if (vanillaMethod.getClassFile().isInterface()) + { + ins.add(new InvokeInterface(instructions, vanillaMethod.getPoolMethod())); + } else { ins.add(new InvokeVirtual(instructions, vanillaMethod.getPoolMethod())); diff --git a/injector/src/main/java/com/openosrs/injector/transformers/Java8Ifier.java b/injector/src/main/java/com/openosrs/injector/transformers/Java8Ifier.java new file mode 100644 index 0000000000..9d5e981d3f --- /dev/null +++ b/injector/src/main/java/com/openosrs/injector/transformers/Java8Ifier.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2020, ThatGamerBlue + * All rights reserved. + * + * This code is licensed under GPL3, see the complete license in + * the LICENSE file in the root directory of this source tree. + */ +package com.openosrs.injector.transformers; + +import com.openosrs.injector.InjectException; +import com.openosrs.injector.injection.InjectData; +import java.util.ListIterator; +import net.runelite.asm.ClassFile; +import net.runelite.asm.Method; +import net.runelite.asm.attributes.Code; +import net.runelite.asm.attributes.code.Exception; +import net.runelite.asm.attributes.code.Instruction; +import net.runelite.asm.attributes.code.Instructions; +import net.runelite.asm.attributes.code.Label; +import net.runelite.asm.attributes.code.instructions.InvokeSpecial; +import org.objectweb.asm.Opcodes; + +public class Java8Ifier extends InjectTransformer +{ + public Java8Ifier(InjectData inject) + { + super(inject); + } + + @Override + void transformImpl() + { + inject.forEachPair(this::makeJava8); + } + + private void makeJava8(ClassFile rsc, ClassFile vanilla) + { + vanilla.setVersion(Opcodes.V1_8); + for (Method method : vanilla.getMethods()) + { + if (!method.getName().equals("")) + { + continue; + } + + fixTryCatch(method); + } + } + + private void fixTryCatch(Method method) + { + Code code = method.getCode(); + + if (code.getExceptions().getExceptions().stream().noneMatch(e -> e.getCatchType() != null && e.getCatchType().getName().equals("java/lang/RuntimeException"))) + { + return; + } + + Instructions instructions = code.getInstructions(); + ListIterator insnIt = instructions.listIterator(); + Instruction insn; + Label firstLabel = null; + Label injectedLabel = null; + while (insnIt.hasNext()) + { + insn = insnIt.next(); + + if (firstLabel == null && insn instanceof Label) + { + firstLabel = (Label) insn; + } + else if (insn instanceof InvokeSpecial) + { + if (((InvokeSpecial) insn).getMethod().getName().equals("")) + { + injectedLabel = new Label(instructions); + insnIt.add(injectedLabel); + break; + } + } + } + + // this should never happen + if (firstLabel == null) + { + throw new InjectException("Label missing from ctor " + method.toString() + " even though exception exists"); + } + + // label was injected + if (injectedLabel != null) + { + for (Exception ex : code.getExceptions().getExceptions()) + { + if (ex.getStart().equals(firstLabel)) + { + ex.setStart(injectedLabel); + } + } + } + } +} \ No newline at end of file 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 9aac7b9a67..7c2bf5c580 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -52,6 +52,8 @@ import net.runelite.api.IndexedSprite; import net.runelite.api.IntegerNode; import net.runelite.api.InventoryID; import net.runelite.api.ItemComposition; +import net.runelite.api.MenuAction; +import static net.runelite.api.MenuAction.*; import net.runelite.api.MenuEntry; import net.runelite.api.MenuAction; import static net.runelite.api.MenuAction.PLAYER_EIGTH_OPTION; @@ -1538,12 +1540,11 @@ public abstract class RSClientMixin implements RSClient @Inject public static void preRenderWidgetLayer(Widget[] widgets, int parentId, int minX, int minY, int maxX, int maxY, int x, int y, int var8) { - Callbacks callbacks = client.getCallbacks(); @SuppressWarnings("unchecked") HashTable componentTable = client.getComponentTable(); - for (Widget rlWidget : widgets) + for (int i = 0; i < widgets.length; i++) { - RSWidget widget = (RSWidget) rlWidget; + RSWidget widget = (RSWidget) widgets[i]; if (widget == null || widget.getRSParentId() != parentId || widget.isSelfHidden()) { continue; @@ -1559,38 +1560,36 @@ public abstract class RSClientMixin implements RSClient widget.setRenderX(renderX); widget.setRenderY(renderY); - if (widget.getType() == WidgetType.RECTANGLE) + if (widget.getType() == WidgetType.RECTANGLE && renderX == client.getViewportXOffset() && renderY == client.getViewportYOffset() + && widget.getWidth() == client.getViewportWidth() && widget.getHeight() == client.getViewportHeight() + && widget.getOpacity() > 0 && widget.isFilled() && widget.getFillMode().getOrdinal() == 0 && client.isGpu()) { - if (renderX == client.getViewportXOffset() && renderY == client.getViewportYOffset() - && widget.getWidth() == client.getViewportWidth() && widget.getHeight() == client.getViewportHeight() - && widget.getOpacity() > 0 && widget.isFilled() && client.isGpu()) - { - int tc = widget.getTextColor(); - int alpha = widget.getOpacity() & 0xFF; - int inverseAlpha = 256 - alpha; - int vpc = viewportColor; - int c1 = (alpha * (tc & 0xff00ff) >> 8 & 0xFF00FF) + (alpha * (tc & 0x00FF00) >> 8 & 0x00FF00); - int c2 = (inverseAlpha * (vpc & 0xff00ff) >> 8 & 0xFF00FF) + (inverseAlpha * (vpc & 0x00FF00) >> 8 & 0x00FF00); - int outAlpha = inverseAlpha + ((vpc >>> 24) * (255 - alpha) * 0x8081 >>> 23); - viewportColor = outAlpha << 24 | c1 + c2; - widget.setHidden(true); - hiddenWidgets.add(widget); - continue; - } + int tc = widget.getTextColor(); + int alpha = widget.getOpacity() & 0xFF; + int inverseAlpha = 256 - alpha; + int vpc = viewportColor; + int c1 = (inverseAlpha * (tc & 0xFF00FF) >> 8 & 0xFF00FF) + (inverseAlpha * (tc & 0x00FF00) >> 8 & 0x00FF00); + int c2 = (alpha * (vpc & 0xFF00FF) >> 8 & 0xFF00FF) + (alpha * (vpc & 0x00FF00) >> 8 & 0x00FF00); + int outAlpha = inverseAlpha + ((vpc >>> 24) * (255 - inverseAlpha) * 0x8081 >>> 23); + viewportColor = outAlpha << 24 | c1 + c2; + widget.setHidden(true); + hiddenWidgets.add(widget); } - - WidgetNode childNode = componentTable.get(widget.getId()); - if (childNode != null) + else { - int widgetId = widget.getId(); - int groupId = childNode.getId(); - RSWidget[] children = client.getWidgets()[groupId]; - - for (RSWidget child : children) + WidgetNode childNode = componentTable.get(widget.getId()); + if (childNode != null) { - if (child.getRSParentId() == -1) + int widgetId = widget.getId(); + int groupId = childNode.getId(); + RSWidget[] children = client.getWidgets()[groupId]; + + for (RSWidget child : children) { - child.setRenderParentId(widgetId); + if (child.getRSParentId() == -1) + { + child.setRenderParentId(widgetId); + } } } } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSEnumerated.java b/runescape-api/src/main/java/net/runelite/rs/api/RSEnumerated.java index 1b97cfebc9..3189893968 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSEnumerated.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSEnumerated.java @@ -1,3 +1,9 @@ package net.runelite.rs.api; -public interface RSEnumerated {} +import net.runelite.mapping.Import; + +public interface RSEnumerated +{ + @Import("rsOrdinal") + int getOrdinal(); +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java index 57546ccfe4..9f22cac637 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java @@ -589,5 +589,8 @@ public interface RSWidget extends Widget @Override void setOnVarTransmitListener(Object[] o); + @Import("fillMode") + RSWidgetFillMode getFillMode(); + void broadcastHidden(boolean hidden); } \ No newline at end of file diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWidgetFillMode.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWidgetFillMode.java new file mode 100644 index 0000000000..14495522a4 --- /dev/null +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWidgetFillMode.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021, ThatGamerBlue + * 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.rs.api; + +public interface RSWidgetFillMode extends RSEnumerated +{ +} diff --git a/runescape-client/src/main/java/NetSocket.java b/runescape-client/src/main/java/NetSocket.java index dfc77db500..c872bafa17 100644 --- a/runescape-client/src/main/java/NetSocket.java +++ b/runescape-client/src/main/java/NetSocket.java @@ -333,8 +333,8 @@ public final class NetSocket extends AbstractSocket implements Runnable { garbageValue = "8" ) @Export("FillMode_values") - public static class333[] FillMode_values() { - return new class333[]{class333.field3897, class333.field3898, class333.SOLID}; // L: 15 + public static WidgetFillMode[] FillMode_values() { + return new WidgetFillMode[]{WidgetFillMode.field3897, WidgetFillMode.field3898, WidgetFillMode.SOLID}; // L: 15 } @ObfuscatedName("gh") diff --git a/runescape-client/src/main/java/Widget.java b/runescape-client/src/main/java/Widget.java index 0f8b51840e..c25c1e7d78 100644 --- a/runescape-client/src/main/java/Widget.java +++ b/runescape-client/src/main/java/Widget.java @@ -213,7 +213,7 @@ public class Widget extends Node { descriptor = "Llj;" ) @Export("fillMode") - public class333 fillMode; + public WidgetFillMode fillMode; @ObfuscatedName("ar") @ObfuscatedGetter( intValue = -318915915 @@ -711,7 +711,7 @@ public class Widget extends Node { this.mouseOverColor = 0; this.mouseOverColor2 = 0; this.fill = false; - this.fillMode = class333.SOLID; + this.fillMode = WidgetFillMode.SOLID; this.transparencyTop = 0; this.transparencyBot = 0; this.lineWid = 1; diff --git a/runescape-client/src/main/java/class333.java b/runescape-client/src/main/java/WidgetFillMode.java similarity index 85% rename from runescape-client/src/main/java/class333.java rename to runescape-client/src/main/java/WidgetFillMode.java index 0ab3733dad..d7651a784f 100644 --- a/runescape-client/src/main/java/class333.java +++ b/runescape-client/src/main/java/WidgetFillMode.java @@ -1,10 +1,12 @@ import net.runelite.mapping.Export; +import net.runelite.mapping.Implements; import net.runelite.mapping.ObfuscatedGetter; import net.runelite.mapping.ObfuscatedName; import net.runelite.mapping.ObfuscatedSignature; @ObfuscatedName("lj") -public enum class333 implements Enumerated { +@Implements("WidgetFillMode") +public enum WidgetFillMode implements Enumerated { @ObfuscatedName("h") @ObfuscatedSignature( descriptor = "Llj;" @@ -33,7 +35,7 @@ public enum class333 implements Enumerated { ) final int field3900; - class333(int var3, int var4) { + WidgetFillMode(int var3, int var4) { this.field3902 = var3; // L: 19 this.field3900 = var4; // L: 20 } // L: 21 diff --git a/runescape-client/src/main/java/WorldMapData_1.java b/runescape-client/src/main/java/WorldMapData_1.java index 40ccbef1e6..346b7c4c0c 100644 --- a/runescape-client/src/main/java/WorldMapData_1.java +++ b/runescape-client/src/main/java/WorldMapData_1.java @@ -340,7 +340,7 @@ public class WorldMapData_1 extends AbstractWorldMapData { return 1; // L: 708 } else if (var0 == ScriptOpcodes.CC_SETFILLMODE) { // L: 710 var8 = Interpreter.Interpreter_intStack[--VarcInt.Interpreter_intStackSize]; // L: 711 - class333 var6 = (class333)UrlRequester.findEnumerated(NetSocket.FillMode_values(), var8); // L: 712 + WidgetFillMode var6 = (WidgetFillMode)UrlRequester.findEnumerated(NetSocket.FillMode_values(), var8); // L: 712 if (var6 != null) { // L: 713 var3.fillMode = var6; // L: 714 CollisionMap.invalidateWidget(var3); // L: 715