Merge branch 'master' into spawn

This commit is contained in:
James
2019-10-28 12:04:28 -07:00
committed by GitHub
79 changed files with 2634 additions and 1045 deletions

View File

@@ -1,118 +0,0 @@
import org.apache.tools.ant.filters.ReplaceTokens
import java.text.SimpleDateFormat
plugins {
id 'com.github.johnrengelman.shadow' version '5.1.0'
id 'java'
}
description = 'RuneLite Client'
dependencies {
annotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombok
compileOnly group: 'javax.annotation', name: 'javax.annotation-api', version: javax
compileOnly group: 'net.runelite', name: 'orange-extensions', version: orangeExtensions
compileOnly group: 'org.projectlombok', name: 'lombok', version: lombok
implementation group: 'ch.qos.logback', name: 'logback-classic', version: logback
implementation group: 'com.google.code.gson', name: 'gson', version: gson
implementation group: 'com.google.guava', name: 'guava', version: guava
implementation group: 'com.google.inject', name: 'guice', version: guice, classifier: 'no_aop'
implementation group: 'com.h2database', name: 'h2', version: h2
implementation group: 'com.jakewharton.rxrelay2', name: 'rxrelay', version: rxrelay
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: okhttp3
implementation group: 'io.reactivex.rxjava2', name: 'rxjava', version: rxjava
implementation group: 'net.java.dev.jna', name: 'jna', version: jna
implementation group: 'net.java.dev.jna', name: 'jna-platform', version: jna
implementation group: 'net.runelite', name: 'discord', version: discord
implementation group: 'net.runelite.pushingpixels', name: 'substance', version: substance
implementation group: 'net.sf.jopt-simple', name: 'jopt-simple', version: jopt
implementation group: 'org.apache.commons', name: 'commons-text', version: apacheCommonsText
implementation group: 'org.apache.httpcomponents', name: 'httpcore', version: httpcore
implementation group: 'org.apache.httpcomponents', name: 'httpmime', version: httpmime
implementation group: 'org.codehaus.plexus', name: 'plexus-utils', version: plexus
implementation group: 'org.javassist', name: 'javassist', version: javassist
implementation group: 'org.jetbrains', name: 'annotations', version: annotations
implementation group: 'org.jogamp.gluegen', name: 'gluegen-rt', version: jogamp
implementation group: 'org.jogamp.jogl', name: 'jogl-all', version: jogamp
implementation group: 'org.jooq', name: 'jooq', version: jooq
implementation group: 'org.jooq', name: 'jooq-codegen', version: jooq
implementation group: 'org.jooq', name: 'jooq-meta', version: jooq
implementation group: 'org.ow2.asm', name: 'asm-tree', version: asm
implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4j
implementation group: 'org.xeustechnologies', name: 'jcl-core', version: jclCore
implementation project(':http-api')
implementation project(':runelite-api')
implementation(group: 'io.sigpipe', name: 'jbsdiff', version: jbsdiff) {
exclude(module: 'xz')
}
implementation group: 'com.github.joonasvali.naturalmouse', name: 'naturalmouse', version: '2.0.2'
runtime group: 'net.runelite.pushingpixels', name: 'trident', version: trident
runtime group: 'org.jogamp.gluegen', name: 'gluegen-rt', version: jogamp, classifier: 'natives-linux-amd64'
runtime group: 'org.jogamp.gluegen', name: 'gluegen-rt', version: jogamp, classifier: 'natives-linux-i586'
runtime group: 'org.jogamp.gluegen', name: 'gluegen-rt', version: jogamp, classifier: 'natives-windows-amd64'
runtime group: 'org.jogamp.gluegen', name: 'gluegen-rt', version: jogamp, classifier: 'natives-windows-i586'
runtime group: 'org.jogamp.jogl', name: 'jogl-all', version: jogamp, classifier: 'natives-linux-amd64'
runtime group: 'org.jogamp.jogl', name: 'jogl-all', version: jogamp, classifier: 'natives-linux-i586'
runtime group: 'org.jogamp.jogl', name: 'jogl-all', version: jogamp, classifier: 'natives-windows-amd64'
runtime group: 'org.jogamp.jogl', name: 'jogl-all', version: jogamp, classifier: 'natives-windows-i586'
runtime project(':injected-client')
runtime project(':runescape-api')
testAnnotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombok
testCompileOnly group: 'org.projectlombok', name: 'lombok', version: lombok
testImplementation group: 'com.google.inject.extensions', name: 'guice-grapher', version: guice
testImplementation group: 'com.google.inject.extensions', name: 'guice-testlib', version: guice
testImplementation group: 'junit', name: 'junit', version: junit
testImplementation group: 'org.hamcrest', name: 'hamcrest-library', version: hamcrest
testImplementation group: 'org.mockito', name: 'mockito-core', version: mockito
testImplementation group: 'org.mockito', name: 'mockito-inline', version: mockito
testImplementation group: 'org.slf4j', name: 'slf4j-api', version: slf4j
}
static def getDate() {
return new SimpleDateFormat("MM-dd-yyyy", Locale.forLanguageTag("en-US")).format(new Date())
}
def buildDate = getDate()
processResources {
from file("src/main/resources/open.osrs.properties"), {
filter(ReplaceTokens, tokens: [
"project.version": project.version,
"rs.version": rsversion.toString(),
"open.osrs.version": plusVersion.toString(),
"open.osrs.builddate": buildDate.toString(),
"launcher.version": launcherVersion.toString()
])
}
}
tasks.withType(AbstractArchiveTask) {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
jar {
manifest {
attributes 'Main-Class': 'net.runelite.client.RuneLite'
}
}
shadowJar {
archiveClassifier.set("shaded")
exclude("net/runelite/injector/**")
}
task dependencyReportFile(type: DependencyReportTask) {
outputFile = file('dependencies.txt')
Set configs = [project.configurations.runtimeClasspath]
setConfigurations(configs)
}
tasks.build.dependsOn tasks.shadowJar
tasks.shadowJar.dependsOn tasks.dependencyReportFile

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2019 Owain van Brakel <https://github.com/Owain94>
* 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.
*/
import org.apache.tools.ant.filters.ReplaceTokens
import java.util.Date
import java.text.SimpleDateFormat
buildscript {
dependencies {
classpath(gradleApi())
}
}
plugins {
id(Plugins.shadow.first) version Plugins.shadow.second
java
}
description = "RuneLite Client"
dependencies {
annotationProcessor(Libraries.lombok)
compileOnly(Libraries.javax)
compileOnly(Libraries.orangeExtensions)
compileOnly(Libraries.lombok)
implementation(Libraries.logback)
implementation(Libraries.gson)
implementation(Libraries.guava)
implementation(Libraries.guice)
implementation(Libraries.h2)
implementation(Libraries.rxrelay)
implementation(Libraries.okhttp3)
implementation(Libraries.rxjava)
implementation(Libraries.jna)
implementation(Libraries.jnaPlatform)
implementation(Libraries.discord)
implementation(Libraries.substance)
implementation(Libraries.jopt)
implementation(Libraries.apacheCommonsText)
implementation(Libraries.httpcore)
implementation(Libraries.httpmime)
implementation(Libraries.plexus)
implementation(Libraries.javassist)
implementation(Libraries.annotations)
implementation(Libraries.jogampGluegen)
implementation(Libraries.jogampJogl)
implementation(Libraries.jooq)
implementation(Libraries.jooqCodegen)
implementation(Libraries.jooqMeta)
implementation(Libraries.asmTree)
implementation(Libraries.slf4jApi)
implementation(Libraries.jclCore)
implementation(project(":http-api"))
implementation(project(":runelite-api"))
implementation(Libraries.jbsdiff) {
exclude(module = "xz")
}
implementation(Libraries.naturalMouse)
runtime(Libraries.trident)
runtime(Libraries.jogampGluegenLinuxAmd64)
runtime(Libraries.jogampGluegenLinuxI586)
runtime(Libraries.jogampGluegenWindowsAmd64)
runtime(Libraries.jogampGluegenWindowsI586)
runtime(Libraries.jogampJoglLinuxAmd64)
runtime(Libraries.jogampJoglLinuxI586)
runtime(Libraries.jogampJoglWindowsAmd64)
runtime(Libraries.jogampJoglWindowsI586)
runtime(project(":injected-client"))
runtime(project(":runescape-api"))
testAnnotationProcessor(Libraries.lombok)
testCompileOnly(Libraries.lombok)
testImplementation(Libraries.guiceGrapher)
testImplementation(Libraries.guiceTestlib)
testImplementation(Libraries.junit)
testImplementation(Libraries.hamcrest)
testImplementation(Libraries.mockitoCore)
testImplementation(Libraries.mockitoInline)
testImplementation(Libraries.slf4jApi)
}
fun formatDate(date: Date?) = with(date ?: Date()) {
SimpleDateFormat("MM-dd-yyyy").format(this)
}
tasks {
register<DependencyReportTask>("dependencyReportFile") {
outputFile = file("dependencies.txt")
setConfiguration("runtimeClasspath")
}
build {
finalizedBy("shadowJar")
}
"processResources"(ProcessResources::class) {
val tokens = mapOf(
"project.version" to ProjectVersions.rlVersion,
"rs.version" to ProjectVersions.rsversion.toString(),
"open.osrs.version" to ProjectVersions.openosrsVersion,
"open.osrs.builddate" to formatDate(Date()),
"launcher.version" to ProjectVersions.launcherVersion
)
inputs.properties(tokens)
from("src/main/resources") {
include("open.osrs.properties")
filter<ReplaceTokens>("tokens" to tokens)
}
}
jar {
manifest {
attributes(mutableMapOf("Main-Class" to "net.runelite.client.RuneLite"))
}
}
shadowJar {
dependsOn("dependencyReportFile")
archiveClassifier.set("shaded")
exclude("net/runelite/injector/**")
}
}

View File

@@ -59,6 +59,7 @@ import net.runelite.client.eventbus.EventBus;
import net.runelite.client.game.ClanManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.LootManager;
import net.runelite.client.game.XpDropManager;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.graphics.ModelOutlineRenderer;
import net.runelite.client.menus.MenuManager;
@@ -151,6 +152,9 @@ public class RuneLite
@Inject
private Provider<LootManager> lootManager;
@Inject
private Provider<XpDropManager> xpDropManager;
@Inject
private Provider<ChatboxPanelManager> chatboxPanelManager;
@@ -368,6 +372,7 @@ public class RuneLite
chatMessageManager.get();
commandManager.get();
lootManager.get();
xpDropManager.get();
chatboxPanelManager.get();
eventBus.subscribe(GameStateChanged.class, this, hooks::onGameStateChanged);

View File

@@ -61,9 +61,27 @@ import net.runelite.client.events.PlayerLootReceived;
@Slf4j
public class LootManager
{
private static final Map<Integer, Integer> NPC_DEATH_ANIMATIONS = ImmutableMap.of(
NpcID.CAVE_KRAKEN, AnimationID.CAVE_KRAKEN_DEATH
);
private static final Map<Integer, Integer> NPC_DEATH_ANIMATIONS = ImmutableMap.<Integer, Integer>builder()
.put(NpcID.CAVE_KRAKEN, AnimationID.CAVE_KRAKEN_DEATH)
.put(NpcID.CRYSTALLINE_BAT, AnimationID.CRYSTALLINE_BAT_DEATH)
.put(NpcID.CRYSTALLINE_RAT, AnimationID.CRYSTALLINE_RAT_DEATH)
.put(NpcID.CRYSTALLINE_SPIDER, AnimationID.CRYSTALLINE_SPIDER_DEATH)
.put(NpcID.CRYSTALLINE_WOLF, AnimationID.CRYSTALLINE_WOLF_DEATH)
.put(NpcID.CRYSTALLINE_UNICORN, AnimationID.CRYSTALLINE_UNICORN_DEATH)
.put(NpcID.CRYSTALLINE_SCORPION, AnimationID.CORRUPTED_SCORPION_DEATH)
.put(NpcID.CRYSTALLINE_DRAGON, AnimationID.CRYSTALLINE_DRAGON_DEATH)
.put(NpcID.CRYSTALLINE_DARK_BEAST, AnimationID.CRYSTALLINE_DARK_BEAST_DEATH)
.put(NpcID.CRYSTALLINE_BEAR, AnimationID.CRYSTALLINE_BEAR_DEATH)
.put(NpcID.CORRUPTED_BAT, AnimationID.CRYSTALLINE_BAT_DEATH)
.put(NpcID.CORRUPTED_RAT, AnimationID.CRYSTALLINE_RAT_DEATH)
.put(NpcID.CORRUPTED_SPIDER, AnimationID.CRYSTALLINE_SPIDER_DEATH)
.put(NpcID.CORRUPTED_WOLF, AnimationID.CRYSTALLINE_WOLF_DEATH)
.put(NpcID.CORRUPTED_UNICORN, AnimationID.CRYSTALLINE_UNICORN_DEATH)
.put(NpcID.CORRUPTED_SCORPION, AnimationID.CORRUPTED_SCORPION_DEATH)
.put(NpcID.CORRUPTED_DRAGON, AnimationID.CRYSTALLINE_DRAGON_DEATH)
.put(NpcID.CORRUPTED_DARK_BEAST, AnimationID.CRYSTALLINE_DARK_BEAST_DEATH)
.put(NpcID.CORRUPTED_BEAR, AnimationID.CRYSTALLINE_BEAR_DEATH)
.build();
private final EventBus eventBus;
private final Client client;
@@ -167,6 +185,7 @@ public class LootManager
final Tile tile = itemSpawned.getTile();
final LocalPoint location = tile.getLocalLocation();
final int packed = location.getSceneX() << 8 | location.getSceneY();
log.debug("storing items in {}", packed);
itemSpawns.put(packed, new ItemStack(item.getId(), item.getQuantity(), location));
log.debug("Item spawn {} ({}) location {}", item.getId(), item.getQuantity(), location);
}

View File

@@ -0,0 +1,12 @@
package net.runelite.client.game;
import lombok.Data;
import net.runelite.api.Skill;
import net.runelite.api.events.Event;
@Data
public class XpDropEvent implements Event
{
private Skill skill;
private int exp;
}

View File

@@ -0,0 +1,60 @@
package net.runelite.client.game;
import java.util.EnumMap;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.Skill;
import net.runelite.api.events.ExperienceChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.eventbus.EventBus;
@Singleton
public class XpDropManager
{
private final Map<Skill, Integer> previousSkillExpTable = new EnumMap<>(Skill.class);
@Getter(AccessLevel.PACKAGE)
private int damage = 0;
@Getter(AccessLevel.PACKAGE)
private int tickShow = 0;
private int previousExpGained;
private Client client;
private EventBus eventBus;
@Inject
private XpDropManager(
final EventBus eventBus,
final Client client
)
{
this.client = client;
this.eventBus = eventBus;
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventBus.subscribe(ExperienceChanged.class, this, this::onExperienceChanged);
}
private void onGameStateChanged(GameStateChanged event)
{
damage = 0;
tickShow = 0;
}
private void onExperienceChanged(ExperienceChanged event)
{
final Skill skill = event.getSkill();
final int xp = client.getSkillExperience(skill);
Integer previous = previousSkillExpTable.put(skill, xp);
if (previous != null)
{
previousExpGained = xp - previous;
XpDropEvent xpDropEvent = new XpDropEvent();
xpDropEvent.setExp(previousExpGained);
xpDropEvent.setSkill(skill);
eventBus.post(XpDropEvent.class, xpDropEvent);
}
}
}

View File

@@ -223,7 +223,7 @@ public class CoxPlugin extends Plugin
{
final String fixedPlayerName = Text.sanitize(rawPlayerName);
if (fixedPlayerName.equals(tpMatcher.group(1)))
if (fixedPlayerName.equals(Text.sanitize(tpMatcher.group(1))))
{
victims.add(new Victim(player, Victim.Type.TELEPORT));
}

View File

@@ -0,0 +1,42 @@
package net.runelite.client.plugins.deathindicator;
import java.time.Duration;
import java.time.Instant;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.Scene;
import net.runelite.api.coords.WorldPoint;
import static net.runelite.client.plugins.deathindicator.DeathIndicatorPlugin.HIJACKED_ITEMID;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.MiscUtils;
@EqualsAndHashCode
@Getter
@Setter
class Bone
{
private String name;
private WorldPoint loc;
private Instant time;
void addToScene(Scene scene)
{
scene.addItem(HIJACKED_ITEMID, 1, loc);
}
void removeFromScene(Scene scene)
{
scene.removeItem(HIJACKED_ITEMID, 1, loc);
}
String getName()
{
return ColorUtil.colorStartTag(0xff9040) + "Bones (" + name + ")";
}
String getExamine()
{
return name + " died here " + MiscUtils.formatTimeAgo(Duration.between(time, Instant.now()));
}
}

View File

@@ -0,0 +1,200 @@
package net.runelite.client.plugins.deathindicator;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Scene;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.config.ConfigManager;
import static net.runelite.http.api.RuneLiteAPI.GSON;
@Slf4j
public class Bones
{
private static final String CONFIG_GROUP = "deathIndicator";
private static final String BONES_PREFIX = "bones_";
private ImmutableMap<Integer, Map<WorldPoint, List<Bone>>> map;
private boolean changed = false;
void init(Client client, ConfigManager configManager)
{
// Clone is important here as the normal array changes
int[] regions = client.getMapRegions().clone();
Bone[][] bones = getBones(configManager, regions);
if (log.isDebugEnabled())
{
log.debug("Regions are now {}", Arrays.toString(regions));
int n = 0;
for (Bone[] ar : bones)
{
n += ar.length;
}
log.debug("Loaded {} Bones", n);
}
initMap(regions, bones);
showBones(client.getScene());
}
private Bone[][] getBones(ConfigManager configManager, int[] regions)
{
Bone[][] bones = new Bone[regions.length][];
for (int i = 0; i < regions.length; i++)
{
int region = regions[i];
bones[i] = getBones(configManager, region);
}
return bones;
}
private Bone[] getBones(ConfigManager configManager, int regionId)
{
String json = configManager.getConfiguration(CONFIG_GROUP, BONES_PREFIX + regionId);
if (json == null)
{
return new Bone[0];
}
return GSON.fromJson(json, Bone[].class);
}
@SuppressWarnings("unchecked")
private void initMap(int[] regions, Bone[][] bones)
{
ImmutableMap.Builder<Integer, Map<WorldPoint, List<Bone>>> builder = ImmutableMap.builder();
for (int i = 0; i < regions.length; i++)
{
int region = regions[i];
Bone[] boneA = bones[i];
if (boneA.length == 0)
{
builder.put(region, Collections.EMPTY_MAP);
continue;
}
Map<WorldPoint, List<Bone>> map = new HashMap(boneA.length);
for (Bone b : boneA)
{
List<Bone> list = map.computeIfAbsent(b.getLoc(), wp -> new ArrayList<>());
list.add(b);
}
builder.put(region, map);
}
this.map = builder.build();
}
private void showBones(Scene scene)
{
this.forEach(bone -> bone.addToScene(scene));
}
void save(ConfigManager configManager)
{
if (this.map == null || !changed)
{
this.changed = false;
return;
}
for (Map.Entry<Integer, Map<WorldPoint, List<Bone>>> entry : this.map.entrySet())
{
final String key = BONES_PREFIX + entry.getKey();
final Map<WorldPoint, List<Bone>> map = entry.getValue();
if (map.size() == 0)
{
configManager.unsetConfiguration(CONFIG_GROUP, key);
continue;
}
List<Bone> list = new ArrayList<>(map.values().size());
for (List<Bone> lb : map.values())
{
list.addAll(lb);
}
String val = GSON.toJson(list.toArray(new Bone[0]));
configManager.setConfiguration(CONFIG_GROUP, key, val);
}
this.changed = false;
}
public boolean add(Bone bone)
{
if (this.map == null)
{
return false;
}
this.changed = true;
final int region = bone.getLoc().getRegionID();
final Map<WorldPoint, List<Bone>> map = this.map.get(region);
final List<Bone> list = map.computeIfAbsent(bone.getLoc(), wp -> new ArrayList<>());
list.add(bone);
return true;
}
public void remove(Bone bone)
{
this.changed = true;
final int region = bone.getLoc().getRegionID();
final Map<WorldPoint, List<Bone>> map = this.map.get(region);
final List<Bone> list = map.get(bone.getLoc());
list.remove(bone);
}
public void clear(Scene scene)
{
if (map == null)
{
return;
}
this.forEach(bone -> bone.removeFromScene(scene));
}
public Bone get(WorldPoint point, int i)
{
return get(point).get(i);
}
public List<Bone> get(WorldPoint point)
{
final int reg = point.getRegionID();
final Map<WorldPoint, List<Bone>> map = this.map.get(reg);
if (map == null)
{
return null;
}
return map.get(point);
}
private void forEach(Consumer<Bone> consumer)
{
for (Map<WorldPoint, List<Bone>> map : this.map.values())
{
for (Map.Entry<WorldPoint, List<Bone>> entry : map.entrySet())
{
for (Bone bone : entry.getValue())
{
consumer.accept(bone);
}
}
}
}
}

View File

@@ -152,4 +152,14 @@ public interface DeathIndicatorConfig extends Config
description = ""
)
void timeOfDeath(Instant timeOfDeath);
@ConfigItem(
keyName = "permaBones",
name = "Permanent bones",
description = "Show right clickable bones with the name of who died permanently, after seeing someone die"
)
default boolean permaBones()
{
return false;
}
}

View File

@@ -30,18 +30,32 @@ import java.awt.image.BufferedImage;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.api.MenuEntry;
import net.runelite.api.MenuOpcode;
import net.runelite.api.Player;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ItemDespawned;
import net.runelite.api.events.LocalPlayerDeath;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOpened;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.PlayerDeath;
import net.runelite.api.events.PostItemDefinition;
import net.runelite.api.util.Text;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.game.ItemManager;
@@ -61,6 +75,10 @@ import net.runelite.client.util.ImageUtil;
@Slf4j
public class DeathIndicatorPlugin extends Plugin
{
private static final Object BONES = new Object();
// A random number, that jagex probably won't actually use in the near future
static final int HIJACKED_ITEMID = 0x69696969;
private static final Set<Integer> RESPAWN_REGIONS = ImmutableSet.of(
12850, // Lumbridge
11828, // Falador
@@ -88,6 +106,14 @@ public class DeathIndicatorPlugin extends Plugin
@Inject
private EventBus eventBus;
@Inject
private ConfigManager configManager;
@Inject
private ClientThread clientThread;
private final Bones bones = new Bones();
private BufferedImage mapArrow;
private Timer deathTimer;
@@ -95,7 +121,7 @@ public class DeathIndicatorPlugin extends Plugin
private WorldPoint lastDeath;
private Instant lastDeathTime;
private int lastDeathWorld;
private int despawnIdx = 0;
@Provides
DeathIndicatorConfig deathIndicatorConfig(ConfigManager configManager)
{
@@ -129,12 +155,18 @@ public class DeathIndicatorPlugin extends Plugin
worldMapPointManager.removeIf(DeathWorldMapPoint.class::isInstance);
worldMapPointManager.add(new DeathWorldMapPoint(new WorldPoint(config.deathLocationX(), config.deathLocationY(), config.deathLocationPlane()), this));
}
if (config.permaBones() && client.getGameState() == GameState.LOGGED_IN)
{
clientThread.invokeLater(this::initBones);
}
}
@Override
protected void shutDown()
{
eventBus.unregister(this);
eventBus.unregister(BONES);
if (client.hasHintArrow())
{
@@ -148,6 +180,24 @@ public class DeathIndicatorPlugin extends Plugin
}
worldMapPointManager.removeIf(DeathWorldMapPoint.class::isInstance);
clientThread.invokeLater(this::clearBones);
saveBones();
}
private void initBones()
{
bones.init(client, configManager);
}
private void saveBones()
{
bones.save(configManager);
}
private void clearBones()
{
bones.clear(client.getScene());
}
private void addSubscriptions()
@@ -156,6 +206,100 @@ public class DeathIndicatorPlugin extends Plugin
eventBus.subscribe(LocalPlayerDeath.class, this, this::onLocalPlayerDeath);
eventBus.subscribe(GameTick.class, this, this::onGameTick);
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
if (config.permaBones())
{
addBoneSubs();
}
}
private void addBoneSubs()
{
eventBus.subscribe(ItemDespawned.class, BONES, this::onItemDespawn);
eventBus.subscribe(PlayerDeath.class, BONES, this::onPlayerDeath);
eventBus.subscribe(MenuEntryAdded.class, BONES, this::onMenuEntryAdded);
eventBus.subscribe(MenuOptionClicked.class, BONES, this::onMenuOptionClicked);
eventBus.subscribe(MenuOpened.class, BONES, this::onMenuOpened);
eventBus.subscribe(PostItemDefinition.class, BONES, this::onPostItemDefinition);
}
private void onPostItemDefinition(PostItemDefinition def)
{
ItemDefinition itemDef = def.getItemDefinition();
if (itemDef.getId() == HIJACKED_ITEMID)
{
itemDef.setModelOverride(ItemID.BONES);
itemDef.setName("Bones");
// This is so never hide untradeables doesn't not hide it
itemDef.setTradeable(true);
}
}
private void onPlayerDeath(PlayerDeath death)
{
Player p = death.getPlayer();
Bone b = new Bone();
b.setName(Text.sanitize(p.getName()));
b.setTime(Instant.now());
b.setLoc(p.getWorldLocation());
while (!bones.add(b))
{
initBones();
}
b.addToScene(client.getScene());
}
private void onMenuEntryAdded(MenuEntryAdded event)
{
if (event.getIdentifier() == HIJACKED_ITEMID)
{
if (event.getOpcode() == MenuOpcode.GROUND_ITEM_THIRD_OPTION.getId())
{
client.setMenuOptionCount(client.getMenuOptionCount() - 1);
}
}
}
private void onMenuOpened(MenuOpened event)
{
int idx = 0;
for (MenuEntry entry : event)
{
if (entry.getIdentifier() != HIJACKED_ITEMID)
{
continue;
}
// Only entries with appropriate identifier here will be examine so that's easy
// Add idx to id field, so we can find that back from clicked event
entry.setIdentifier(HIJACKED_ITEMID + idx);
Bone bone = bones.get(
WorldPoint.fromScene(client, entry.getParam0(), entry.getParam1(), client.getPlane()),
idx++
);
entry.setTarget(bone.getName());
event.setModified();
}
}
private void onMenuOptionClicked(MenuOptionClicked event)
{
if (event.getIdentifier() >= HIJACKED_ITEMID
&& event.getOpcode() == MenuOpcode.EXAMINE_ITEM_GROUND.getId())
{
Bone b = bones.get(
WorldPoint.fromScene(client, event.getParam0(), event.getParam1(), client.getPlane()),
event.getIdentifier() - HIJACKED_ITEMID
);
client.addChatMessage(ChatMessageType.ITEM_EXAMINE, "", b.getExamine(), "");
event.consume();
}
}
private void onLocalPlayerDeath(LocalPlayerDeath death)
@@ -238,6 +382,29 @@ public class DeathIndicatorPlugin extends Plugin
{
if (event.getGroup().equals("deathIndicator"))
{
if ("permaBones".equals(event.getKey()))
{
if (config.permaBones())
{
addBoneSubs();
if (client.getGameState() == GameState.LOGGED_IN)
{
clientThread.invokeLater(this::initBones);
}
}
else
{
eventBus.unregister(BONES);
if (client.getGameState() == GameState.LOGGED_IN)
{
clientThread.invokeLater(this::clearBones);
saveBones();
}
}
return;
}
if (!config.showDeathHintArrow() && hasDied())
{
client.clearHintArrow();
@@ -267,32 +434,62 @@ public class DeathIndicatorPlugin extends Plugin
private void onGameStateChanged(GameStateChanged event)
{
if (!hasDied())
switch (event.getGameState())
{
return;
}
if (event.getGameState() == GameState.LOGGED_IN)
{
if (client.getWorld() == config.deathWorld())
{
WorldPoint deathPoint = new WorldPoint(config.deathLocationX(), config.deathLocationY(), config.deathLocationPlane());
if (config.showDeathHintArrow())
case LOADING:
clearBones();
saveBones();
break;
case LOGGED_IN:
if (config.permaBones())
{
client.setHintArrow(deathPoint);
initBones();
}
if (config.showDeathOnWorldMap())
if (!hasDied())
{
return;
}
if (client.getWorld() == config.deathWorld())
{
WorldPoint deathPoint = new WorldPoint(config.deathLocationX(), config.deathLocationY(), config.deathLocationPlane());
if (config.showDeathHintArrow())
{
client.setHintArrow(deathPoint);
}
if (config.showDeathOnWorldMap())
{
worldMapPointManager.removeIf(DeathWorldMapPoint.class::isInstance);
worldMapPointManager.add(new DeathWorldMapPoint(deathPoint, this));
}
}
else
{
worldMapPointManager.removeIf(DeathWorldMapPoint.class::isInstance);
worldMapPointManager.add(new DeathWorldMapPoint(deathPoint, this));
}
}
else
break;
}
}
private void onItemDespawn(ItemDespawned event)
{
if (event.getItem().getId() == HIJACKED_ITEMID)
{
List<Bone> list = bones.get(event.getTile().getWorldLocation());
if (list == null)
{
worldMapPointManager.removeIf(DeathWorldMapPoint.class::isInstance);
return;
}
if (list.size() <= despawnIdx)
{
despawnIdx = 0;
}
Bone bone = list.get(despawnIdx++);
bone.addToScene(client.getScene());
}
}

View File

@@ -29,8 +29,6 @@ package net.runelite.client.plugins.experiencedrop;
import com.google.inject.Provides;
import java.awt.Color;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Map;
import java.util.stream.IntStream;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -46,7 +44,6 @@ import net.runelite.api.SpriteID;
import net.runelite.api.Varbits;
import net.runelite.api.WorldType;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ExperienceChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ScriptCallbackEvent;
@@ -57,6 +54,7 @@ import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.game.NPCManager;
import net.runelite.client.game.XpDropEvent;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
@@ -65,30 +63,23 @@ import net.runelite.client.util.ColorUtil;
@PluginDescriptor(
name = "XP Drop",
description = "Enable customization of the way XP drops are displayed",
tags = {"experience", "levels", "tick"}
)
tags = {"experience", "levels", "tick"})
@Singleton
public class XpDropPlugin extends Plugin
{
private static final int XPDROP_PADDING = 2; // space between xp drop icons
private static final double HITPOINT_RATIO = 1.33; // Base rate of hp xp per point damage
private static final double DMM_MULTIPLIER_RATIO = 10;
@Inject
private Client client;
@Inject
private XpDropConfig config;
@Inject
private NPCManager npcManager;
@Inject
private OverlayManager overlayManager;
@Inject
private XpDropOverlay overlay;
@Inject
private EventBus eventBus;
@@ -106,16 +97,15 @@ public class XpDropPlugin extends Plugin
private boolean hasDropped = false;
private boolean correctPrayer;
private Skill lastSkill = null;
private final Map<Skill, Integer> previousSkillExpTable = new EnumMap<>(Skill.class);
private PrayerType currentTickPrayer;
private XpDropConfig.DamageMode damageMode;
private boolean hideSkillIcons;
private Color getMeleePrayerColor;
private Color getRangePrayerColor;
private Color getMagePrayerColor;
private int fakeXpDropDelay;
private XpDropConfig.DamageMode showdamagedrops;
@Getter(AccessLevel.PACKAGE)
private Color damageColor;
@@ -153,10 +143,17 @@ public class XpDropPlugin extends Plugin
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventBus.subscribe(WidgetHiddenChanged.class, this, this::onWidgetHiddenChanged);
eventBus.subscribe(GameTick.class, this, this::onGameTick);
eventBus.subscribe(ExperienceChanged.class, this, this::onExperienceChanged);
eventBus.subscribe(XpDropEvent.class, this, this::onXpDropEvent);
eventBus.subscribe(ScriptCallbackEvent.class, this, this::onScriptCallbackEvent);
}
private void onXpDropEvent(XpDropEvent event)
{
previousExpGained = event.getExp();
lastSkill = event.getSkill();
hasDropped = true;
}
private void onConfigChanged(ConfigChanged event)
{
if (!event.getGroup().equals("xpdrop"))
@@ -188,8 +185,8 @@ public class XpDropPlugin extends Plugin
private void onGameStateChanged(GameStateChanged event)
{
damage = 0;
tickShow = 0;
damage = 0;
}
private void onWidgetHiddenChanged(WidgetHiddenChanged event)
@@ -269,9 +266,12 @@ public class XpDropPlugin extends Plugin
switch (prayer)
{
case MELEE:
if (spriteIDs.anyMatch(id ->
id == SpriteID.SKILL_ATTACK || id == SpriteID.SKILL_STRENGTH || id == SpriteID.SKILL_DEFENCE
|| correctPrayer))
if (spriteIDs.anyMatch(
id ->
id == SpriteID.SKILL_ATTACK
|| id == SpriteID.SKILL_STRENGTH
|| id == SpriteID.SKILL_DEFENCE
|| correctPrayer))
{
color = this.getMeleePrayerColor.getRGB();
correctPrayer = true;
@@ -351,21 +351,6 @@ public class XpDropPlugin extends Plugin
client.runScript(XPDROP_DISABLED, lastSkill.ordinal(), previousExpGained);
}
private void onExperienceChanged(ExperienceChanged event)
{
final Skill skill = event.getSkill();
final int xp = client.getSkillExperience(skill);
lastSkill = skill;
Integer previous = previousSkillExpTable.put(skill, xp);
if (previous != null)
{
previousExpGained = xp - previous;
hasDropped = true;
}
}
private void onScriptCallbackEvent(ScriptCallbackEvent e)
{
if (this.showdamagedrops == XpDropConfig.DamageMode.NONE)
@@ -404,16 +389,19 @@ public class XpDropPlugin extends Plugin
final int exp = intStack[intStackSize - 1];
calculateDamageDealt(exp);
}
else if (eventName.equals("xpDropAddDamage") &&
damageMode == XpDropConfig.DamageMode.IN_XP_DROP &&
damage > 0)
else if (eventName.equals("xpDropAddDamage")
&& damageMode == XpDropConfig.DamageMode.IN_XP_DROP
&& damage > 0)
{
final String[] stringStack = client.getStringStack();
final int stringStackSize = client.getStringStackSize();
String builder = stringStack[stringStackSize - 1] +
ColorUtil.colorTag(this.damageColor) +
" (" + damage + ")";
String builder =
stringStack[stringStackSize - 1]
+ ColorUtil.colorTag(this.damageColor)
+ " ("
+ damage
+ ")";
stringStack[stringStackSize - 1] = builder;
}
}
@@ -431,7 +419,8 @@ public class XpDropPlugin extends Plugin
Actor a = client.getLocalPlayer().getInteracting();
if (!(a instanceof NPC) && !(a instanceof Player))
{
// If we are interacting with nothing we may have clicked away at the perfect time fall back to last tick
// If we are interacting with nothing we may have clicked away at the perfect time fall back
// to last tick
if (!(lastOpponent instanceof NPC) && !(lastOpponent instanceof Player))
{
damage = (int) Math.rint(damageDealt);

View File

@@ -321,4 +321,16 @@ public interface GauntletConfig extends Config
{
return false;
}
@ConfigItem(
position = 21,
keyName = "displayResources",
name = "Show raw resources gathered",
description = "Displays how much of each resource you have gathered.",
titleSection = "resources"
)
default boolean displayGatheredResources()
{
return false;
}
}

View File

@@ -43,6 +43,7 @@ import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import net.runelite.api.HeadIcon;
import net.runelite.api.ItemID;
import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition;
import net.runelite.api.NpcID;
@@ -50,6 +51,7 @@ import net.runelite.api.ObjectID;
import net.runelite.api.Player;
import net.runelite.api.Projectile;
import net.runelite.api.ProjectileID;
import net.runelite.api.Skill;
import net.runelite.api.SoundEffectID;
import net.runelite.api.Varbits;
import net.runelite.api.events.AnimationChanged;
@@ -58,6 +60,7 @@ import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.api.events.ProjectileSpawned;
@@ -65,6 +68,8 @@ import net.runelite.api.events.VarbitChanged;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.NpcLootReceived;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@@ -73,7 +78,10 @@ import static net.runelite.client.plugins.gauntlet.Hunllef.BossAttack.LIGHTNING;
import static net.runelite.client.plugins.gauntlet.Hunllef.BossAttack.MAGIC;
import static net.runelite.client.plugins.gauntlet.Hunllef.BossAttack.PRAYER;
import static net.runelite.client.plugins.gauntlet.Hunllef.BossAttack.RANGE;
import net.runelite.client.game.XpDropEvent;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.Counter;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
@PluginDescriptor(
name = "Gauntlet",
@@ -104,7 +112,8 @@ public class GauntletPlugin extends Plugin
ObjectID.PHREN_ROOTS_36066, ObjectID.FISHING_SPOT_36068, ObjectID.FISHING_SPOT_35971, ObjectID.GRYM_ROOT, ObjectID.GRYM_ROOT_36070,
ObjectID.LINUM_TIRINUM, ObjectID.LINUM_TIRINUM_36072
);
private static final int GATHERING_HERB = 0;
private static final int GATHERING_CLOTH = 1;
@Inject
@Getter(AccessLevel.NONE)
private Client client;
@@ -138,6 +147,10 @@ public class GauntletPlugin extends Plugin
@Setter(AccessLevel.PACKAGE)
@Nullable
private Hunllef hunllef;
@Inject
private InfoBoxManager infoBoxManager;
@Inject
private ItemManager itemManager;
private boolean attackVisualOutline;
private boolean completeStartup = false;
private boolean displayTimerChat;
@@ -160,11 +173,24 @@ public class GauntletPlugin extends Plugin
private final Map<String, Integer> items = new HashMap<>();
private final Set<Missiles> projectiles = new HashSet<>();
private final Set<Resources> resources = new HashSet<>();
private GauntletConfig.CounterDisplay countAttacks;
private int resourceIconSize;
private Set<Tornado> tornadoes = new HashSet<>();
private int projectileIconSize;
private boolean displayResources;
private Counter oreCounter;
private Counter woodCounter;
private Counter clothCounter;
private Counter fishCounter;
private Counter herbCounter;
private int oresGathered;
private int woodGathered;
private int clothGathered;
private int fishGathered;
private int herbGathered;
private int currentFarmingAction = -1;
private boolean countersVisible = false;
@Provides
GauntletConfig getConfig(ConfigManager configManager)
@@ -177,6 +203,7 @@ public class GauntletPlugin extends Plugin
{
addSubscriptions();
updateConfig();
initializeCounters();
overlayManager.add(overlay);
overlayManager.add(infoboxoverlay);
overlayManager.add(GauntletCounter);
@@ -200,6 +227,47 @@ public class GauntletPlugin extends Plugin
}
}
private void addCounters()
{
if (!countersVisible)
{
infoBoxManager.addInfoBox(oreCounter);
infoBoxManager.addInfoBox(woodCounter);
infoBoxManager.addInfoBox(clothCounter);
infoBoxManager.addInfoBox(fishCounter);
infoBoxManager.addInfoBox(herbCounter);
countersVisible = true;
}
}
private void initializeCounters()
{
resetGatheringCounters();
oreCounter = new Counter(itemManager.getImage(ItemID.CORRUPTED_ORE), this, 0);
woodCounter = new Counter(itemManager.getImage(ItemID.PHREN_BARK_23878), this, 0);
clothCounter = new Counter(itemManager.getImage(ItemID.LINUM_TIRINUM_23876), this, 0);
fishCounter = new Counter(itemManager.getImage(ItemID.RAW_PADDLEFISH), this, 0);
herbCounter = new Counter(itemManager.getImage(ItemID.GRYM_LEAF_23875), this, 0);
}
private void resetGatheringCounters()
{
oresGathered = 0;
fishGathered = 0;
woodGathered = 0;
clothGathered = 0;
herbGathered = 0;
}
private void updateCounters()
{
oreCounter.setCount(oresGathered);
woodCounter.setCount(woodGathered);
clothCounter.setCount(clothGathered);
fishCounter.setCount(fishGathered);
herbCounter.setCount(herbGathered);
}
@Override
protected void shutDown()
{
@@ -213,12 +281,24 @@ public class GauntletPlugin extends Plugin
overlayManager.remove(overlay);
overlayManager.remove(infoboxoverlay);
overlayManager.remove(GauntletCounter);
removeCounters();
resetGatheringCounters();
resources.clear();
projectiles.clear();
tornadoes.clear();
setHunllef(null);
}
private void removeCounters()
{
infoBoxManager.removeInfoBox(oreCounter);
infoBoxManager.removeInfoBox(woodCounter);
infoBoxManager.removeInfoBox(clothCounter);
infoBoxManager.removeInfoBox(fishCounter);
infoBoxManager.removeInfoBox(herbCounter);
countersVisible = false;
}
private void addSubscriptions()
{
eventBus.subscribe(AnimationChanged.class, this, this::onAnimationChanged);
@@ -231,6 +311,56 @@ public class GauntletPlugin extends Plugin
eventBus.subscribe(NpcSpawned.class, this, this::onNpcSpawned);
eventBus.subscribe(ProjectileSpawned.class, this, this::onProjectileSpawned);
eventBus.subscribe(VarbitChanged.class, this, this::onVarbitChanged);
eventBus.subscribe(XpDropEvent.class, this, this::onXpDropEvent);
eventBus.subscribe(NpcLootReceived.class, this, this::onNpcLootReceived);
eventBus.subscribe(MenuOptionClicked.class, this, this::onMenuOptionClicked);
}
private void onMenuOptionClicked(MenuOptionClicked menuOptionClicked)
{
if (menuOptionClicked.getTarget().toUpperCase().contains("LINUM"))
{
currentFarmingAction = GATHERING_CLOTH;
}
if (menuOptionClicked.getTarget().toUpperCase().contains("GRYM"))
{
currentFarmingAction = GATHERING_HERB;
}
}
private void onNpcLootReceived(NpcLootReceived npcLootReceived)
{
fishGathered += (int) npcLootReceived.getItems().stream().filter(item -> item.getId() == ItemID.RAW_PADDLEFISH).count();
herbGathered += (int) npcLootReceived.getItems().stream().filter(item -> item.getId() == ItemID.GRYM_LEAF || item.getId() == ItemID.GRYM_LEAF_23875).count();
updateCounters();
}
private void onXpDropEvent(XpDropEvent experienceChanged)
{
if (experienceChanged.getSkill().compareTo(Skill.MINING) == 0)
{
oresGathered++;
}
if (experienceChanged.getSkill().compareTo(Skill.WOODCUTTING) == 0)
{
woodGathered++;
}
if (experienceChanged.getSkill().compareTo(Skill.FARMING) == 0)
{
if (currentFarmingAction == GATHERING_HERB)
{
herbGathered++;
}
else if (currentFarmingAction == GATHERING_CLOTH)
{
clothGathered++;
}
}
if (experienceChanged.getSkill().compareTo(Skill.FISHING) == 0)
{
fishGathered++;
}
updateCounters();
}
private void onAnimationChanged(AnimationChanged event)
@@ -325,6 +455,18 @@ public class GauntletPlugin extends Plugin
timerVisible = false;
}
}
if (event.getKey().equals("displayResources"))
{
if (this.displayResources && this.startedGauntlet())
{
addCounters();
}
else
{
removeCounters();
}
}
}
private void onGameObjectDespawned(GameObjectDespawned event)
@@ -379,6 +521,7 @@ public class GauntletPlugin extends Plugin
if (HUNLLEF_NPC_IDS.contains(npc.getId()))
{
setHunllef(null);
resetGatheringCounters();
}
else if (TORNADO_NPC_IDS.contains(npc.getId()))
{
@@ -436,6 +579,14 @@ public class GauntletPlugin extends Plugin
{
timer.checkStates(true);
}
if (startedGauntlet() && displayResources)
{
addCounters();
}
else
{
removeCounters();
}
}
boolean fightingBoss()
@@ -468,5 +619,6 @@ public class GauntletPlugin extends Plugin
this.displayTimerChat = config.displayTimerChat();
this.attackVisualOutline = config.attackVisualOutline();
this.highlightPrayerInfobox = config.highlightPrayerInfobox();
this.displayResources = config.displayGatheredResources();
}
}

View File

@@ -1,6 +1,8 @@
package net.runelite.client.util;
import java.awt.Polygon;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import net.runelite.api.Client;
import net.runelite.api.Player;
import net.runelite.api.WorldType;
@@ -16,6 +18,17 @@ public class MiscUtils
private static final Polygon abovePoly = new Polygon(abovePointsX, abovePointsY, abovePointsX.length);
private static final Polygon belowPoly = new Polygon(belowPointsX, belowPointsY, belowPointsX.length);
private static final ChronoUnit[] ORDERED_CHRONOS = new ChronoUnit[]
{
ChronoUnit.YEARS,
ChronoUnit.MONTHS,
ChronoUnit.WEEKS,
ChronoUnit.DAYS,
ChronoUnit.HOURS,
ChronoUnit.MINUTES,
ChronoUnit.SECONDS
};
//test replacement so private for now
private static boolean inWildy(WorldPoint point)
{
@@ -86,4 +99,75 @@ public class MiscUtils
//return getWildernessLevelFrom(client, localPlayer.getWorldLocation()) > 0;
}
public static String formatTimeAgo(Duration dur)
{
long dA = 0, dB = 0, rm;
ChronoUnit cA = null, cB = null;
for (int i = 0; i < ORDERED_CHRONOS.length; i++)
{
cA = ORDERED_CHRONOS[i];
dA = dur.getSeconds() / cA.getDuration().getSeconds();
rm = dur.getSeconds() % cA.getDuration().getSeconds();
if (dA <= 0)
{
cA = null;
continue;
}
if (i + 1 < ORDERED_CHRONOS.length)
{
cB = ORDERED_CHRONOS[i + 1];
dB = rm / cB.getDuration().getSeconds();
if (dB <= 0)
{
cB = null;
}
}
break;
}
if (cA == null)
{
return "just now.";
}
String str = formatUnit(cA, dA);
if (cB != null)
{
str += " and " + formatUnit(cB, dB);
}
return str + " ago.";
}
private static String formatUnit(ChronoUnit chrono, long val)
{
boolean multiple = val != 1;
String str;
if (multiple)
{
str = val + " ";
}
else
{
str = "a" + (chrono == ChronoUnit.HOURS ? "n " : " ");
}
str += chrono.name().toLowerCase();
if (!multiple)
{
if (str.charAt(str.length() - 1) == 's')
{
str = str.substring(0, str.length() - 1);
}
}
else if (str.charAt(str.length() - 1) != 's')
{
str += "s";
}
return str;
}
}

File diff suppressed because one or more lines are too long