diff --git a/runelite-api/src/main/java/net/runelite/api/AnimationID.java b/runelite-api/src/main/java/net/runelite/api/AnimationID.java index 0d4350fbcf..59c61ab497 100644 --- a/runelite-api/src/main/java/net/runelite/api/AnimationID.java +++ b/runelite-api/src/main/java/net/runelite/api/AnimationID.java @@ -205,6 +205,7 @@ public final class AnimationID public static final int LEAGUE_HOME_TELEPORT_5 = 8805; public static final int LEAGUE_HOME_TELEPORT_6 = 8807; public static final int RAID_LIGHT_ANIMATION = 3101; + public static final int LOOTBEAM_ANIMATION = 9260; public static final int CONSTRUCTION = 3676; public static final int CONSTRUCTION_IMCANDO = 8912; diff --git a/runelite-api/src/main/java/net/runelite/api/JagexColor.java b/runelite-api/src/main/java/net/runelite/api/JagexColor.java index 618ed002fa..1175f194e7 100644 --- a/runelite-api/src/main/java/net/runelite/api/JagexColor.java +++ b/runelite-api/src/main/java/net/runelite/api/JagexColor.java @@ -28,11 +28,35 @@ import java.awt.Color; public final class JagexColor { + public static final int HUE_MAX = 63; + public static final int SATURATION_MAX = 7; + public static final int LUMINANCE_MAX = 127; + public static short packHSL(int hue, int saturation, int luminance) { - return (short) ((short) (hue & 63) << 10 - | (short) (saturation & 7) << 7 - | (short) (luminance & 127)); + return (short) ((short) (hue & HUE_MAX) << 10 + | (short) (saturation & SATURATION_MAX) << 7 + | (short) (luminance & LUMINANCE_MAX)); + } + + public static int unpackHue(short hsl) + { + return hsl >> 10 & HUE_MAX; + } + + public static int unpackSaturation(short hsl) + { + return hsl >> 7 & SATURATION_MAX; + } + + public static int unpackLuminance(short hsl) + { + return hsl & LUMINANCE_MAX; + } + + public static String formatHSL(short hsl) + { + return String.format("%02Xh%Xs%02Xl", unpackHue(hsl), unpackSaturation(hsl), unpackLuminance(hsl)); } public static short rgbToHSL(int rgb, double brightness) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java index 2e32a8e336..5869c07208 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -436,4 +436,15 @@ public interface GroundItemsConfig extends Config { return HighlightTier.HIGH; } + + @ConfigItem( + keyName = "lootbeamStyle", + name = "Lootbeam Style", + description = "Style of lootbeam to use", + position = 32 + ) + default Lootbeam.Style lootbeamStyle() + { + return Lootbeam.Style.MODERN; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java index 773fd8b044..af5282db14 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java @@ -99,7 +99,7 @@ import net.runelite.client.util.Text; @PluginDescriptor( name = "Ground Items", description = "Highlight ground items and/or show price information", - tags = {"grand", "exchange", "high", "alchemy", "prices", "highlight", "overlay"} + tags = {"grand", "exchange", "high", "alchemy", "prices", "highlight", "overlay", "lootbeam"} ) public class GroundItemsPlugin extends Plugin { @@ -791,12 +791,13 @@ public class GroundItemsPlugin extends Plugin Lootbeam lootbeam = lootbeams.get(worldPoint); if (lootbeam == null) { - lootbeam = new Lootbeam(client, clientThread, worldPoint, color); + lootbeam = new Lootbeam(client, clientThread, worldPoint, color, config.lootbeamStyle()); lootbeams.put(worldPoint, lootbeam); } else { lootbeam.setColor(color); + lootbeam.setStyle(config.lootbeamStyle()); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java index 9e8761a93f..96d7d34409 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java @@ -24,10 +24,14 @@ */ package net.runelite.client.plugins.grounditems; +import java.util.function.Function; +import lombok.RequiredArgsConstructor; +import net.runelite.api.Animation; import net.runelite.api.AnimationID; import net.runelite.api.Client; import net.runelite.api.JagexColor; import net.runelite.api.Model; +import net.runelite.api.ModelData; import net.runelite.api.RuneLiteObject; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; @@ -36,22 +40,58 @@ import net.runelite.client.callback.ClientThread; class Lootbeam { - private static final int RAID_LIGHT_MODEL = 5809; - private static final short RAID_LIGHT_FIND_COLOR = 6371; - private final RuneLiteObject runeLiteObject; private final Client client; private final ClientThread clientThread; private Color color; + private Style style; - public Lootbeam(Client client, ClientThread clientThread, WorldPoint worldPoint, Color color) + @RequiredArgsConstructor + public enum Style + { + LIGHT(l -> l.client.loadModel( + 5809, + new short[]{6371}, + new short[]{JagexColor.rgbToHSL(l.color.getRGB(), 1.0d)} + ), anim(AnimationID.RAID_LIGHT_ANIMATION)), + MODERN(l -> + { + ModelData md = l.client.loadModelData(43330); + if (md == null) + { + return null; + } + + short hsl = JagexColor.rgbToHSL(l.color.getRGB(), 1.0d); + int hue = JagexColor.unpackHue(hsl); + int sat = Math.min(JagexColor.unpackSaturation(hsl) + 1, JagexColor.SATURATION_MAX); + int lum = JagexColor.unpackLuminance(hsl); + + return md.cloneColors() + .recolor((short) 26432, JagexColor.packHSL(hue, sat, Math.min(lum + 12, JagexColor.LUMINANCE_MAX))) + .recolor((short) 26584, JagexColor.packHSL(hue, sat - 1, Math.max(lum - 12, 0))) + .light(75, 1875, ModelData.DEFAULT_X, ModelData.DEFAULT_Y, ModelData.DEFAULT_Z); + }, anim(AnimationID.LOOTBEAM_ANIMATION)), + ; + + private final Function modelSupplier; + private final Function animationSupplier; + } + + private static Function anim(int id) + { + return b -> b.client.loadAnimation(id); + } + + public Lootbeam(Client client, ClientThread clientThread, WorldPoint worldPoint, Color color, Style style) { this.client = client; this.clientThread = clientThread; runeLiteObject = client.createRuneLiteObject(); - setColor(color); - runeLiteObject.setAnimation(client.loadAnimation(AnimationID.RAID_LIGHT_ANIMATION)); + this.color = color; + this.style = style; + update(); runeLiteObject.setShouldLoop(true); LocalPoint lp = LocalPoint.fromWorld(client, worldPoint); @@ -68,19 +108,34 @@ class Lootbeam } this.color = color; + update(); + } + + public void setStyle(Style style) + { + if (this.style == style) + { + return; + } + + this.style = style; + update(); + } + + private void update() + { clientThread.invoke(() -> { - Model m = client.loadModel( - RAID_LIGHT_MODEL, - new short[]{RAID_LIGHT_FIND_COLOR}, - new short[]{JagexColor.rgbToHSL(color.getRGB(), 1.0d)} - ); - if (m == null) + Model model = style.modelSupplier.apply(this); + if (model == null) { return false; } - runeLiteObject.setModel(m); + Animation anim = style.animationSupplier.apply(this); + + runeLiteObject.setAnimation(anim); + runeLiteObject.setModel(model); return true; }); }