Merge remote-tracking branch 'upstream/master' into runelite
# Conflicts: # cache-client/pom.xml # cache-updater/pom.xml # cache/pom.xml # http-api/pom.xml # http-service/pom.xml # pom.xml # runelite-api/pom.xml # runelite-api/src/main/java/net/runelite/api/Client.java # runelite-api/src/main/java/net/runelite/api/FarmingTrackerTest.java # runelite-client/pom.xml # runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java # runelite-client/src/test/java/net/runelite/client/chat/ChatMessageManagerTest.java # runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java # runelite-client/src/test/java/net/runelite/client/plugins/emojis/EmojiPluginTest.java # runelite-client/src/test/java/net/runelite/client/plugins/grounditems/GroundItemsPluginTest.java # runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java # runelite-script-assembler-plugin/pom.xml
This commit is contained in:
@@ -27,13 +27,26 @@ package net.runelite.http.api.gson;
|
|||||||
import com.google.gson.ExclusionStrategy;
|
import com.google.gson.ExclusionStrategy;
|
||||||
import com.google.gson.FieldAttributes;
|
import com.google.gson.FieldAttributes;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class IllegalReflectionExclusion implements ExclusionStrategy
|
public class IllegalReflectionExclusion implements ExclusionStrategy
|
||||||
{
|
{
|
||||||
|
private static final Set<ClassLoader> PRIVATE_CLASSLOADERS = new HashSet<>();
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
for (ClassLoader cl = ClassLoader.getSystemClassLoader(); cl != null; )
|
||||||
|
{
|
||||||
|
cl = cl.getParent();
|
||||||
|
PRIVATE_CLASSLOADERS.add(cl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldSkipField(FieldAttributes f)
|
public boolean shouldSkipField(FieldAttributes f)
|
||||||
{
|
{
|
||||||
if (f.getDeclaringClass().getName().startsWith("net.runelite"))
|
if (!PRIVATE_CLASSLOADERS.contains(f.getDeclaringClass().getClassLoader()))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ public final class AnimationID
|
|||||||
public static final int CRAFTING_SPINNING = 894;
|
public static final int CRAFTING_SPINNING = 894;
|
||||||
public static final int CRAFTING_POTTERS_WHEEL = 883;
|
public static final int CRAFTING_POTTERS_WHEEL = 883;
|
||||||
public static final int CRAFTING_POTTERY_OVEN = 24975;
|
public static final int CRAFTING_POTTERY_OVEN = 24975;
|
||||||
|
public static final int CRAFTING_LOOM = 2270;
|
||||||
public static final int SMITHING_SMELTING = 899;
|
public static final int SMITHING_SMELTING = 899;
|
||||||
public static final int SMITHING_CANNONBALL = 827; //cball smithing uses this and SMITHING_SMELTING
|
public static final int SMITHING_CANNONBALL = 827; //cball smithing uses this and SMITHING_SMELTING
|
||||||
public static final int SMITHING_ANVIL = 898;
|
public static final int SMITHING_ANVIL = 898;
|
||||||
@@ -209,6 +210,12 @@ public final class AnimationID
|
|||||||
public static final int HOME_MAKE_TABLET = 4067;
|
public static final int HOME_MAKE_TABLET = 4067;
|
||||||
public static final int DRAGONFIRE_SHIELD_SPECIAL = 6696;
|
public static final int DRAGONFIRE_SHIELD_SPECIAL = 6696;
|
||||||
|
|
||||||
|
// Ectofuntus animations
|
||||||
|
public static final int ECTOFUNTUS_FILL_SLIME_BUCKET = 4471;
|
||||||
|
public static final int ECTOFUNTUS_GRIND_BONES = 1648;
|
||||||
|
public static final int ECTOFUNTUS_INSERT_BONES = 1649;
|
||||||
|
public static final int ECTOFUNTUS_EMPTY_BIN = 1650;
|
||||||
|
|
||||||
// NPC animations
|
// NPC animations
|
||||||
public static final int TZTOK_JAD_MAGIC_ATTACK = 2656;
|
public static final int TZTOK_JAD_MAGIC_ATTACK = 2656;
|
||||||
public static final int TZTOK_JAD_RANGE_ATTACK = 2652;
|
public static final int TZTOK_JAD_RANGE_ATTACK = 2652;
|
||||||
|
|||||||
@@ -124,12 +124,25 @@ public interface Client extends GameEngine
|
|||||||
/**
|
/**
|
||||||
* Adds a new chat message to the chatbox.
|
* Adds a new chat message to the chatbox.
|
||||||
*
|
*
|
||||||
* @param type the type of message
|
* @param type the type of message
|
||||||
* @param name the name of the player that sent the message
|
* @param name the name of the player that sent the message
|
||||||
* @param message the message contents
|
* @param message the message contents
|
||||||
* @param sender the sender/channel name
|
* @param sender the sender/channel name
|
||||||
|
* @return the message node for the message
|
||||||
*/
|
*/
|
||||||
void addChatMessage(ChatMessageType type, String name, String message, String sender);
|
MessageNode addChatMessage(ChatMessageType type, String name, String message, String sender);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new chat message to the chatbox.
|
||||||
|
*
|
||||||
|
* @param type the type of message
|
||||||
|
* @param name the name of the player that sent the message
|
||||||
|
* @param message the message contents
|
||||||
|
* @param sender the sender/channel name
|
||||||
|
* @param postEvent whether to post the chat message event
|
||||||
|
* @return the message node for the message
|
||||||
|
*/
|
||||||
|
MessageNode addChatMessage(ChatMessageType type, String name, String message, String sender, boolean postEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current game state.
|
* Gets the current game state.
|
||||||
@@ -1542,7 +1555,7 @@ public interface Client extends GameEngine
|
|||||||
*
|
*
|
||||||
* @param state the new player hidden state
|
* @param state the new player hidden state
|
||||||
*/
|
*/
|
||||||
void setPlayersHidden(boolean state);
|
void setOthersHidden(boolean state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether 2D sprites related to the other players are hidden.
|
* Sets whether 2D sprites related to the other players are hidden.
|
||||||
@@ -1550,7 +1563,7 @@ public interface Client extends GameEngine
|
|||||||
*
|
*
|
||||||
* @param state the new player 2D hidden state
|
* @param state the new player 2D hidden state
|
||||||
*/
|
*/
|
||||||
void setPlayersHidden2D(boolean state);
|
void setOthersHidden2D(boolean state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether or not friends are hidden.
|
* Sets whether or not friends are hidden.
|
||||||
@@ -1566,6 +1579,13 @@ public interface Client extends GameEngine
|
|||||||
*/
|
*/
|
||||||
void setFriendsChatMembersHidden(boolean state);
|
void setFriendsChatMembersHidden(boolean state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether or not ignored players are hidden.
|
||||||
|
*
|
||||||
|
* @param state the new ignored player hidden state
|
||||||
|
*/
|
||||||
|
void setIgnoresHidden(boolean state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether the local player is hidden.
|
* Sets whether the local player is hidden.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ public class Perspective
|
|||||||
*/
|
*/
|
||||||
public static Polygon getCanvasTilePoly(@Nonnull Client client, @Nonnull LocalPoint localLocation, int zOffset)
|
public static Polygon getCanvasTilePoly(@Nonnull Client client, @Nonnull LocalPoint localLocation, int zOffset)
|
||||||
{
|
{
|
||||||
return getCanvasTileAreaPoly(client, localLocation, 1, zOffset);
|
return getCanvasTileAreaPoly(client, localLocation, 1, 1, zOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -389,7 +389,7 @@ public class Perspective
|
|||||||
*/
|
*/
|
||||||
public static Polygon getCanvasTileAreaPoly(@Nonnull Client client, @Nonnull LocalPoint localLocation, int size)
|
public static Polygon getCanvasTileAreaPoly(@Nonnull Client client, @Nonnull LocalPoint localLocation, int size)
|
||||||
{
|
{
|
||||||
return getCanvasTileAreaPoly(client, localLocation, size, 0);
|
return getCanvasTileAreaPoly(client, localLocation, size, size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -397,23 +397,25 @@ public class Perspective
|
|||||||
*
|
*
|
||||||
* @param client the game client
|
* @param client the game client
|
||||||
* @param localLocation the center location of the AoE
|
* @param localLocation the center location of the AoE
|
||||||
* @param size the size of the area (ie. 3x3 AoE evaluates to size 3)
|
* @param sizeX the size of the area in tiles on the x axis
|
||||||
|
* @param sizeY the size of the area in tiles on the y axis
|
||||||
* @param zOffset offset from ground plane
|
* @param zOffset offset from ground plane
|
||||||
* @return a polygon representing the tiles in the area
|
* @return a polygon representing the tiles in the area
|
||||||
*/
|
*/
|
||||||
public static Polygon getCanvasTileAreaPoly(
|
public static Polygon getCanvasTileAreaPoly(
|
||||||
@Nonnull Client client,
|
@Nonnull Client client,
|
||||||
@Nonnull LocalPoint localLocation,
|
@Nonnull LocalPoint localLocation,
|
||||||
int size,
|
int sizeX,
|
||||||
|
int sizeY,
|
||||||
int zOffset)
|
int zOffset)
|
||||||
{
|
{
|
||||||
final int plane = client.getPlane();
|
final int plane = client.getPlane();
|
||||||
|
|
||||||
final int swX = localLocation.getX() - (size * LOCAL_TILE_SIZE / 2);
|
final int swX = localLocation.getX() - (sizeX * LOCAL_TILE_SIZE / 2);
|
||||||
final int swY = localLocation.getY() - (size * LOCAL_TILE_SIZE / 2);
|
final int swY = localLocation.getY() - (sizeY * LOCAL_TILE_SIZE / 2);
|
||||||
|
|
||||||
final int neX = localLocation.getX() + (size * LOCAL_TILE_SIZE / 2);
|
final int neX = localLocation.getX() + (sizeX * LOCAL_TILE_SIZE / 2);
|
||||||
final int neY = localLocation.getY() + (size * LOCAL_TILE_SIZE / 2);
|
final int neY = localLocation.getY() + (sizeY * LOCAL_TILE_SIZE / 2);
|
||||||
|
|
||||||
final byte[][][] tileSettings = client.getTileSettings();
|
final byte[][][] tileSettings = client.getTileSettings();
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import net.runelite.api.ChatMessageType;
|
|||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.Constants;
|
import net.runelite.api.Constants;
|
||||||
import net.runelite.api.GameState;
|
import net.runelite.api.GameState;
|
||||||
|
import net.runelite.api.Player;
|
||||||
import net.runelite.client.chat.ChatColorType;
|
import net.runelite.client.chat.ChatColorType;
|
||||||
import net.runelite.client.chat.ChatMessageBuilder;
|
import net.runelite.client.chat.ChatMessageBuilder;
|
||||||
import net.runelite.client.chat.ChatMessageManager;
|
import net.runelite.client.chat.ChatMessageManager;
|
||||||
@@ -175,7 +176,7 @@ public class Notifier
|
|||||||
|
|
||||||
if (runeLiteConfig.enableTrayNotifications())
|
if (runeLiteConfig.enableTrayNotifications())
|
||||||
{
|
{
|
||||||
sendNotification(appName, message, type);
|
sendNotification(buildTitle(), message, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (runeLiteConfig.notificationSound())
|
switch (runeLiteConfig.notificationSound())
|
||||||
@@ -210,6 +211,23 @@ public class Notifier
|
|||||||
log.debug(message);
|
log.debug(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String buildTitle()
|
||||||
|
{
|
||||||
|
Player player = client.getLocalPlayer();
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
return appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = player.getName();
|
||||||
|
if (Strings.isNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
return appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return appName + " - " + name;
|
||||||
|
}
|
||||||
|
|
||||||
public void processFlash(final Graphics2D graphics)
|
public void processFlash(final Graphics2D graphics)
|
||||||
{
|
{
|
||||||
FlashNotification flashNotification = runeLiteConfig.flashNotification();
|
FlashNotification flashNotification = runeLiteConfig.flashNotification();
|
||||||
|
|||||||
@@ -106,11 +106,6 @@ public class ChatCommandManager implements ChatboxInputListener
|
|||||||
String message = chatMessage.getMessage();
|
String message = chatMessage.getMessage();
|
||||||
|
|
||||||
String command = extractCommand(message);
|
String command = extractCommand(message);
|
||||||
if (command == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
||||||
if (chatCommand == null)
|
if (chatCommand == null)
|
||||||
{
|
{
|
||||||
@@ -137,11 +132,6 @@ public class ChatCommandManager implements ChatboxInputListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
String command = extractCommand(message);
|
String command = extractCommand(message);
|
||||||
if (command == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
||||||
if (chatCommand == null)
|
if (chatCommand == null)
|
||||||
{
|
{
|
||||||
@@ -163,11 +153,6 @@ public class ChatCommandManager implements ChatboxInputListener
|
|||||||
final String message = privateMessageInput.getMessage();
|
final String message = privateMessageInput.getMessage();
|
||||||
|
|
||||||
String command = extractCommand(message);
|
String command = extractCommand(message);
|
||||||
if (command == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
||||||
if (chatCommand == null)
|
if (chatCommand == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,22 +39,22 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import net.runelite.api.ChatLineBuffer;
|
|
||||||
import net.runelite.api.ChatMessageType;
|
import net.runelite.api.ChatMessageType;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.MessageNode;
|
import net.runelite.api.MessageNode;
|
||||||
import net.runelite.api.Player;
|
import net.runelite.api.Player;
|
||||||
import net.runelite.api.Varbits;
|
import net.runelite.api.Varbits;
|
||||||
import net.runelite.api.events.ChatMessage;
|
import net.runelite.api.events.ChatMessage;
|
||||||
import net.runelite.client.events.ConfigChanged;
|
|
||||||
import net.runelite.api.events.ResizeableChanged;
|
import net.runelite.api.events.ResizeableChanged;
|
||||||
import net.runelite.api.events.ScriptCallbackEvent;
|
import net.runelite.api.events.ScriptCallbackEvent;
|
||||||
import net.runelite.api.events.VarbitChanged;
|
import net.runelite.api.events.VarbitChanged;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
import net.runelite.client.config.ChatColorConfig;
|
import net.runelite.client.config.ChatColorConfig;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
|
import net.runelite.client.events.ConfigChanged;
|
||||||
import net.runelite.client.ui.JagexColors;
|
import net.runelite.client.ui.JagexColors;
|
||||||
import net.runelite.client.util.ColorUtil;
|
import net.runelite.client.util.ColorUtil;
|
||||||
|
import net.runelite.client.util.Text;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class ChatMessageManager
|
public class ChatMessageManager
|
||||||
@@ -126,7 +126,8 @@ public class ChatMessageManager
|
|||||||
case PUBLICCHAT:
|
case PUBLICCHAT:
|
||||||
case MODCHAT:
|
case MODCHAT:
|
||||||
{
|
{
|
||||||
boolean isFriend = client.isFriended(chatMessage.getName(), true) && !client.getLocalPlayer().getName().equals(chatMessage.getName());
|
String sanitizedUsername = Text.removeTags(chatMessage.getName());
|
||||||
|
boolean isFriend = client.isFriended(sanitizedUsername, true) && !client.getLocalPlayer().getName().equals(sanitizedUsername);
|
||||||
|
|
||||||
if (isFriend)
|
if (isFriend)
|
||||||
{
|
{
|
||||||
@@ -571,18 +572,15 @@ public class ChatMessageManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String formattedMessage = formatRuneLiteMessage(message.getRuneLiteFormattedMessage(), message.getType());
|
||||||
|
|
||||||
// this updates chat cycle
|
// this updates chat cycle
|
||||||
client.addChatMessage(
|
final MessageNode line = client.addChatMessage(
|
||||||
message.getType(),
|
message.getType(),
|
||||||
MoreObjects.firstNonNull(message.getName(), ""),
|
MoreObjects.firstNonNull(message.getName(), ""),
|
||||||
MoreObjects.firstNonNull(message.getValue(), message.getRuneLiteFormattedMessage()),
|
MoreObjects.firstNonNull(formattedMessage, message.getValue()),
|
||||||
message.getSender());
|
message.getSender());
|
||||||
|
|
||||||
// Get last message from line buffer (the one we just added)
|
|
||||||
final ChatLineBuffer chatLineBuffer = client.getChatLineMap().get(message.getType().getType());
|
|
||||||
final MessageNode[] lines = chatLineBuffer.getLines();
|
|
||||||
final MessageNode line = lines[0];
|
|
||||||
|
|
||||||
// Update the message with RuneLite additions
|
// Update the message with RuneLite additions
|
||||||
line.setRuneLiteFormatMessage(message.getRuneLiteFormattedMessage());
|
line.setRuneLiteFormatMessage(message.getRuneLiteFormattedMessage());
|
||||||
|
|
||||||
@@ -590,34 +588,38 @@ public class ChatMessageManager
|
|||||||
{
|
{
|
||||||
line.setTimestamp(message.getTimestamp());
|
line.setTimestamp(message.getTimestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
update(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(final MessageNode target)
|
/**
|
||||||
|
* Rebuild the message node message from the RuneLite format message
|
||||||
|
*
|
||||||
|
* @param messageNode message node
|
||||||
|
*/
|
||||||
|
public void update(final MessageNode messageNode)
|
||||||
{
|
{
|
||||||
if (Strings.isNullOrEmpty(target.getRuneLiteFormatMessage()))
|
String message = formatRuneLiteMessage(messageNode.getRuneLiteFormatMessage(), messageNode.getType());
|
||||||
|
if (message != null)
|
||||||
{
|
{
|
||||||
return;
|
messageNode.setValue(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatRuneLiteMessage(String runeLiteFormatMessage, ChatMessageType type)
|
||||||
|
{
|
||||||
|
if (Strings.isNullOrEmpty(runeLiteFormatMessage))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean transparent = client.isResized() && transparencyVarbit != 0;
|
final boolean transparent = client.isResized() && transparencyVarbit != 0;
|
||||||
final Collection<ChatColor> chatColors = colorCache.get(target.getType());
|
final Collection<ChatColor> chatColors = colorCache.get(type);
|
||||||
|
|
||||||
// If we do not have any colors cached, simply set clean message
|
|
||||||
if (chatColors == null || chatColors.isEmpty())
|
if (chatColors == null || chatColors.isEmpty())
|
||||||
{
|
{
|
||||||
target.setValue(target.getRuneLiteFormatMessage());
|
return runeLiteFormatMessage;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
target.setValue(recolorMessage(transparent, target.getRuneLiteFormatMessage(), target.getType()));
|
final AtomicReference<String> resultMessage = new AtomicReference<>(runeLiteFormatMessage);
|
||||||
}
|
|
||||||
|
|
||||||
private String recolorMessage(boolean transparent, String message, ChatMessageType messageType)
|
|
||||||
{
|
|
||||||
final Collection<ChatColor> chatColors = colorCache.get(messageType);
|
|
||||||
final AtomicReference<String> resultMessage = new AtomicReference<>(message);
|
|
||||||
|
|
||||||
// Replace custom formatting with actual colors
|
// Replace custom formatting with actual colors
|
||||||
chatColors.stream()
|
chatColors.stream()
|
||||||
|
|||||||
@@ -152,6 +152,11 @@ public class ConfigManager
|
|||||||
scheduledExecutorService.scheduleWithFixedDelay(this::sendConfig, 30, 30, TimeUnit.SECONDS);
|
scheduledExecutorService.scheduleWithFixedDelay(this::sendConfig, 30, 30, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRSProfileKey()
|
||||||
|
{
|
||||||
|
return rsProfileKey;
|
||||||
|
}
|
||||||
|
|
||||||
public final void switchSession(AccountSession session)
|
public final void switchSession(AccountSession session)
|
||||||
{
|
{
|
||||||
// Ensure existing config is saved
|
// Ensure existing config is saved
|
||||||
@@ -507,6 +512,11 @@ public class ConfigManager
|
|||||||
|
|
||||||
public void setConfiguration(String groupName, String profile, String key, String value)
|
public void setConfiguration(String groupName, String profile, String key, String value)
|
||||||
{
|
{
|
||||||
|
if (Strings.isNullOrEmpty(groupName) || Strings.isNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
assert !key.startsWith(RSPROFILE_GROUP + ".");
|
assert !key.startsWith(RSPROFILE_GROUP + ".");
|
||||||
String wholeKey = getWholeKey(groupName, profile, key);
|
String wholeKey = getWholeKey(groupName, profile, key);
|
||||||
String oldValue = (String) properties.setProperty(wholeKey, value);
|
String oldValue = (String) properties.setProperty(wholeKey, value);
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ import java.util.Map;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.runelite.api.ItemID;
|
import net.runelite.api.ItemID;
|
||||||
import static net.runelite.api.NpcID.FISHING_SPOT;
|
import static net.runelite.api.NpcID.FISHING_SPOT;
|
||||||
|
import static net.runelite.api.NpcID.FISHING_SPOT_10513;
|
||||||
|
import static net.runelite.api.NpcID.FISHING_SPOT_10514;
|
||||||
|
import static net.runelite.api.NpcID.FISHING_SPOT_10515;
|
||||||
import static net.runelite.api.NpcID.FISHING_SPOT_1497;
|
import static net.runelite.api.NpcID.FISHING_SPOT_1497;
|
||||||
import static net.runelite.api.NpcID.FISHING_SPOT_1498;
|
import static net.runelite.api.NpcID.FISHING_SPOT_1498;
|
||||||
import static net.runelite.api.NpcID.FISHING_SPOT_1499;
|
import static net.runelite.api.NpcID.FISHING_SPOT_1499;
|
||||||
@@ -132,13 +135,14 @@ public enum FishingSpot
|
|||||||
FISHING_SPOT_1525, FISHING_SPOT_1528, FISHING_SPOT_1530,
|
FISHING_SPOT_1525, FISHING_SPOT_1528, FISHING_SPOT_1530,
|
||||||
FISHING_SPOT_1544, FISHING_SPOT_3913, FISHING_SPOT_7155,
|
FISHING_SPOT_1544, FISHING_SPOT_3913, FISHING_SPOT_7155,
|
||||||
FISHING_SPOT_7459, FISHING_SPOT_7462, FISHING_SPOT_7467,
|
FISHING_SPOT_7459, FISHING_SPOT_7462, FISHING_SPOT_7467,
|
||||||
FISHING_SPOT_7469, FISHING_SPOT_7947
|
FISHING_SPOT_7469, FISHING_SPOT_7947, FISHING_SPOT_10513
|
||||||
),
|
),
|
||||||
LOBSTER("Lobster, Swordfish, Tuna", "Lobster", ItemID.RAW_LOBSTER,
|
LOBSTER("Lobster, Swordfish, Tuna", "Lobster", ItemID.RAW_LOBSTER,
|
||||||
FISHING_SPOT_1510, FISHING_SPOT_1519, FISHING_SPOT_1522,
|
FISHING_SPOT_1510, FISHING_SPOT_1519, FISHING_SPOT_1522,
|
||||||
FISHING_SPOT_3914, FISHING_SPOT_5820, FISHING_SPOT_7199,
|
FISHING_SPOT_3914, FISHING_SPOT_5820, FISHING_SPOT_7199,
|
||||||
FISHING_SPOT_7460, FISHING_SPOT_7465, FISHING_SPOT_7470,
|
FISHING_SPOT_7460, FISHING_SPOT_7465, FISHING_SPOT_7470,
|
||||||
FISHING_SPOT_7946, FISHING_SPOT_9173, FISHING_SPOT_9174
|
FISHING_SPOT_7946, FISHING_SPOT_9173, FISHING_SPOT_9174,
|
||||||
|
FISHING_SPOT_10515
|
||||||
),
|
),
|
||||||
SHARK("Shark, Bass", "Shark", ItemID.RAW_SHARK,
|
SHARK("Shark, Bass", "Shark", ItemID.RAW_SHARK,
|
||||||
FISHING_SPOT_1511, FISHING_SPOT_1520, FISHING_SPOT_3419,
|
FISHING_SPOT_1511, FISHING_SPOT_1520, FISHING_SPOT_3419,
|
||||||
@@ -146,7 +150,7 @@ public enum FishingSpot
|
|||||||
FISHING_SPOT_5233, FISHING_SPOT_5234, FISHING_SPOT_5821,
|
FISHING_SPOT_5233, FISHING_SPOT_5234, FISHING_SPOT_5821,
|
||||||
FISHING_SPOT_7200, FISHING_SPOT_7461, FISHING_SPOT_7466,
|
FISHING_SPOT_7200, FISHING_SPOT_7461, FISHING_SPOT_7466,
|
||||||
FISHING_SPOT_8525, FISHING_SPOT_8526, FISHING_SPOT_8527,
|
FISHING_SPOT_8525, FISHING_SPOT_8526, FISHING_SPOT_8527,
|
||||||
FISHING_SPOT_9171, FISHING_SPOT_9172
|
FISHING_SPOT_9171, FISHING_SPOT_9172, FISHING_SPOT_10514
|
||||||
),
|
),
|
||||||
MONKFISH("Monkfish", ItemID.RAW_MONKFISH,
|
MONKFISH("Monkfish", ItemID.RAW_MONKFISH,
|
||||||
FISHING_SPOT_4316
|
FISHING_SPOT_4316
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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 HOLDER 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.banktags;
|
||||||
|
|
||||||
|
public interface BankTag
|
||||||
|
{
|
||||||
|
boolean contains(int itemId);
|
||||||
|
}
|
||||||
@@ -75,13 +75,11 @@ import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
|||||||
import net.runelite.client.input.MouseManager;
|
import net.runelite.client.input.MouseManager;
|
||||||
import net.runelite.client.input.MouseWheelListener;
|
import net.runelite.client.input.MouseWheelListener;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import net.runelite.client.plugins.PluginDependency;
|
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
import net.runelite.client.plugins.banktags.tabs.TabInterface;
|
import net.runelite.client.plugins.banktags.tabs.TabInterface;
|
||||||
import static net.runelite.client.plugins.banktags.tabs.TabInterface.FILTERED_CHARS;
|
import static net.runelite.client.plugins.banktags.tabs.TabInterface.FILTERED_CHARS;
|
||||||
import net.runelite.client.plugins.banktags.tabs.TabSprites;
|
import net.runelite.client.plugins.banktags.tabs.TabSprites;
|
||||||
import net.runelite.client.plugins.banktags.tabs.TagTab;
|
import net.runelite.client.plugins.banktags.tabs.TagTab;
|
||||||
import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin;
|
|
||||||
import net.runelite.client.util.Text;
|
import net.runelite.client.util.Text;
|
||||||
|
|
||||||
@PluginDescriptor(
|
@PluginDescriptor(
|
||||||
@@ -89,7 +87,6 @@ import net.runelite.client.util.Text;
|
|||||||
description = "Enable tagging of bank items and searching of bank tags",
|
description = "Enable tagging of bank items and searching of bank tags",
|
||||||
tags = {"searching", "tagging"}
|
tags = {"searching", "tagging"}
|
||||||
)
|
)
|
||||||
@PluginDependency(ClueScrollPlugin.class)
|
|
||||||
public class BankTagsPlugin extends Plugin implements MouseWheelListener
|
public class BankTagsPlugin extends Plugin implements MouseWheelListener
|
||||||
{
|
{
|
||||||
public static final String CONFIG_GROUP = "banktags";
|
public static final String CONFIG_GROUP = "banktags";
|
||||||
|
|||||||
@@ -27,24 +27,17 @@ package net.runelite.client.plugins.banktags;
|
|||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import net.runelite.api.ItemID;
|
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
import net.runelite.client.game.ItemVariationMapping;
|
import net.runelite.client.game.ItemVariationMapping;
|
||||||
import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP;
|
import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP;
|
||||||
import net.runelite.client.plugins.cluescrolls.ClueScrollService;
|
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.ClueScroll;
|
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.CoordinateClue;
|
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.EmoteClue;
|
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.FairyRingClue;
|
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.HotColdClue;
|
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.MapClue;
|
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirement;
|
|
||||||
import net.runelite.client.util.Text;
|
import net.runelite.client.util.Text;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -53,17 +46,15 @@ public class TagManager
|
|||||||
static final String ITEM_KEY_PREFIX = "item_";
|
static final String ITEM_KEY_PREFIX = "item_";
|
||||||
private final ConfigManager configManager;
|
private final ConfigManager configManager;
|
||||||
private final ItemManager itemManager;
|
private final ItemManager itemManager;
|
||||||
private final ClueScrollService clueScrollService;
|
private final Map<String, BankTag> customTags = new HashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private TagManager(
|
private TagManager(
|
||||||
final ItemManager itemManager,
|
final ItemManager itemManager,
|
||||||
final ConfigManager configManager,
|
final ConfigManager configManager)
|
||||||
final ClueScrollService clueScrollService)
|
|
||||||
{
|
{
|
||||||
this.itemManager = itemManager;
|
this.itemManager = itemManager;
|
||||||
this.configManager = configManager;
|
this.configManager = configManager;
|
||||||
this.clueScrollService = clueScrollService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String getTagString(int itemId, boolean variation)
|
String getTagString(int itemId, boolean variation)
|
||||||
@@ -123,7 +114,8 @@ public class TagManager
|
|||||||
|
|
||||||
boolean findTag(int itemId, String search)
|
boolean findTag(int itemId, String search)
|
||||||
{
|
{
|
||||||
if (search.equals("clue") && testClue(itemId))
|
BankTag bankTag = customTags.get(search);
|
||||||
|
if (bankTag != null && bankTag.contains(itemId))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -194,38 +186,13 @@ public class TagManager
|
|||||||
return itemId;
|
return itemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean testClue(int itemId)
|
public void registerTag(String name, BankTag tag)
|
||||||
{
|
{
|
||||||
ClueScroll c = clueScrollService.getClue();
|
customTags.put(name, tag);
|
||||||
|
}
|
||||||
|
|
||||||
if (c == null)
|
public void unregisterTag(String name)
|
||||||
{
|
{
|
||||||
return false;
|
customTags.remove(name);
|
||||||
}
|
|
||||||
|
|
||||||
if (c instanceof EmoteClue)
|
|
||||||
{
|
|
||||||
EmoteClue emote = (EmoteClue) c;
|
|
||||||
|
|
||||||
for (ItemRequirement ir : emote.getItemRequirements())
|
|
||||||
{
|
|
||||||
if (ir.fulfilledBy(itemId))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (c instanceof CoordinateClue || c instanceof HotColdClue || c instanceof FairyRingClue)
|
|
||||||
{
|
|
||||||
return itemId == ItemID.SPADE;
|
|
||||||
}
|
|
||||||
else if (c instanceof MapClue)
|
|
||||||
{
|
|
||||||
MapClue mapClue = (MapClue) c;
|
|
||||||
|
|
||||||
return mapClue.getObjectId() == -1 && itemId == ItemID.SPADE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,7 +304,8 @@ public class CannonPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.getMessage().contains("You pick up the cannon")
|
if (event.getMessage().contains("You pick up the cannon")
|
||||||
|| event.getMessage().contains("Your cannon has decayed. Speak to Nulodion to get a new one!"))
|
|| event.getMessage().contains("Your cannon has decayed. Speak to Nulodion to get a new one!")
|
||||||
|
|| event.getMessage().contains("Your cannon has been destroyed!"))
|
||||||
{
|
{
|
||||||
cannonPlaced = false;
|
cannonPlaced = false;
|
||||||
cballsLeft = 0;
|
cballsLeft = 0;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ enum CannonSpots
|
|||||||
DUST_DEVIL(new WorldPoint(3218, 9366, 0)),
|
DUST_DEVIL(new WorldPoint(3218, 9366, 0)),
|
||||||
EARTH_WARRIOR(new WorldPoint(3120, 9987, 0)),
|
EARTH_WARRIOR(new WorldPoint(3120, 9987, 0)),
|
||||||
ELDER_CHAOS_DRUID(new WorldPoint(3237, 3622, 0)),
|
ELDER_CHAOS_DRUID(new WorldPoint(3237, 3622, 0)),
|
||||||
ELVES(new WorldPoint(2044, 4635, 0), new WorldPoint(3278, 6098, 0)),
|
ELVES(new WorldPoint(3278, 6098, 0)),
|
||||||
FIRE_GIANTS(new WorldPoint(2393, 9782, 0), new WorldPoint(2412, 9776, 0), new WorldPoint(2401, 9780, 0), new WorldPoint(3047, 10340, 0)),
|
FIRE_GIANTS(new WorldPoint(2393, 9782, 0), new WorldPoint(2412, 9776, 0), new WorldPoint(2401, 9780, 0), new WorldPoint(3047, 10340, 0)),
|
||||||
GREATER_DEMONS(new WorldPoint(1435, 10086, 2), new WorldPoint(3224, 10132, 0)),
|
GREATER_DEMONS(new WorldPoint(1435, 10086, 2), new WorldPoint(3224, 10132, 0)),
|
||||||
GREEN_DRAGON(new WorldPoint(3225, 10068, 0)),
|
GREEN_DRAGON(new WorldPoint(3225, 10068, 0)),
|
||||||
|
|||||||
@@ -666,7 +666,7 @@ public class ChatCommandsPlugin extends Plugin
|
|||||||
.append(ChatColorType.NORMAL)
|
.append(ChatColorType.NORMAL)
|
||||||
.append(" kill count: ")
|
.append(" kill count: ")
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append(Integer.toString(kc))
|
.append(String.format("%,d", kc))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
log.debug("Setting response {}", response);
|
log.debug("Setting response {}", response);
|
||||||
@@ -748,15 +748,15 @@ public class ChatCommandsPlugin extends Plugin
|
|||||||
.append(ChatColorType.NORMAL)
|
.append(ChatColorType.NORMAL)
|
||||||
.append("Duel Arena wins: ")
|
.append("Duel Arena wins: ")
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append(Integer.toString(wins))
|
.append(String.format("%,d", wins))
|
||||||
.append(ChatColorType.NORMAL)
|
.append(ChatColorType.NORMAL)
|
||||||
.append(" losses: ")
|
.append(" losses: ")
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append(Integer.toString(losses))
|
.append(String.format("%,d", losses))
|
||||||
.append(ChatColorType.NORMAL)
|
.append(ChatColorType.NORMAL)
|
||||||
.append(" streak: ")
|
.append(" streak: ")
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append(Integer.toString((winningStreak != 0 ? winningStreak : -losingStreak)))
|
.append(String.format("%,d", winningStreak != 0 ? winningStreak : -losingStreak))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
log.debug("Setting response {}", response);
|
log.debug("Setting response {}", response);
|
||||||
@@ -957,7 +957,7 @@ public class ChatCommandsPlugin extends Plugin
|
|||||||
.append(ChatColorType.NORMAL)
|
.append(ChatColorType.NORMAL)
|
||||||
.append("Barbarian Assault High-level gambles: ")
|
.append("Barbarian Assault High-level gambles: ")
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append(Integer.toString(gc))
|
.append(String.format("%,d", gc))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
log.debug("Setting response {}", response);
|
log.debug("Setting response {}", response);
|
||||||
@@ -1420,7 +1420,7 @@ public class ChatCommandsPlugin extends Plugin
|
|||||||
.append(ChatColorType.NORMAL)
|
.append(ChatColorType.NORMAL)
|
||||||
.append("Clue scroll (" + level + ")").append(": ")
|
.append("Clue scroll (" + level + ")").append(": ")
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append(Integer.toString(quantity));
|
.append(String.format("%,d", quantity));
|
||||||
|
|
||||||
if (rank != -1)
|
if (rank != -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ import net.runelite.api.widgets.WidgetInfo;
|
|||||||
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
||||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
import net.runelite.client.chat.ChatMessageManager;
|
|
||||||
import net.runelite.client.chat.QueuedMessage;
|
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.input.KeyListener;
|
import net.runelite.client.input.KeyListener;
|
||||||
@@ -82,7 +80,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
|||||||
private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB;
|
private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB;
|
||||||
private static final int FRIENDS_MAX_SIZE = 5;
|
private static final int FRIENDS_MAX_SIZE = 5;
|
||||||
|
|
||||||
private Queue<QueuedMessage> messageQueue;
|
private Queue<MessageNode> messageQueue;
|
||||||
private Deque<String> friends;
|
private Deque<String> friends;
|
||||||
|
|
||||||
private String currentMessage = null;
|
private String currentMessage = null;
|
||||||
@@ -99,9 +97,6 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
|||||||
@Inject
|
@Inject
|
||||||
private KeyManager keyManager;
|
private KeyManager keyManager;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private ChatMessageManager chatMessageManager;
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
ChatHistoryConfig getConfig(ConfigManager configManager)
|
ChatHistoryConfig getConfig(ConfigManager configManager)
|
||||||
{
|
{
|
||||||
@@ -111,6 +106,9 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
|||||||
@Override
|
@Override
|
||||||
protected void startUp()
|
protected void startUp()
|
||||||
{
|
{
|
||||||
|
// The client reuses MessageNodes after 100 chat messages of
|
||||||
|
// the same type, so this must be 100 (or maybe a map of
|
||||||
|
// size 100 evicting queues)
|
||||||
messageQueue = EvictingQueue.create(100);
|
messageQueue = EvictingQueue.create(100);
|
||||||
friends = new ArrayDeque<>(FRIENDS_MAX_SIZE + 1);
|
friends = new ArrayDeque<>(FRIENDS_MAX_SIZE + 1);
|
||||||
keyManager.registerKeyListener(this);
|
keyManager.registerKeyListener(this);
|
||||||
@@ -140,11 +138,16 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QueuedMessage queuedMessage;
|
for (MessageNode queuedMessage : messageQueue)
|
||||||
|
|
||||||
while ((queuedMessage = messageQueue.poll()) != null)
|
|
||||||
{
|
{
|
||||||
chatMessageManager.queue(queuedMessage);
|
final MessageNode node = client.addChatMessage(
|
||||||
|
queuedMessage.getType(),
|
||||||
|
queuedMessage.getName(),
|
||||||
|
queuedMessage.getValue(),
|
||||||
|
queuedMessage.getSender(),
|
||||||
|
false);
|
||||||
|
node.setRuneLiteFormatMessage(queuedMessage.getRuneLiteFormatMessage());
|
||||||
|
node.setTimestamp(queuedMessage.getTimestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -171,19 +174,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
|||||||
case MODCHAT:
|
case MODCHAT:
|
||||||
case FRIENDSCHAT:
|
case FRIENDSCHAT:
|
||||||
case CONSOLE:
|
case CONSOLE:
|
||||||
final QueuedMessage queuedMessage = QueuedMessage.builder()
|
messageQueue.offer(chatMessage.getMessageNode());
|
||||||
.type(chatMessageType)
|
|
||||||
.name(chatMessage.getName())
|
|
||||||
.sender(chatMessage.getSender())
|
|
||||||
.value(nbsp(chatMessage.getMessage()))
|
|
||||||
.runeLiteFormattedMessage(nbsp(chatMessage.getMessageNode().getRuneLiteFormatMessage()))
|
|
||||||
.timestamp(chatMessage.getTimestamp())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if (!messageQueue.contains(queuedMessage))
|
|
||||||
{
|
|
||||||
messageQueue.offer(queuedMessage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,21 +339,6 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
|||||||
clearMessageQueue(tab);
|
clearMessageQueue(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Small hack to prevent plugins checking for specific messages to match
|
|
||||||
* @param message message
|
|
||||||
* @return message with nbsp
|
|
||||||
*/
|
|
||||||
private static String nbsp(final String message)
|
|
||||||
{
|
|
||||||
if (message != null)
|
|
||||||
{
|
|
||||||
return message.replace(' ', '\u00A0');
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyPressed(KeyEvent e)
|
public void keyPressed(KeyEvent e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -108,4 +108,15 @@ public interface ChatNotificationsConfig extends Config
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
position = 7,
|
||||||
|
keyName = "notifyOnPM",
|
||||||
|
name = "Notify on private message",
|
||||||
|
description = "Notifies you whenever you receive a private message"
|
||||||
|
)
|
||||||
|
default boolean notifyOnPM()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,13 @@ public class ChatNotificationsPlugin extends Plugin
|
|||||||
notifier.notify(Text.removeFormattingTags(broadcast));
|
notifier.notify(Text.removeFormattingTags(broadcast));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PRIVATECHAT:
|
||||||
|
case MODPRIVATECHAT:
|
||||||
|
if (config.notifyOnPM())
|
||||||
|
{
|
||||||
|
notifier.notify(Text.removeTags(chatMessage.getName()) + ": " + chatMessage.getMessage());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CONSOLE:
|
case CONSOLE:
|
||||||
// Don't notify for notification messages
|
// Don't notify for notification messages
|
||||||
if (chatMessage.getName().equals(runeliteTitle))
|
if (chatMessage.getName().equals(runeliteTitle))
|
||||||
|
|||||||
@@ -96,7 +96,10 @@ import net.runelite.client.events.ConfigChanged;
|
|||||||
import net.runelite.client.events.OverlayMenuClicked;
|
import net.runelite.client.events.OverlayMenuClicked;
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
|
import net.runelite.client.plugins.PluginDependency;
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
|
import net.runelite.client.plugins.banktags.BankTagsPlugin;
|
||||||
|
import net.runelite.client.plugins.banktags.TagManager;
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.AnagramClue;
|
import net.runelite.client.plugins.cluescrolls.clues.AnagramClue;
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.BeginnerMapClue;
|
import net.runelite.client.plugins.cluescrolls.clues.BeginnerMapClue;
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.CipherClue;
|
import net.runelite.client.plugins.cluescrolls.clues.CipherClue;
|
||||||
@@ -117,6 +120,7 @@ import net.runelite.client.plugins.cluescrolls.clues.ObjectClueScroll;
|
|||||||
import net.runelite.client.plugins.cluescrolls.clues.SkillChallengeClue;
|
import net.runelite.client.plugins.cluescrolls.clues.SkillChallengeClue;
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.TextClueScroll;
|
import net.runelite.client.plugins.cluescrolls.clues.TextClueScroll;
|
||||||
import net.runelite.client.plugins.cluescrolls.clues.ThreeStepCrypticClue;
|
import net.runelite.client.plugins.cluescrolls.clues.ThreeStepCrypticClue;
|
||||||
|
import net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirement;
|
||||||
import net.runelite.client.ui.overlay.OverlayManager;
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
import net.runelite.client.ui.overlay.OverlayMenuEntry;
|
import net.runelite.client.ui.overlay.OverlayMenuEntry;
|
||||||
import net.runelite.client.ui.overlay.OverlayUtil;
|
import net.runelite.client.ui.overlay.OverlayUtil;
|
||||||
@@ -131,6 +135,7 @@ import org.apache.commons.lang3.ArrayUtils;
|
|||||||
description = "Show answers to clue scroll riddles, anagrams, ciphers, and cryptic clues",
|
description = "Show answers to clue scroll riddles, anagrams, ciphers, and cryptic clues",
|
||||||
tags = {"arrow", "hints", "world", "map", "coordinates", "emotes"}
|
tags = {"arrow", "hints", "world", "map", "coordinates", "emotes"}
|
||||||
)
|
)
|
||||||
|
@PluginDependency(BankTagsPlugin.class)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ClueScrollPlugin extends Plugin
|
public class ClueScrollPlugin extends Plugin
|
||||||
{
|
{
|
||||||
@@ -144,6 +149,7 @@ public class ClueScrollPlugin extends Plugin
|
|||||||
13150, 9011,
|
13150, 9011,
|
||||||
13151, 9012
|
13151, 9012
|
||||||
};
|
};
|
||||||
|
private static final String CLUE_TAG_NAME = "clue";
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private ClueScroll clue;
|
private ClueScroll clue;
|
||||||
@@ -191,6 +197,9 @@ public class ClueScrollPlugin extends Plugin
|
|||||||
@Inject
|
@Inject
|
||||||
private WorldMapPointManager worldMapPointManager;
|
private WorldMapPointManager worldMapPointManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private TagManager tagManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@Named("developerMode")
|
@Named("developerMode")
|
||||||
boolean developerMode;
|
boolean developerMode;
|
||||||
@@ -227,11 +236,13 @@ public class ClueScrollPlugin extends Plugin
|
|||||||
overlayManager.add(clueScrollEmoteOverlay);
|
overlayManager.add(clueScrollEmoteOverlay);
|
||||||
overlayManager.add(clueScrollWorldOverlay);
|
overlayManager.add(clueScrollWorldOverlay);
|
||||||
overlayManager.add(clueScrollMusicOverlay);
|
overlayManager.add(clueScrollMusicOverlay);
|
||||||
|
tagManager.registerTag(CLUE_TAG_NAME, this::testClueTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void shutDown() throws Exception
|
protected void shutDown() throws Exception
|
||||||
{
|
{
|
||||||
|
tagManager.unregisterTag(CLUE_TAG_NAME);
|
||||||
overlayManager.remove(clueScrollOverlay);
|
overlayManager.remove(clueScrollOverlay);
|
||||||
overlayManager.remove(clueScrollEmoteOverlay);
|
overlayManager.remove(clueScrollEmoteOverlay);
|
||||||
overlayManager.remove(clueScrollWorldOverlay);
|
overlayManager.remove(clueScrollWorldOverlay);
|
||||||
@@ -484,6 +495,10 @@ public class ClueScrollPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
resetClue(true);
|
resetClue(true);
|
||||||
}
|
}
|
||||||
|
else if (state == GameState.HOPPING)
|
||||||
|
{
|
||||||
|
namedObjectCheckThisTick = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -550,6 +565,7 @@ public class ClueScrollPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the current plane's tiles if a tick has elapsed since the player has changed planes
|
// Load the current plane's tiles if a tick has elapsed since the player has changed planes
|
||||||
|
// or upon reaching a logged in state after hopping worlds
|
||||||
if (namedObjectCheckThisTick)
|
if (namedObjectCheckThisTick)
|
||||||
{
|
{
|
||||||
namedObjectCheckThisTick = false;
|
namedObjectCheckThisTick = false;
|
||||||
@@ -569,7 +585,7 @@ public class ClueScrollPlugin extends Plugin
|
|||||||
if (chatDialogClueItem != null
|
if (chatDialogClueItem != null
|
||||||
&& (chatDialogClueItem.getItemId() == ItemID.CLUE_SCROLL_BEGINNER || chatDialogClueItem.getItemId() == ItemID.CLUE_SCROLL_MASTER))
|
&& (chatDialogClueItem.getItemId() == ItemID.CLUE_SCROLL_BEGINNER || chatDialogClueItem.getItemId() == ItemID.CLUE_SCROLL_MASTER))
|
||||||
{
|
{
|
||||||
resetClue(true);
|
resetClue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Widget clueScrollText = client.getWidget(WidgetInfo.CLUE_SCROLL_TEXT);
|
final Widget clueScrollText = client.getWidget(WidgetInfo.CLUE_SCROLL_TEXT);
|
||||||
@@ -1109,4 +1125,38 @@ public class ClueScrollPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
return worldPoint;
|
return worldPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean testClueTag(int itemId)
|
||||||
|
{
|
||||||
|
ClueScroll c = clue;
|
||||||
|
if (c == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c instanceof EmoteClue)
|
||||||
|
{
|
||||||
|
EmoteClue emote = (EmoteClue) c;
|
||||||
|
|
||||||
|
for (ItemRequirement ir : emote.getItemRequirements())
|
||||||
|
{
|
||||||
|
if (ir.fulfilledBy(itemId))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c instanceof CoordinateClue || c instanceof HotColdClue || c instanceof FairyRingClue)
|
||||||
|
{
|
||||||
|
return itemId == ItemID.SPADE;
|
||||||
|
}
|
||||||
|
else if (c instanceof MapClue)
|
||||||
|
{
|
||||||
|
MapClue mapClue = (MapClue) c;
|
||||||
|
|
||||||
|
return mapClue.getObjectId() == -1 && itemId == ItemID.SPADE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,6 +205,8 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati
|
|||||||
.put(new WorldPoint(2484, 4016, 0), new CoordinateClueInfo("Northeast corner of the Island of Stone.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2484, 4016, 0), new CoordinateClueInfo("Northeast corner of the Island of Stone.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2222, 3331, 0), new CoordinateClueInfo("Prifddinas, west of the Tower of Voices", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2222, 3331, 0), new CoordinateClueInfo("Prifddinas, west of the Tower of Voices", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3560, 3987, 0), new CoordinateClueInfo("Lithkren. Digsite pendant teleport if unlocked, otherwise take rowboat from west of Mushroom Meadow Mushtree.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3560, 3987, 0), new CoordinateClueInfo("Lithkren. Digsite pendant teleport if unlocked, otherwise take rowboat from west of Mushroom Meadow Mushtree.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
||||||
|
.put(new WorldPoint(2318, 2954, 0), new CoordinateClueInfo("North-east corner of the Isle of Souls.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
||||||
|
.put(new WorldPoint(2094, 2889, 0), new CoordinateClueInfo("West side of the Isle of Souls.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
||||||
// Master
|
// Master
|
||||||
.put(new WorldPoint(2178, 3209, 0), new CoordinateClueInfo("South of Iorwerth Camp.", BRASSICAN_MAGE))
|
.put(new WorldPoint(2178, 3209, 0), new CoordinateClueInfo("South of Iorwerth Camp.", BRASSICAN_MAGE))
|
||||||
.put(new WorldPoint(2155, 3100, 0), new CoordinateClueInfo("South of Port Tyras (BJS if 76 Agility).", BRASSICAN_MAGE))
|
.put(new WorldPoint(2155, 3100, 0), new CoordinateClueInfo("South of Port Tyras (BJS if 76 Agility).", BRASSICAN_MAGE))
|
||||||
@@ -227,7 +229,7 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati
|
|||||||
.put(new WorldPoint(2202, 3825, 0), new CoordinateClueInfo("Pirates' Cove, between Lunar Isle and Rellekka.", ANCIENT_WIZARDS))
|
.put(new WorldPoint(2202, 3825, 0), new CoordinateClueInfo("Pirates' Cove, between Lunar Isle and Rellekka.", ANCIENT_WIZARDS))
|
||||||
.put(new WorldPoint(1761, 3853, 0), new CoordinateClueInfo("Arceuus essence mine (CIS).", BRASSICAN_MAGE))
|
.put(new WorldPoint(1761, 3853, 0), new CoordinateClueInfo("Arceuus essence mine (CIS).", BRASSICAN_MAGE))
|
||||||
.put(new WorldPoint(2090, 3863, 0), new CoordinateClueInfo("South of Lunar Isle, west of Astral altar.", ANCIENT_WIZARDS))
|
.put(new WorldPoint(2090, 3863, 0), new CoordinateClueInfo("South of Lunar Isle, west of Astral altar.", ANCIENT_WIZARDS))
|
||||||
.put(new WorldPoint(1442, 3878, 0), new CoordinateClueInfo("Sulphur Mine.", BRASSICAN_MAGE))
|
.put(new WorldPoint(1442, 3878, 0), new CoordinateClueInfo("Northern area of the Lovakengj Sulphur Mine. Facemask or Slayer Helmet recommended.", BRASSICAN_MAGE))
|
||||||
.put(new WorldPoint(3380, 3929, 0), new CoordinateClueInfo("Wilderness. Near Volcano.", ANCIENT_WIZARDS))
|
.put(new WorldPoint(3380, 3929, 0), new CoordinateClueInfo("Wilderness. Near Volcano.", ANCIENT_WIZARDS))
|
||||||
.put(new WorldPoint(3188, 3939, 0), new CoordinateClueInfo("Wilderness. Resource Area.", BRASSICAN_MAGE))
|
.put(new WorldPoint(3188, 3939, 0), new CoordinateClueInfo("Wilderness. Resource Area.", BRASSICAN_MAGE))
|
||||||
.put(new WorldPoint(3304, 3941, 0), new CoordinateClueInfo("Wilderness. East of Rogues' Castle.", ANCIENT_WIZARDS))
|
.put(new WorldPoint(3304, 3941, 0), new CoordinateClueInfo("Wilderness. East of Rogues' Castle.", ANCIENT_WIZARDS))
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public enum HotColdLocation
|
|||||||
FREMENNIK_PROVINCE_LUNAR_VILLAGE(new WorldPoint(2084, 3916, 0), FREMENNIK_PROVINCE, "Lunar Isle, inside the village.", ANCIENT_WIZARDS),
|
FREMENNIK_PROVINCE_LUNAR_VILLAGE(new WorldPoint(2084, 3916, 0), FREMENNIK_PROVINCE, "Lunar Isle, inside the village.", ANCIENT_WIZARDS),
|
||||||
FREMENNIK_PROVINCE_LUNAR_NORTH(new WorldPoint(2106, 3949, 0), FREMENNIK_PROVINCE, "Lunar Isle, north of the village.", ANCIENT_WIZARDS),
|
FREMENNIK_PROVINCE_LUNAR_NORTH(new WorldPoint(2106, 3949, 0), FREMENNIK_PROVINCE, "Lunar Isle, north of the village.", ANCIENT_WIZARDS),
|
||||||
ICE_MOUNTAIN(new WorldPoint(3007, 3475, 0), MISTHALIN, "Atop Ice Mountain"),
|
ICE_MOUNTAIN(new WorldPoint(3007, 3475, 0), MISTHALIN, "Atop Ice Mountain"),
|
||||||
|
ISLE_OF_SOULS_MINE(new WorldPoint(2189, 2794, 0), KANDARIN, "Isle of Souls Mine, south of the Soul Wars lobby"),
|
||||||
KANDARIN_SINCLAR_MANSION(new WorldPoint(2730, 3588, 0), KANDARIN, "North-west of the Sinclair Mansion, near the log balance shortcut.", BRASSICAN_MAGE),
|
KANDARIN_SINCLAR_MANSION(new WorldPoint(2730, 3588, 0), KANDARIN, "North-west of the Sinclair Mansion, near the log balance shortcut.", BRASSICAN_MAGE),
|
||||||
KANDARIN_CATHERBY(new WorldPoint(2774, 3436, 0), KANDARIN, "Catherby, between the bank and the beehives, near small rock formation.", BRASSICAN_MAGE),
|
KANDARIN_CATHERBY(new WorldPoint(2774, 3436, 0), KANDARIN, "Catherby, between the bank and the beehives, near small rock formation.", BRASSICAN_MAGE),
|
||||||
KANDARIN_GRAND_TREE(new WorldPoint(2448, 3503, 0), KANDARIN, "Grand Tree, just east of the terrorchick gnome enclosure.", BRASSICAN_MAGE),
|
KANDARIN_GRAND_TREE(new WorldPoint(2448, 3503, 0), KANDARIN, "Grand Tree, just east of the terrorchick gnome enclosure.", BRASSICAN_MAGE),
|
||||||
@@ -164,7 +165,7 @@ public enum HotColdLocation
|
|||||||
ZEAH_BLASTMINE_NORTH(new WorldPoint(1488, 3881, 0), ZEAH, "Northern part of the Lovakengj blast mine.", BRASSICAN_MAGE),
|
ZEAH_BLASTMINE_NORTH(new WorldPoint(1488, 3881, 0), ZEAH, "Northern part of the Lovakengj blast mine.", BRASSICAN_MAGE),
|
||||||
ZEAH_LOVAKITE_FURNACE(new WorldPoint(1507, 3819, 0), ZEAH, "Next to the lovakite furnace in Lovakengj.", ANCIENT_WIZARDS),
|
ZEAH_LOVAKITE_FURNACE(new WorldPoint(1507, 3819, 0), ZEAH, "Next to the lovakite furnace in Lovakengj.", ANCIENT_WIZARDS),
|
||||||
ZEAH_LOVAKENGJ_MINE(new WorldPoint(1477, 3778, 0), ZEAH, "Next to mithril rock in the Lovakengj mine.", ANCIENT_WIZARDS),
|
ZEAH_LOVAKENGJ_MINE(new WorldPoint(1477, 3778, 0), ZEAH, "Next to mithril rock in the Lovakengj mine.", ANCIENT_WIZARDS),
|
||||||
ZEAH_SULPHR_MINE(new WorldPoint(1428, 3869, 0), ZEAH, "Western entrance in the Lovakengj sulphur mine.", BRASSICAN_MAGE),
|
ZEAH_SULPHR_MINE(new WorldPoint(1428, 3869, 0), ZEAH, "Western entrance in the Lovakengj sulphur mine. Facemask or Slayer Helmet recommended.", BRASSICAN_MAGE),
|
||||||
ZEAH_SHAYZIEN_BANK(new WorldPoint(1517, 3603, 0), ZEAH, "South-east of the bank in Shayzien.", ANCIENT_WIZARDS),
|
ZEAH_SHAYZIEN_BANK(new WorldPoint(1517, 3603, 0), ZEAH, "South-east of the bank in Shayzien.", ANCIENT_WIZARDS),
|
||||||
ZEAH_OVERPASS(new WorldPoint(1467, 3714, 0), ZEAH, "Overpass between Lovakengj and Shayzien.", BRASSICAN_MAGE),
|
ZEAH_OVERPASS(new WorldPoint(1467, 3714, 0), ZEAH, "Overpass between Lovakengj and Shayzien.", BRASSICAN_MAGE),
|
||||||
ZEAH_LIZARDMAN(new WorldPoint(1490, 3698, 0), ZEAH, "Within Lizardman Canyon, east of the ladder. Requires 5% favour with Shayzien.", ANCIENT_WIZARDS),
|
ZEAH_LIZARDMAN(new WorldPoint(1490, 3698, 0), ZEAH, "Within Lizardman Canyon, east of the ladder. Requires 5% favour with Shayzien.", ANCIENT_WIZARDS),
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ import net.runelite.api.Constants;
|
|||||||
import net.runelite.api.DecorativeObject;
|
import net.runelite.api.DecorativeObject;
|
||||||
import net.runelite.api.GameObject;
|
import net.runelite.api.GameObject;
|
||||||
import net.runelite.api.GraphicsObject;
|
import net.runelite.api.GraphicsObject;
|
||||||
import net.runelite.api.TileItem;
|
|
||||||
import net.runelite.api.GroundObject;
|
|
||||||
import net.runelite.api.ItemLayer;
|
import net.runelite.api.ItemLayer;
|
||||||
import net.runelite.api.NPC;
|
import net.runelite.api.NPC;
|
||||||
import net.runelite.api.NPCComposition;
|
import net.runelite.api.NPCComposition;
|
||||||
@@ -55,7 +53,8 @@ import net.runelite.api.Point;
|
|||||||
import net.runelite.api.Projectile;
|
import net.runelite.api.Projectile;
|
||||||
import net.runelite.api.Scene;
|
import net.runelite.api.Scene;
|
||||||
import net.runelite.api.Tile;
|
import net.runelite.api.Tile;
|
||||||
import net.runelite.api.WallObject;
|
import net.runelite.api.TileItem;
|
||||||
|
import net.runelite.api.TileObject;
|
||||||
import net.runelite.api.coords.LocalPoint;
|
import net.runelite.api.coords.LocalPoint;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
@@ -154,7 +153,6 @@ class DevToolsOverlay extends Overlay
|
|||||||
|
|
||||||
String text = local.getName() + " (A: " + local.getAnimation() + ") (P: " + local.getPoseAnimation() + ") (G: " + local.getGraphic() + ")";
|
String text = local.getName() + " (A: " + local.getAnimation() + ") (P: " + local.getPoseAnimation() + ") (G: " + local.getGraphic() + ")";
|
||||||
OverlayUtil.renderActorOverlay(graphics, local, text, CYAN);
|
OverlayUtil.renderActorOverlay(graphics, local, text, CYAN);
|
||||||
renderPlayerWireframe(graphics, local, CYAN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderNpcs(Graphics2D graphics)
|
private void renderNpcs(Graphics2D graphics)
|
||||||
@@ -214,7 +212,7 @@ class DevToolsOverlay extends Overlay
|
|||||||
|
|
||||||
if (plugin.getGroundObjects().isActive())
|
if (plugin.getGroundObjects().isActive())
|
||||||
{
|
{
|
||||||
renderGroundObject(graphics, tile, player);
|
renderTileObject(graphics, tile.getGroundObject(), player, PURPLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin.getGameObjects().isActive())
|
if (plugin.getGameObjects().isActive())
|
||||||
@@ -224,7 +222,7 @@ class DevToolsOverlay extends Overlay
|
|||||||
|
|
||||||
if (plugin.getWalls().isActive())
|
if (plugin.getWalls().isActive())
|
||||||
{
|
{
|
||||||
renderWallObject(graphics, tile, player);
|
renderTileObject(graphics, tile.getWallObject(), player, GRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin.getDecorations().isActive())
|
if (plugin.getDecorations().isActive())
|
||||||
@@ -309,45 +307,21 @@ class DevToolsOverlay extends Overlay
|
|||||||
{
|
{
|
||||||
for (GameObject gameObject : gameObjects)
|
for (GameObject gameObject : gameObjects)
|
||||||
{
|
{
|
||||||
if (gameObject != null)
|
if (gameObject != null && gameObject.getSceneMinLocation().equals(tile.getSceneLocation()))
|
||||||
{
|
{
|
||||||
if (player.getLocalLocation().distanceTo(gameObject.getLocalLocation()) <= MAX_DISTANCE)
|
renderTileObject(graphics, gameObject, player, GREEN);
|
||||||
{
|
|
||||||
OverlayUtil.renderTileOverlay(graphics, gameObject, "ID: " + gameObject.getId(), GREEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw a polygon around the convex hull
|
|
||||||
// of the model vertices
|
|
||||||
Shape p = gameObject.getConvexHull();
|
|
||||||
if (p != null)
|
|
||||||
{
|
|
||||||
graphics.draw(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderGroundObject(Graphics2D graphics, Tile tile, Player player)
|
private void renderTileObject(Graphics2D graphics, TileObject tileObject, Player player, Color color)
|
||||||
{
|
{
|
||||||
GroundObject groundObject = tile.getGroundObject();
|
if (tileObject != null)
|
||||||
if (groundObject != null)
|
|
||||||
{
|
{
|
||||||
if (player.getLocalLocation().distanceTo(groundObject.getLocalLocation()) <= MAX_DISTANCE)
|
if (player.getLocalLocation().distanceTo(tileObject.getLocalLocation()) <= MAX_DISTANCE)
|
||||||
{
|
{
|
||||||
OverlayUtil.renderTileOverlay(graphics, groundObject, "ID: " + groundObject.getId(), PURPLE);
|
OverlayUtil.renderTileOverlay(graphics, tileObject, "ID: " + tileObject.getId(), color);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderWallObject(Graphics2D graphics, Tile tile, Player player)
|
|
||||||
{
|
|
||||||
WallObject wallObject = tile.getWallObject();
|
|
||||||
if (wallObject != null)
|
|
||||||
{
|
|
||||||
if (player.getLocalLocation().distanceTo(wallObject.getLocalLocation()) <= MAX_DISTANCE)
|
|
||||||
{
|
|
||||||
OverlayUtil.renderTileOverlay(graphics, wallObject, "ID: " + wallObject.getId(), GRAY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,22 +421,4 @@ class DevToolsOverlay extends Overlay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderPlayerWireframe(Graphics2D graphics, Player player, Color color)
|
|
||||||
{
|
|
||||||
Polygon[] polys = player.getPolygons();
|
|
||||||
|
|
||||||
if (polys == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
graphics.setColor(color);
|
|
||||||
|
|
||||||
for (Polygon p : polys)
|
|
||||||
{
|
|
||||||
graphics.drawPolygon(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,16 +26,12 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.discord;
|
package net.runelite.client.plugins.discord;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.runelite.api.Client;
|
|
||||||
import net.runelite.api.Skill;
|
import net.runelite.api.Skill;
|
||||||
import net.runelite.api.Varbits;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
@@ -187,6 +183,7 @@ enum DiscordGameEventType
|
|||||||
DUNGEON_CRABCLAW_CAVES("Crabclaw Caves", DiscordAreaType.DUNGEONS, 6553, 6809),
|
DUNGEON_CRABCLAW_CAVES("Crabclaw Caves", DiscordAreaType.DUNGEONS, 6553, 6809),
|
||||||
DUNGEON_CRANDOR("Crandor Dungeon", DiscordAreaType.DUNGEONS, 11414),
|
DUNGEON_CRANDOR("Crandor Dungeon", DiscordAreaType.DUNGEONS, 11414),
|
||||||
DUNGEON_CRASH_SITE_CAVERN("Crash Site Cavern", DiscordAreaType.DUNGEONS, 8280, 8536),
|
DUNGEON_CRASH_SITE_CAVERN("Crash Site Cavern", DiscordAreaType.DUNGEONS, 8280, 8536),
|
||||||
|
DUNGEON_CRUMBLING_TOWER("Crumbling Tower", DiscordAreaType.DUNGEONS, 7827),
|
||||||
DUNGEON_DAEYALT_ESSENCE_MINE("Daeyalt Essence Mine", DiscordAreaType.DUNGEONS, 14744),
|
DUNGEON_DAEYALT_ESSENCE_MINE("Daeyalt Essence Mine", DiscordAreaType.DUNGEONS, 14744),
|
||||||
DUNGEON_DIGSITE("Digsite Dungeon", DiscordAreaType.DUNGEONS, 13464, 13465),
|
DUNGEON_DIGSITE("Digsite Dungeon", DiscordAreaType.DUNGEONS, 13464, 13465),
|
||||||
DUNGEON_DORGESHKAAN("Dorgesh-Kaan South Dungeon", DiscordAreaType.DUNGEONS, 10833),
|
DUNGEON_DORGESHKAAN("Dorgesh-Kaan South Dungeon", DiscordAreaType.DUNGEONS, 10833),
|
||||||
@@ -210,6 +207,7 @@ enum DiscordGameEventType
|
|||||||
DUNGEON_HAM_STORE_ROOM("H.A.M. Store room", DiscordAreaType.DUNGEONS, 10321),
|
DUNGEON_HAM_STORE_ROOM("H.A.M. Store room", DiscordAreaType.DUNGEONS, 10321),
|
||||||
DUNGEON_HEROES_GUILD("Heroes' Guild Mine", DiscordAreaType.DUNGEONS, 11674),
|
DUNGEON_HEROES_GUILD("Heroes' Guild Mine", DiscordAreaType.DUNGEONS, 11674),
|
||||||
DUNGEON_IORWERTH("Iorwerth Dungeon", DiscordAreaType.DUNGEONS, 12737, 12738, 12993, 12994),
|
DUNGEON_IORWERTH("Iorwerth Dungeon", DiscordAreaType.DUNGEONS, 12737, 12738, 12993, 12994),
|
||||||
|
DUNGEON_ISLE_OF_SOULS("Isle of Souls Dungeon", DiscordAreaType.DUNGEONS, 8593),
|
||||||
DUNGEON_JATIZSO_MINES("Jatizso Mines", DiscordAreaType.DUNGEONS, 9631),
|
DUNGEON_JATIZSO_MINES("Jatizso Mines", DiscordAreaType.DUNGEONS, 9631),
|
||||||
DUNGEON_JIGGIG_BURIAL_TOMB("Jiggig Burial Tomb", DiscordAreaType.DUNGEONS, 9875, 9874),
|
DUNGEON_JIGGIG_BURIAL_TOMB("Jiggig Burial Tomb", DiscordAreaType.DUNGEONS, 9875, 9874),
|
||||||
DUNGEON_JOGRE("Jogre Dungeon", DiscordAreaType.DUNGEONS, 11412),
|
DUNGEON_JOGRE("Jogre Dungeon", DiscordAreaType.DUNGEONS, 11412),
|
||||||
@@ -307,8 +305,8 @@ enum DiscordGameEventType
|
|||||||
MG_VOLCANIC_MINE("Volcanic Mine", DiscordAreaType.MINIGAMES, 15263, 15262),
|
MG_VOLCANIC_MINE("Volcanic Mine", DiscordAreaType.MINIGAMES, 15263, 15262),
|
||||||
|
|
||||||
// Raids
|
// Raids
|
||||||
RAIDS_CHAMBERS_OF_XERIC("Chambers of Xeric", DiscordAreaType.RAIDS, Varbits.IN_RAID),
|
RAIDS_CHAMBERS_OF_XERIC("Chambers of Xeric", DiscordAreaType.RAIDS, 12889, 13136, 13137, 13138, 13139, 13140, 13141, 13145, 13393, 13394, 13395, 13396, 13397, 13401),
|
||||||
RAIDS_THEATRE_OF_BLOOD("Theatre of Blood", DiscordAreaType.RAIDS, Varbits.THEATRE_OF_BLOOD),
|
RAIDS_THEATRE_OF_BLOOD("Theatre of Blood", DiscordAreaType.RAIDS, 12611, 12612, 12613, 12867, 12869, 13122, 13123, 13125, 13379),
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
REGION_ABYSSAL_AREA("Abyssal Area", DiscordAreaType.REGIONS, 12108),
|
REGION_ABYSSAL_AREA("Abyssal Area", DiscordAreaType.REGIONS, 12108),
|
||||||
@@ -367,6 +365,7 @@ enum DiscordGameEventType
|
|||||||
REGION_ICYENE_GRAVEYARD("Icyene Graveyard", DiscordAreaType.REGIONS, 14641, 14897, 14898),
|
REGION_ICYENE_GRAVEYARD("Icyene Graveyard", DiscordAreaType.REGIONS, 14641, 14897, 14898),
|
||||||
REGION_ISAFDAR("Isafdar", DiscordAreaType.REGIONS, 8497, 8753, 8754, 9009, 9010),
|
REGION_ISAFDAR("Isafdar", DiscordAreaType.REGIONS, 8497, 8753, 8754, 9009, 9010),
|
||||||
REGION_ISLAND_OF_STONE("Island of Stone", DiscordAreaType.REGIONS, 9790),
|
REGION_ISLAND_OF_STONE("Island of Stone", DiscordAreaType.REGIONS, 9790),
|
||||||
|
REGION_ISLE_OF_SOULS("Isle of Souls", DiscordAreaType.REGIONS, 8236, 8237, 8238, 8491, 8492, 8494, 8747, 8750, 9003, 9004, 9006, 9260, 9261, 9262),
|
||||||
REGION_JIGGIG("Jiggig" , DiscordAreaType.REGIONS, 9775),
|
REGION_JIGGIG("Jiggig" , DiscordAreaType.REGIONS, 9775),
|
||||||
REGION_KANDARIN("Kandarin", DiscordAreaType.REGIONS, 9014, 9263, 9264, 9519, 9524, 9527, 9776, 9783, 10037, 10290, 10294, 10546, 10551, 10805),
|
REGION_KANDARIN("Kandarin", DiscordAreaType.REGIONS, 9014, 9263, 9264, 9519, 9524, 9527, 9776, 9783, 10037, 10290, 10294, 10546, 10551, 10805),
|
||||||
REGION_KARAMJA("Karamja" , DiscordAreaType.REGIONS, 10801, 10802, 11054, 11311, 11312, 11313, 11566, 11567, 11568, 11569, 11822),
|
REGION_KARAMJA("Karamja" , DiscordAreaType.REGIONS, 10801, 10802, 11054, 11311, 11312, 11313, 11566, 11567, 11568, 11569, 11822),
|
||||||
@@ -430,20 +429,12 @@ enum DiscordGameEventType
|
|||||||
REGION_WRATH_ALTAR("Wrath Altar", DiscordAreaType.REGIONS, 9291);
|
REGION_WRATH_ALTAR("Wrath Altar", DiscordAreaType.REGIONS, 9291);
|
||||||
|
|
||||||
private static final Map<Integer, DiscordGameEventType> FROM_REGION;
|
private static final Map<Integer, DiscordGameEventType> FROM_REGION;
|
||||||
private static final List<DiscordGameEventType> FROM_VARBITS;
|
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
ImmutableMap.Builder<Integer, DiscordGameEventType> regionMapBuilder = new ImmutableMap.Builder<>();
|
ImmutableMap.Builder<Integer, DiscordGameEventType> regionMapBuilder = new ImmutableMap.Builder<>();
|
||||||
ImmutableList.Builder<DiscordGameEventType> fromVarbitsBuilder = ImmutableList.builder();
|
|
||||||
for (DiscordGameEventType discordGameEventType : DiscordGameEventType.values())
|
for (DiscordGameEventType discordGameEventType : DiscordGameEventType.values())
|
||||||
{
|
{
|
||||||
if (discordGameEventType.getVarbits() != null)
|
|
||||||
{
|
|
||||||
fromVarbitsBuilder.add(discordGameEventType);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discordGameEventType.getRegionIds() == null)
|
if (discordGameEventType.getRegionIds() == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -455,7 +446,6 @@ enum DiscordGameEventType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FROM_REGION = regionMapBuilder.build();
|
FROM_REGION = regionMapBuilder.build();
|
||||||
FROM_VARBITS = fromVarbitsBuilder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -497,9 +487,6 @@ enum DiscordGameEventType
|
|||||||
@Nullable
|
@Nullable
|
||||||
private DiscordAreaType discordAreaType;
|
private DiscordAreaType discordAreaType;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Varbits varbits;
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private int[] regionIds;
|
private int[] regionIds;
|
||||||
|
|
||||||
@@ -541,15 +528,6 @@ enum DiscordGameEventType
|
|||||||
this(state, priority, true, false, false, true, false);
|
this(state, priority, true, false, false, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscordGameEventType(String areaName, DiscordAreaType areaType, Varbits varbits)
|
|
||||||
{
|
|
||||||
this.state = exploring(areaType, areaName);
|
|
||||||
this.priority = -2;
|
|
||||||
this.discordAreaType = areaType;
|
|
||||||
this.varbits = varbits;
|
|
||||||
this.shouldClear = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String training(final Skill skill)
|
private static String training(final Skill skill)
|
||||||
{
|
{
|
||||||
return training(skill.getName());
|
return training(skill.getName());
|
||||||
@@ -609,17 +587,4 @@ enum DiscordGameEventType
|
|||||||
{
|
{
|
||||||
return FROM_REGION.get(regionId);
|
return FROM_REGION.get(regionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DiscordGameEventType fromVarbit(final Client client)
|
|
||||||
{
|
|
||||||
for (DiscordGameEventType fromVarbit : FROM_VARBITS)
|
|
||||||
{
|
|
||||||
if (client.getVar(fromVarbit.getVarbits()) != 0)
|
|
||||||
{
|
|
||||||
return fromVarbit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import net.runelite.api.WorldType;
|
|||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import net.runelite.api.events.GameStateChanged;
|
import net.runelite.api.events.GameStateChanged;
|
||||||
import net.runelite.api.events.StatChanged;
|
import net.runelite.api.events.StatChanged;
|
||||||
import net.runelite.api.events.VarbitChanged;
|
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.discord.DiscordService;
|
import net.runelite.client.discord.DiscordService;
|
||||||
import net.runelite.client.discord.events.DiscordJoinGame;
|
import net.runelite.client.discord.events.DiscordJoinGame;
|
||||||
@@ -210,22 +209,6 @@ public class DiscordPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onVarbitChanged(VarbitChanged event)
|
|
||||||
{
|
|
||||||
if (!config.showRaidingActivity())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final DiscordGameEventType discordGameEventType = DiscordGameEventType.fromVarbit(client);
|
|
||||||
|
|
||||||
if (discordGameEventType != null)
|
|
||||||
{
|
|
||||||
discordState.triggerEvent(discordGameEventType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onDiscordReady(DiscordReady event)
|
public void onDiscordReady(DiscordReady event)
|
||||||
{
|
{
|
||||||
@@ -447,6 +430,7 @@ public class DiscordPlugin extends Plugin
|
|||||||
case DUNGEONS: return config.showDungeonActivity();
|
case DUNGEONS: return config.showDungeonActivity();
|
||||||
case MINIGAMES: return config.showMinigameActivity();
|
case MINIGAMES: return config.showMinigameActivity();
|
||||||
case REGIONS: return config.showRegionsActivity();
|
case REGIONS: return config.showRegionsActivity();
|
||||||
|
case RAIDS: return config.showRaidingActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ enum Emoji
|
|||||||
GORILLA(":G"),
|
GORILLA(":G"),
|
||||||
PLEADING("(n_n)"),
|
PLEADING("(n_n)"),
|
||||||
XD("Xd"),
|
XD("Xd"),
|
||||||
|
SPOON("--o"),
|
||||||
|
WEARY_FACE("Dx"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private static final Map<String, Emoji> emojiMap;
|
private static final Map<String, Emoji> emojiMap;
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import net.runelite.api.events.ChatMessage;
|
|||||||
import net.runelite.api.events.GameStateChanged;
|
import net.runelite.api.events.GameStateChanged;
|
||||||
import net.runelite.api.events.OverheadTextChanged;
|
import net.runelite.api.events.OverheadTextChanged;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
import net.runelite.client.chat.ChatMessageManager;
|
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
@@ -63,9 +62,6 @@ public class EmojiPlugin extends Plugin
|
|||||||
@Inject
|
@Inject
|
||||||
private ClientThread clientThread;
|
private ClientThread clientThread;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private ChatMessageManager chatMessageManager;
|
|
||||||
|
|
||||||
private int modIconsStart = -1;
|
private int modIconsStart = -1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -145,9 +141,7 @@ public class EmojiPlugin extends Plugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
messageNode.setRuneLiteFormatMessage(updatedMessage);
|
messageNode.setValue(updatedMessage);
|
||||||
chatMessageManager.update(messageNode);
|
|
||||||
client.refreshChat();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
|
|||||||
@@ -29,16 +29,18 @@ import net.runelite.client.config.Config;
|
|||||||
import net.runelite.client.config.ConfigGroup;
|
import net.runelite.client.config.ConfigGroup;
|
||||||
import net.runelite.client.config.ConfigItem;
|
import net.runelite.client.config.ConfigItem;
|
||||||
|
|
||||||
@ConfigGroup("entityhider")
|
@ConfigGroup(EntityHiderConfig.GROUP)
|
||||||
public interface EntityHiderConfig extends Config
|
public interface EntityHiderConfig extends Config
|
||||||
{
|
{
|
||||||
|
String GROUP = "entityhider";
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 1,
|
position = 1,
|
||||||
keyName = "hidePlayers",
|
keyName = "hidePlayers",
|
||||||
name = "Hide Players",
|
name = "Hide Others",
|
||||||
description = "Configures whether or not players are hidden"
|
description = "Configures whether or not other players are hidden"
|
||||||
)
|
)
|
||||||
default boolean hidePlayers()
|
default boolean hideOthers()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -46,10 +48,10 @@ public interface EntityHiderConfig extends Config
|
|||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 2,
|
position = 2,
|
||||||
keyName = "hidePlayers2D",
|
keyName = "hidePlayers2D",
|
||||||
name = "Hide Players 2D",
|
name = "Hide Others 2D",
|
||||||
description = "Configures whether or not players 2D elements are hidden"
|
description = "Configures whether or not other players 2D elements are hidden"
|
||||||
)
|
)
|
||||||
default boolean hidePlayers2D()
|
default boolean hideOthers2D()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -78,6 +80,17 @@ public interface EntityHiderConfig extends Config
|
|||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 5,
|
position = 5,
|
||||||
|
keyName = "hideIgnores",
|
||||||
|
name = "Hide Ignores",
|
||||||
|
description = "Configures whether or not ignored players are hidden"
|
||||||
|
)
|
||||||
|
default boolean hideIgnores()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
position = 6,
|
||||||
keyName = "hideLocalPlayer",
|
keyName = "hideLocalPlayer",
|
||||||
name = "Hide Local Player",
|
name = "Hide Local Player",
|
||||||
description = "Configures whether or not the local player is hidden"
|
description = "Configures whether or not the local player is hidden"
|
||||||
@@ -88,7 +101,7 @@ public interface EntityHiderConfig extends Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 6,
|
position = 7,
|
||||||
keyName = "hideLocalPlayer2D",
|
keyName = "hideLocalPlayer2D",
|
||||||
name = "Hide Local Player 2D",
|
name = "Hide Local Player 2D",
|
||||||
description = "Configures whether or not the local player's 2D elements are hidden"
|
description = "Configures whether or not the local player's 2D elements are hidden"
|
||||||
@@ -99,7 +112,7 @@ public interface EntityHiderConfig extends Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 7,
|
position = 8,
|
||||||
keyName = "hideNPCs",
|
keyName = "hideNPCs",
|
||||||
name = "Hide NPCs",
|
name = "Hide NPCs",
|
||||||
description = "Configures whether or not NPCs are hidden"
|
description = "Configures whether or not NPCs are hidden"
|
||||||
@@ -110,7 +123,7 @@ public interface EntityHiderConfig extends Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 8,
|
position = 9,
|
||||||
keyName = "hideNPCs2D",
|
keyName = "hideNPCs2D",
|
||||||
name = "Hide NPCs 2D",
|
name = "Hide NPCs 2D",
|
||||||
description = "Configures whether or not NPCs 2D elements are hidden"
|
description = "Configures whether or not NPCs 2D elements are hidden"
|
||||||
@@ -121,7 +134,7 @@ public interface EntityHiderConfig extends Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 9,
|
position = 10,
|
||||||
keyName = "hidePets",
|
keyName = "hidePets",
|
||||||
name = "Hide Pets",
|
name = "Hide Pets",
|
||||||
description = "Configures whether or not other player pets are hidden"
|
description = "Configures whether or not other player pets are hidden"
|
||||||
@@ -132,7 +145,7 @@ public interface EntityHiderConfig extends Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 10,
|
position = 11,
|
||||||
keyName = "hideAttackers",
|
keyName = "hideAttackers",
|
||||||
name = "Hide Attackers",
|
name = "Hide Attackers",
|
||||||
description = "Configures whether or not NPCs/players attacking you are hidden"
|
description = "Configures whether or not NPCs/players attacking you are hidden"
|
||||||
@@ -143,7 +156,7 @@ public interface EntityHiderConfig extends Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 11,
|
position = 12,
|
||||||
keyName = "hideProjectiles",
|
keyName = "hideProjectiles",
|
||||||
name = "Hide Projectiles",
|
name = "Hide Projectiles",
|
||||||
description = "Configures whether or not projectiles are hidden"
|
description = "Configures whether or not projectiles are hidden"
|
||||||
|
|||||||
@@ -28,13 +28,9 @@ package net.runelite.client.plugins.entityhider;
|
|||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.GameState;
|
|
||||||
import net.runelite.api.Player;
|
|
||||||
import net.runelite.api.coords.WorldPoint;
|
|
||||||
import net.runelite.client.events.ConfigChanged;
|
|
||||||
import net.runelite.api.events.GameStateChanged;
|
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
|
import net.runelite.client.events.ConfigChanged;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
|
|
||||||
@@ -67,27 +63,22 @@ public class EntityHiderPlugin extends Plugin
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onConfigChanged(ConfigChanged e)
|
public void onConfigChanged(ConfigChanged e)
|
||||||
{
|
{
|
||||||
updateConfig();
|
if (e.getGroup().equals(EntityHiderConfig.GROUP))
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onGameStateChanged(GameStateChanged event)
|
|
||||||
{
|
|
||||||
if (event.getGameState() == GameState.LOGGED_IN)
|
|
||||||
{
|
{
|
||||||
client.setIsHidingEntities(isPlayerRegionAllowed());
|
updateConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateConfig()
|
private void updateConfig()
|
||||||
{
|
{
|
||||||
client.setIsHidingEntities(isPlayerRegionAllowed());
|
client.setIsHidingEntities(true);
|
||||||
|
|
||||||
client.setPlayersHidden(config.hidePlayers());
|
client.setOthersHidden(config.hideOthers());
|
||||||
client.setPlayersHidden2D(config.hidePlayers2D());
|
client.setOthersHidden2D(config.hideOthers2D());
|
||||||
|
|
||||||
client.setFriendsHidden(config.hideFriends());
|
client.setFriendsHidden(config.hideFriends());
|
||||||
client.setFriendsChatMembersHidden(config.hideFriendsChatMembers());
|
client.setFriendsChatMembersHidden(config.hideFriendsChatMembers());
|
||||||
|
client.setIgnoresHidden(config.hideIgnores());
|
||||||
|
|
||||||
client.setLocalPlayerHidden(config.hideLocalPlayer());
|
client.setLocalPlayerHidden(config.hideLocalPlayer());
|
||||||
client.setLocalPlayerHidden2D(config.hideLocalPlayer2D());
|
client.setLocalPlayerHidden2D(config.hideLocalPlayer2D());
|
||||||
@@ -107,11 +98,12 @@ public class EntityHiderPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
client.setIsHidingEntities(false);
|
client.setIsHidingEntities(false);
|
||||||
|
|
||||||
client.setPlayersHidden(false);
|
client.setOthersHidden(false);
|
||||||
client.setPlayersHidden2D(false);
|
client.setOthersHidden2D(false);
|
||||||
|
|
||||||
client.setFriendsHidden(false);
|
client.setFriendsHidden(false);
|
||||||
client.setFriendsChatMembersHidden(false);
|
client.setFriendsChatMembersHidden(false);
|
||||||
|
client.setIgnoresHidden(false);
|
||||||
|
|
||||||
client.setLocalPlayerHidden(false);
|
client.setLocalPlayerHidden(false);
|
||||||
client.setLocalPlayerHidden2D(false);
|
client.setLocalPlayerHidden2D(false);
|
||||||
@@ -125,19 +117,4 @@ public class EntityHiderPlugin extends Plugin
|
|||||||
|
|
||||||
client.setProjectilesHidden(false);
|
client.setProjectilesHidden(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPlayerRegionAllowed()
|
|
||||||
{
|
|
||||||
final Player localPlayer = client.getLocalPlayer();
|
|
||||||
|
|
||||||
if (localPlayer == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int playerRegionID = WorldPoint.fromLocalInstance(client, localPlayer.getLocalLocation()).getRegionID();
|
|
||||||
|
|
||||||
// 9520 = Castle Wars
|
|
||||||
return playerRegionID != 9520;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,17 @@ public interface FishingConfig extends Config
|
|||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 10,
|
position = 10,
|
||||||
|
keyName = "flyingFishNotification",
|
||||||
|
name = "Flying fish notification",
|
||||||
|
description = "Send a notification when a flying fish spawns on your fishing spot."
|
||||||
|
)
|
||||||
|
default boolean flyingFishNotification()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
position = 11,
|
||||||
keyName = "trawlerNotification",
|
keyName = "trawlerNotification",
|
||||||
name = "Trawler activity notification",
|
name = "Trawler activity notification",
|
||||||
description = "Send a notification when fishing trawler activity drops below 15%."
|
description = "Send a notification when fishing trawler activity drops below 15%."
|
||||||
@@ -160,7 +171,7 @@ public interface FishingConfig extends Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
position = 11,
|
position = 12,
|
||||||
keyName = "trawlerTimer",
|
keyName = "trawlerTimer",
|
||||||
name = "Trawler timer in MM:SS",
|
name = "Trawler timer in MM:SS",
|
||||||
description = "Trawler Timer will display a more accurate timer in MM:SS format."
|
description = "Trawler Timer will display a more accurate timer in MM:SS format."
|
||||||
|
|||||||
@@ -215,6 +215,11 @@ public class FishingPlugin extends Plugin
|
|||||||
spotOverlay.setHidden(false);
|
spotOverlay.setHidden(false);
|
||||||
fishingSpotMinimapOverlay.setHidden(false);
|
fishingSpotMinimapOverlay.setHidden(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.getMessage().equals("A flying fish jumps up and eats some of your minnows!") && config.flyingFishNotification())
|
||||||
|
{
|
||||||
|
notifier.notify("A flying fish is eating your minnows!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -372,7 +377,7 @@ public class FishingPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
if (!trawlerNotificationSent)
|
if (!trawlerNotificationSent)
|
||||||
{
|
{
|
||||||
notifier.notify("[" + client.getLocalPlayer().getName() + "] has low Fishing Trawler activity!");
|
notifier.notify("You have low Fishing Trawler activity!");
|
||||||
trawlerNotificationSent = true;
|
trawlerNotificationSent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -411,11 +411,7 @@ public class FriendsChatPlugin extends Plugin
|
|||||||
.append(textColor, member.getName() + activityMessage);
|
.append(textColor, member.getName() + activityMessage);
|
||||||
|
|
||||||
final String messageString = message.build();
|
final String messageString = message.build();
|
||||||
client.addChatMessage(ChatMessageType.FRIENDSCHATNOTIFICATION, "", messageString, "");
|
final MessageNode line = client.addChatMessage(ChatMessageType.FRIENDSCHATNOTIFICATION, "", messageString, "");
|
||||||
|
|
||||||
final ChatLineBuffer chatLineBuffer = client.getChatLineMap().get(ChatMessageType.FRIENDSCHATNOTIFICATION.getType());
|
|
||||||
final MessageNode[] lines = chatLineBuffer.getLines();
|
|
||||||
final MessageNode line = lines[0];
|
|
||||||
|
|
||||||
MemberJoinMessage joinMessage = new MemberJoinMessage(line, line.getId(), client.getTickCount());
|
MemberJoinMessage joinMessage = new MemberJoinMessage(line, line.getId(), client.getTickCount());
|
||||||
joinMessages.addLast(joinMessage);
|
joinMessages.addLast(joinMessage);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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.gpu;
|
||||||
|
|
||||||
|
import org.jocl.Pointer;
|
||||||
|
import org.jocl.cl_mem;
|
||||||
|
|
||||||
|
class GLBuffer
|
||||||
|
{
|
||||||
|
int glBufferId = -1;
|
||||||
|
int size = -1;
|
||||||
|
cl_mem cl_mem;
|
||||||
|
|
||||||
|
Pointer ptr()
|
||||||
|
{
|
||||||
|
return cl_mem != null ? Pointer.to(cl_mem) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,11 @@ import com.google.inject.Provides;
|
|||||||
import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
|
import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
|
||||||
import com.jogamp.nativewindow.awt.JAWTWindow;
|
import com.jogamp.nativewindow.awt.JAWTWindow;
|
||||||
import com.jogamp.opengl.GL;
|
import com.jogamp.opengl.GL;
|
||||||
|
import static com.jogamp.opengl.GL.GL_ARRAY_BUFFER;
|
||||||
|
import static com.jogamp.opengl.GL.GL_DYNAMIC_DRAW;
|
||||||
|
import static com.jogamp.opengl.GL2ES2.GL_STREAM_DRAW;
|
||||||
|
import static com.jogamp.opengl.GL2ES3.GL_STATIC_COPY;
|
||||||
|
import static com.jogamp.opengl.GL2ES3.GL_UNIFORM_BUFFER;
|
||||||
import com.jogamp.opengl.GL4;
|
import com.jogamp.opengl.GL4;
|
||||||
import com.jogamp.opengl.GLCapabilities;
|
import com.jogamp.opengl.GLCapabilities;
|
||||||
import com.jogamp.opengl.GLContext;
|
import com.jogamp.opengl.GLContext;
|
||||||
@@ -45,6 +50,7 @@ import java.awt.Image;
|
|||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.DataBufferInt;
|
import java.awt.image.DataBufferInt;
|
||||||
|
import java.nio.Buffer;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
@@ -93,6 +99,10 @@ import net.runelite.client.plugins.gpu.config.UIScalingMode;
|
|||||||
import net.runelite.client.plugins.gpu.template.Template;
|
import net.runelite.client.plugins.gpu.template.Template;
|
||||||
import net.runelite.client.ui.DrawManager;
|
import net.runelite.client.ui.DrawManager;
|
||||||
import net.runelite.client.util.OSType;
|
import net.runelite.client.util.OSType;
|
||||||
|
import org.jocl.CL;
|
||||||
|
import static org.jocl.CL.CL_MEM_READ_ONLY;
|
||||||
|
import static org.jocl.CL.CL_MEM_WRITE_ONLY;
|
||||||
|
import static org.jocl.CL.clCreateFromGLBuffer;
|
||||||
|
|
||||||
@PluginDescriptor(
|
@PluginDescriptor(
|
||||||
name = "GPU",
|
name = "GPU",
|
||||||
@@ -105,8 +115,8 @@ import net.runelite.client.util.OSType;
|
|||||||
public class GpuPlugin extends Plugin implements DrawCallbacks
|
public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||||
{
|
{
|
||||||
// This is the maximum number of triangles the compute shaders support
|
// This is the maximum number of triangles the compute shaders support
|
||||||
private static final int MAX_TRIANGLE = 4096;
|
static final int MAX_TRIANGLE = 4096;
|
||||||
private static final int SMALL_TRIANGLE_COUNT = 512;
|
static final int SMALL_TRIANGLE_COUNT = 512;
|
||||||
private static final int FLAG_SCENE_BUFFER = Integer.MIN_VALUE;
|
private static final int FLAG_SCENE_BUFFER = Integer.MIN_VALUE;
|
||||||
private static final int DEFAULT_DISTANCE = 25;
|
private static final int DEFAULT_DISTANCE = 25;
|
||||||
static final int MAX_DISTANCE = 90;
|
static final int MAX_DISTANCE = 90;
|
||||||
@@ -115,6 +125,9 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
@Inject
|
@Inject
|
||||||
private Client client;
|
private Client client;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private OpenCLManager openCLManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ClientThread clientThread;
|
private ClientThread clientThread;
|
||||||
|
|
||||||
@@ -133,7 +146,14 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
@Inject
|
@Inject
|
||||||
private PluginManager pluginManager;
|
private PluginManager pluginManager;
|
||||||
|
|
||||||
private boolean useComputeShaders;
|
enum ComputeMode
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
OPENGL,
|
||||||
|
OPENCL
|
||||||
|
}
|
||||||
|
|
||||||
|
private ComputeMode computeMode = ComputeMode.NONE;
|
||||||
|
|
||||||
private Canvas canvas;
|
private Canvas canvas;
|
||||||
private JAWTWindow jawtWindow;
|
private JAWTWindow jawtWindow;
|
||||||
@@ -182,23 +202,22 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
private int texSceneHandle;
|
private int texSceneHandle;
|
||||||
private int rboSceneHandle;
|
private int rboSceneHandle;
|
||||||
|
|
||||||
// scene vertex buffer id
|
// scene vertex buffer
|
||||||
private int bufferId;
|
private final GLBuffer sceneVertexBuffer = new GLBuffer();
|
||||||
// scene uv buffer id
|
// scene uv buffer
|
||||||
private int uvBufferId;
|
private final GLBuffer sceneUvBuffer = new GLBuffer();
|
||||||
|
|
||||||
private int tmpBufferId; // temporary scene vertex buffer
|
private final GLBuffer tmpVertexBuffer = new GLBuffer(); // temporary scene vertex buffer
|
||||||
private int tmpUvBufferId; // temporary scene uv buffer
|
private final GLBuffer tmpUvBuffer = new GLBuffer(); // temporary scene uv buffer
|
||||||
private int tmpModelBufferId; // scene model buffer, large
|
private final GLBuffer tmpModelBufferLarge = new GLBuffer(); // scene model buffer, large
|
||||||
private int tmpModelBufferSmallId; // scene model buffer, small
|
private final GLBuffer tmpModelBufferSmall = new GLBuffer(); // scene model buffer, small
|
||||||
private int tmpModelBufferUnorderedId;
|
private final GLBuffer tmpModelBufferUnordered = new GLBuffer(); // scene model buffer, unordered
|
||||||
private int tmpOutBufferId; // target vertex buffer for compute shaders
|
private final GLBuffer tmpOutBuffer = new GLBuffer(); // target vertex buffer for compute shaders
|
||||||
private int tmpOutUvBufferId; // target uv buffer for compute shaders
|
private final GLBuffer tmpOutUvBuffer = new GLBuffer(); // target uv buffer for compute shaders
|
||||||
|
|
||||||
private int textureArrayId;
|
private int textureArrayId;
|
||||||
|
|
||||||
private int uniformBufferId;
|
private final GLBuffer uniformBuffer = new GLBuffer();
|
||||||
private final IntBuffer uniformBuffer = GpuIntBuffer.allocateDirect(5 + 3 + 2048 * 4);
|
|
||||||
private final float[] textureOffsets = new float[128];
|
private final float[] textureOffsets = new float[128];
|
||||||
|
|
||||||
private GpuIntBuffer vertexBuffer;
|
private GpuIntBuffer vertexBuffer;
|
||||||
@@ -278,7 +297,6 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bufferId = uvBufferId = uniformBufferId = tmpBufferId = tmpUvBufferId = tmpModelBufferId = tmpModelBufferSmallId = tmpModelBufferUnorderedId = tmpOutBufferId = tmpOutUvBufferId = -1;
|
|
||||||
texSceneHandle = fboSceneHandle = rboSceneHandle = -1; // AA FBO
|
texSceneHandle = fboSceneHandle = rboSceneHandle = -1; // AA FBO
|
||||||
unorderedModels = smallModels = largeModels = 0;
|
unorderedModels = smallModels = largeModels = 0;
|
||||||
drawingModel = false;
|
drawingModel = false;
|
||||||
@@ -290,8 +308,9 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OSX supports up to OpenGL 4.1, however 4.3 is required for compute shaders
|
computeMode = config.useComputeShaders()
|
||||||
useComputeShaders = config.useComputeShaders() && OSType.getOSType() != OSType.MacOS;
|
? (OSType.getOSType() == OSType.MacOS ? ComputeMode.OPENCL : ComputeMode.OPENGL)
|
||||||
|
: ComputeMode.NONE;
|
||||||
|
|
||||||
canvas.setIgnoreRepaint(true);
|
canvas.setIgnoreRepaint(true);
|
||||||
|
|
||||||
@@ -397,7 +416,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
|
|
||||||
if (client.getGameState() == GameState.LOGGED_IN)
|
if (client.getGameState() == GameState.LOGGED_IN)
|
||||||
{
|
{
|
||||||
uploadScene();
|
invokeOnMainThread(this::uploadScene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
catch (Throwable e)
|
||||||
@@ -433,6 +452,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
|
|
||||||
invokeOnMainThread(() ->
|
invokeOnMainThread(() ->
|
||||||
{
|
{
|
||||||
|
openCLManager.cleanup();
|
||||||
|
|
||||||
if (gl != null)
|
if (gl != null)
|
||||||
{
|
{
|
||||||
if (textureArrayId != -1)
|
if (textureArrayId != -1)
|
||||||
@@ -441,11 +462,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
textureArrayId = -1;
|
textureArrayId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uniformBufferId != -1)
|
destroyGlBuffer(uniformBuffer);
|
||||||
{
|
|
||||||
glDeleteBuffer(gl, uniformBufferId);
|
|
||||||
uniformBufferId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
shutdownBuffers();
|
shutdownBuffers();
|
||||||
shutdownInterfaceTexture();
|
shutdownInterfaceTexture();
|
||||||
@@ -519,12 +536,16 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
glProgram = PROGRAM.compile(gl, template);
|
glProgram = PROGRAM.compile(gl, template);
|
||||||
glUiProgram = UI_PROGRAM.compile(gl, template);
|
glUiProgram = UI_PROGRAM.compile(gl, template);
|
||||||
|
|
||||||
if (useComputeShaders)
|
if (computeMode == ComputeMode.OPENGL)
|
||||||
{
|
{
|
||||||
glComputeProgram = COMPUTE_PROGRAM.compile(gl, template);
|
glComputeProgram = COMPUTE_PROGRAM.compile(gl, template);
|
||||||
glSmallComputeProgram = SMALL_COMPUTE_PROGRAM.compile(gl, template);
|
glSmallComputeProgram = SMALL_COMPUTE_PROGRAM.compile(gl, template);
|
||||||
glUnorderedComputeProgram = UNORDERED_COMPUTE_PROGRAM.compile(gl, template);
|
glUnorderedComputeProgram = UNORDERED_COMPUTE_PROGRAM.compile(gl, template);
|
||||||
}
|
}
|
||||||
|
else if (computeMode == ComputeMode.OPENCL)
|
||||||
|
{
|
||||||
|
openCLManager.init(gl);
|
||||||
|
}
|
||||||
|
|
||||||
initUniforms();
|
initUniforms();
|
||||||
}
|
}
|
||||||
@@ -593,8 +614,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
-1f, 1f, 0.0f, 0.0f, 0f // top left
|
-1f, 1f, 0.0f, 0.0f, 0f // top left
|
||||||
});
|
});
|
||||||
vboUiBuf.rewind();
|
vboUiBuf.rewind();
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vboUiHandle);
|
gl.glBindBuffer(GL_ARRAY_BUFFER, vboUiHandle);
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, vboUiBuf.capacity() * Float.BYTES, vboUiBuf, gl.GL_STATIC_DRAW);
|
gl.glBufferData(GL_ARRAY_BUFFER, vboUiBuf.capacity() * Float.BYTES, vboUiBuf, gl.GL_STATIC_DRAW);
|
||||||
|
|
||||||
// position attribute
|
// position attribute
|
||||||
gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, false, 5 * Float.BYTES, 0);
|
gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, false, 5 * Float.BYTES, 0);
|
||||||
@@ -605,7 +626,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
gl.glEnableVertexAttribArray(1);
|
gl.glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
// unbind VBO
|
// unbind VBO
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0);
|
gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shutdownVao()
|
private void shutdownVao()
|
||||||
@@ -622,71 +643,49 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
|
|
||||||
private void initBuffers()
|
private void initBuffers()
|
||||||
{
|
{
|
||||||
bufferId = glGenBuffers(gl);
|
initGlBuffer(sceneVertexBuffer);
|
||||||
uvBufferId = glGenBuffers(gl);
|
initGlBuffer(sceneUvBuffer);
|
||||||
tmpBufferId = glGenBuffers(gl);
|
initGlBuffer(tmpVertexBuffer);
|
||||||
tmpUvBufferId = glGenBuffers(gl);
|
initGlBuffer(tmpUvBuffer);
|
||||||
tmpModelBufferId = glGenBuffers(gl);
|
initGlBuffer(tmpModelBufferLarge);
|
||||||
tmpModelBufferSmallId = glGenBuffers(gl);
|
initGlBuffer(tmpModelBufferSmall);
|
||||||
tmpModelBufferUnorderedId = glGenBuffers(gl);
|
initGlBuffer(tmpModelBufferUnordered);
|
||||||
tmpOutBufferId = glGenBuffers(gl);
|
initGlBuffer(tmpOutBuffer);
|
||||||
tmpOutUvBufferId = glGenBuffers(gl);
|
initGlBuffer(tmpOutUvBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initGlBuffer(GLBuffer glBuffer)
|
||||||
|
{
|
||||||
|
glBuffer.glBufferId = glGenBuffers(gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shutdownBuffers()
|
private void shutdownBuffers()
|
||||||
{
|
{
|
||||||
if (bufferId != -1)
|
destroyGlBuffer(sceneVertexBuffer);
|
||||||
{
|
destroyGlBuffer(sceneUvBuffer);
|
||||||
glDeleteBuffer(gl, bufferId);
|
|
||||||
bufferId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uvBufferId != -1)
|
destroyGlBuffer(tmpVertexBuffer);
|
||||||
{
|
destroyGlBuffer(tmpUvBuffer);
|
||||||
glDeleteBuffer(gl, uvBufferId);
|
destroyGlBuffer(tmpModelBufferLarge);
|
||||||
uvBufferId = -1;
|
destroyGlBuffer(tmpModelBufferSmall);
|
||||||
}
|
destroyGlBuffer(tmpModelBufferUnordered);
|
||||||
|
destroyGlBuffer(tmpOutBuffer);
|
||||||
|
destroyGlBuffer(tmpOutUvBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
if (tmpBufferId != -1)
|
private void destroyGlBuffer(GLBuffer glBuffer)
|
||||||
|
{
|
||||||
|
if (glBuffer.glBufferId != -1)
|
||||||
{
|
{
|
||||||
glDeleteBuffer(gl, tmpBufferId);
|
glDeleteBuffer(gl, glBuffer.glBufferId);
|
||||||
tmpBufferId = -1;
|
glBuffer.glBufferId = -1;
|
||||||
}
|
}
|
||||||
|
glBuffer.size = -1;
|
||||||
|
|
||||||
if (tmpUvBufferId != -1)
|
if (glBuffer.cl_mem != null)
|
||||||
{
|
{
|
||||||
glDeleteBuffer(gl, tmpUvBufferId);
|
CL.clReleaseMemObject(glBuffer.cl_mem);
|
||||||
tmpUvBufferId = -1;
|
glBuffer.cl_mem = null;
|
||||||
}
|
|
||||||
|
|
||||||
if (tmpModelBufferId != -1)
|
|
||||||
{
|
|
||||||
glDeleteBuffer(gl, tmpModelBufferId);
|
|
||||||
tmpModelBufferId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmpModelBufferSmallId != -1)
|
|
||||||
{
|
|
||||||
glDeleteBuffer(gl, tmpModelBufferSmallId);
|
|
||||||
tmpModelBufferSmallId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmpModelBufferUnorderedId != -1)
|
|
||||||
{
|
|
||||||
glDeleteBuffer(gl, tmpModelBufferUnorderedId);
|
|
||||||
tmpModelBufferUnorderedId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmpOutBufferId != -1)
|
|
||||||
{
|
|
||||||
glDeleteBuffer(gl, tmpOutBufferId);
|
|
||||||
tmpOutBufferId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmpOutUvBufferId != -1)
|
|
||||||
{
|
|
||||||
glDeleteBuffer(gl, tmpOutUvBufferId);
|
|
||||||
tmpOutUvBufferId = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,21 +708,21 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
|
|
||||||
private void initUniformBuffer()
|
private void initUniformBuffer()
|
||||||
{
|
{
|
||||||
uniformBufferId = glGenBuffers(gl);
|
initGlBuffer(uniformBuffer);
|
||||||
gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, uniformBufferId);
|
|
||||||
uniformBuffer.clear();
|
IntBuffer uniformBuf = GpuIntBuffer.allocateDirect(8 + 2048 * 4);
|
||||||
uniformBuffer.put(new int[8]);
|
uniformBuf.put(new int[8]); // uniform block
|
||||||
final int[] pad = new int[2];
|
final int[] pad = new int[2];
|
||||||
for (int i = 0; i < 2048; i++)
|
for (int i = 0; i < 2048; i++)
|
||||||
{
|
{
|
||||||
uniformBuffer.put(Perspective.SINE[i]);
|
uniformBuf.put(Perspective.SINE[i]);
|
||||||
uniformBuffer.put(Perspective.COSINE[i]);
|
uniformBuf.put(Perspective.COSINE[i]);
|
||||||
uniformBuffer.put(pad);
|
uniformBuf.put(pad); // ivec2 alignment in std140 is 16 bytes
|
||||||
}
|
}
|
||||||
uniformBuffer.flip();
|
uniformBuf.flip();
|
||||||
|
|
||||||
gl.glBufferData(gl.GL_UNIFORM_BUFFER, uniformBuffer.limit() * Integer.BYTES, uniformBuffer, gl.GL_DYNAMIC_DRAW);
|
updateBuffer(uniformBuffer, GL_UNIFORM_BUFFER, uniformBuf.limit() * Integer.BYTES, uniformBuf, GL_DYNAMIC_DRAW, CL_MEM_READ_ONLY);
|
||||||
gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, 0);
|
gl.glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initAAFbo(int width, int height, int aaSamples)
|
private void initAAFbo(int width, int height, int aaSamples)
|
||||||
@@ -785,9 +784,11 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
invokeOnMainThread(() ->
|
invokeOnMainThread(() ->
|
||||||
{
|
{
|
||||||
// UBO. Only the first 32 bytes get modified here, the rest is the constant sin/cos table.
|
// UBO. Only the first 32 bytes get modified here, the rest is the constant sin/cos table.
|
||||||
gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, uniformBufferId);
|
// We can reuse the vertex buffer since it isn't used yet.
|
||||||
uniformBuffer.clear();
|
vertexBuffer.clear();
|
||||||
uniformBuffer
|
vertexBuffer.ensureCapacity(32);
|
||||||
|
IntBuffer uniformBuf = vertexBuffer.getBuffer();
|
||||||
|
uniformBuf
|
||||||
.put(yaw)
|
.put(yaw)
|
||||||
.put(pitch)
|
.put(pitch)
|
||||||
.put(client.getCenterX())
|
.put(client.getCenterX())
|
||||||
@@ -796,12 +797,14 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
.put(cameraX)
|
.put(cameraX)
|
||||||
.put(cameraY)
|
.put(cameraY)
|
||||||
.put(cameraZ);
|
.put(cameraZ);
|
||||||
uniformBuffer.flip();
|
uniformBuf.flip();
|
||||||
|
|
||||||
gl.glBufferSubData(gl.GL_UNIFORM_BUFFER, 0, uniformBuffer.limit() * Integer.BYTES, uniformBuffer);
|
gl.glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer.glBufferId);
|
||||||
gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, 0);
|
gl.glBufferSubData(GL_UNIFORM_BUFFER, 0, uniformBuf.limit() * Integer.BYTES, uniformBuf);
|
||||||
|
gl.glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
|
||||||
gl.glBindBufferBase(gl.GL_UNIFORM_BUFFER, 0, uniformBufferId);
|
gl.glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniformBuffer.glBufferId);
|
||||||
|
uniformBuf.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,7 +816,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
|
|
||||||
private void postDraw()
|
private void postDraw()
|
||||||
{
|
{
|
||||||
if (!useComputeShaders)
|
if (computeMode == ComputeMode.NONE)
|
||||||
{
|
{
|
||||||
// Upload buffers
|
// Upload buffers
|
||||||
vertexBuffer.flip();
|
vertexBuffer.flip();
|
||||||
@@ -822,12 +825,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
IntBuffer vertexBuffer = this.vertexBuffer.getBuffer();
|
IntBuffer vertexBuffer = this.vertexBuffer.getBuffer();
|
||||||
FloatBuffer uvBuffer = this.uvBuffer.getBuffer();
|
FloatBuffer uvBuffer = this.uvBuffer.getBuffer();
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpBufferId);
|
updateBuffer(tmpVertexBuffer, GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, GL_DYNAMIC_DRAW, 0L);
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, gl.GL_DYNAMIC_DRAW);
|
updateBuffer(tmpUvBuffer, GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, GL_DYNAMIC_DRAW, 0L);
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpUvBufferId);
|
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, gl.GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,79 +843,91 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
IntBuffer modelBufferSmall = this.modelBufferSmall.getBuffer();
|
IntBuffer modelBufferSmall = this.modelBufferSmall.getBuffer();
|
||||||
IntBuffer modelBufferUnordered = this.modelBufferUnordered.getBuffer();
|
IntBuffer modelBufferUnordered = this.modelBufferUnordered.getBuffer();
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpBufferId);
|
// temp buffers
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, gl.GL_DYNAMIC_DRAW);
|
updateBuffer(tmpVertexBuffer, GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, GL_DYNAMIC_DRAW, CL_MEM_READ_ONLY);
|
||||||
|
updateBuffer(tmpUvBuffer, GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, GL_DYNAMIC_DRAW, CL_MEM_READ_ONLY);
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpUvBufferId);
|
// model buffers
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, gl.GL_DYNAMIC_DRAW);
|
updateBuffer(tmpModelBufferLarge, GL_ARRAY_BUFFER, modelBuffer.limit() * Integer.BYTES, modelBuffer, GL_DYNAMIC_DRAW, CL_MEM_READ_ONLY);
|
||||||
|
updateBuffer(tmpModelBufferSmall, GL_ARRAY_BUFFER, modelBufferSmall.limit() * Integer.BYTES, modelBufferSmall, GL_DYNAMIC_DRAW, CL_MEM_READ_ONLY);
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpModelBufferId);
|
updateBuffer(tmpModelBufferUnordered, GL_ARRAY_BUFFER, modelBufferUnordered.limit() * Integer.BYTES, modelBufferUnordered, GL_DYNAMIC_DRAW, CL_MEM_READ_ONLY);
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, modelBuffer.limit() * Integer.BYTES, modelBuffer, gl.GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpModelBufferSmallId);
|
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, modelBufferSmall.limit() * Integer.BYTES, modelBufferSmall, gl.GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpModelBufferUnorderedId);
|
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, modelBufferUnordered.limit() * Integer.BYTES, modelBufferUnordered, gl.GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
// Output buffers
|
// Output buffers
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpOutBufferId);
|
updateBuffer(tmpOutBuffer,
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER,
|
GL_ARRAY_BUFFER,
|
||||||
targetBufferOffset * 16, // each vertex is an ivec4, which is 16 bytes
|
targetBufferOffset * 16, // each vertex is an ivec4, which is 16 bytes
|
||||||
null,
|
null,
|
||||||
gl.GL_STREAM_DRAW);
|
GL_STREAM_DRAW,
|
||||||
|
CL_MEM_WRITE_ONLY);
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpOutUvBufferId);
|
updateBuffer(tmpOutUvBuffer,
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER,
|
GL_ARRAY_BUFFER,
|
||||||
targetBufferOffset * 16,
|
targetBufferOffset * 16, // each vertex is an ivec4, which is 16 bytes
|
||||||
null,
|
null,
|
||||||
gl.GL_STREAM_DRAW);
|
GL_STREAM_DRAW,
|
||||||
|
CL_MEM_WRITE_ONLY);
|
||||||
|
|
||||||
// Bind UBO to compute programs
|
if (computeMode == ComputeMode.OPENCL)
|
||||||
gl.glUniformBlockBinding(glSmallComputeProgram, uniBlockSmall, 0);
|
{
|
||||||
gl.glUniformBlockBinding(glComputeProgram, uniBlockLarge, 0);
|
// The docs for clEnqueueAcquireGLObjects say all pending GL operations must be completed before calling
|
||||||
|
// clEnqueueAcquireGLObjects, and recommends calling glFinish() as the only portable way to do that.
|
||||||
|
// However no issues have been observed from not calling it, and so will leave disabled for now.
|
||||||
|
// gl.glFinish();
|
||||||
|
|
||||||
|
openCLManager.compute(
|
||||||
|
unorderedModels, smallModels, largeModels,
|
||||||
|
sceneVertexBuffer, sceneUvBuffer,
|
||||||
|
tmpVertexBuffer, tmpUvBuffer,
|
||||||
|
tmpModelBufferUnordered, tmpModelBufferSmall, tmpModelBufferLarge,
|
||||||
|
tmpOutBuffer, tmpOutUvBuffer,
|
||||||
|
uniformBuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute is split into three separate programs: 'unordered', 'small', and 'large'
|
* Compute is split into three separate programs: 'unordered', 'small', and 'large'
|
||||||
* to save on GPU resources. Small will sort <= 512 faces, large will do <= 4096.
|
* to save on GPU resources. Small will sort <= 512 faces, large will do <= 4096.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Bind UBO to compute programs
|
||||||
|
gl.glUniformBlockBinding(glSmallComputeProgram, uniBlockSmall, 0);
|
||||||
|
gl.glUniformBlockBinding(glComputeProgram, uniBlockLarge, 0);
|
||||||
|
|
||||||
// unordered
|
// unordered
|
||||||
gl.glUseProgram(glUnorderedComputeProgram);
|
gl.glUseProgram(glUnorderedComputeProgram);
|
||||||
|
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferUnorderedId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferUnordered.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, sceneVertexBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpVertexBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, sceneUvBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBuffer.glBufferId);
|
||||||
|
|
||||||
gl.glDispatchCompute(unorderedModels, 1, 1);
|
gl.glDispatchCompute(unorderedModels, 1, 1);
|
||||||
|
|
||||||
// small
|
// small
|
||||||
gl.glUseProgram(glSmallComputeProgram);
|
gl.glUseProgram(glSmallComputeProgram);
|
||||||
|
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferSmallId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferSmall.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, sceneVertexBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpVertexBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, sceneUvBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBuffer.glBufferId);
|
||||||
|
|
||||||
gl.glDispatchCompute(smallModels, 1, 1);
|
gl.glDispatchCompute(smallModels, 1, 1);
|
||||||
|
|
||||||
// large
|
// large
|
||||||
gl.glUseProgram(glComputeProgram);
|
gl.glUseProgram(glComputeProgram);
|
||||||
|
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferLarge.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, sceneVertexBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpVertexBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, sceneUvBuffer.glBufferId);
|
||||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId);
|
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBuffer.glBufferId);
|
||||||
|
|
||||||
gl.glDispatchCompute(largeModels, 1, 1);
|
gl.glDispatchCompute(largeModels, 1, 1);
|
||||||
}
|
}
|
||||||
@@ -926,7 +937,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
SceneTilePaint paint, int tileZ, int tileX, int tileY,
|
SceneTilePaint paint, int tileZ, int tileX, int tileY,
|
||||||
int zoom, int centerX, int centerY)
|
int zoom, int centerX, int centerY)
|
||||||
{
|
{
|
||||||
if (!useComputeShaders)
|
if (computeMode == ComputeMode.NONE)
|
||||||
{
|
{
|
||||||
targetBufferOffset += sceneUploader.upload(paint,
|
targetBufferOffset += sceneUploader.upload(paint,
|
||||||
tileZ, tileX, tileY,
|
tileZ, tileX, tileY,
|
||||||
@@ -963,7 +974,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
SceneTileModel model, int tileZ, int tileX, int tileY,
|
SceneTileModel model, int tileZ, int tileX, int tileY,
|
||||||
int zoom, int centerX, int centerY)
|
int zoom, int centerX, int centerY)
|
||||||
{
|
{
|
||||||
if (!useComputeShaders)
|
if (computeMode == ComputeMode.NONE)
|
||||||
{
|
{
|
||||||
targetBufferOffset += sceneUploader.upload(model,
|
targetBufferOffset += sceneUploader.upload(model,
|
||||||
tileX, tileY,
|
tileX, tileY,
|
||||||
@@ -1131,7 +1142,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
|
|
||||||
// Ceil the sizes because even if the size is 599.1 we want to treat it as size 600 (i.e. render to the x=599 pixel).
|
// Ceil the sizes because even if the size is 599.1 we want to treat it as size 600 (i.e. render to the x=599 pixel).
|
||||||
renderViewportHeight = (int) Math.ceil(scaleFactorY * (renderViewportHeight)) + padding * 2;
|
renderViewportHeight = (int) Math.ceil(scaleFactorY * (renderViewportHeight)) + padding * 2;
|
||||||
renderViewportWidth = (int) Math.ceil(scaleFactorX * (renderViewportWidth )) + padding * 2;
|
renderViewportWidth = (int) Math.ceil(scaleFactorX * (renderViewportWidth )) + padding * 2;
|
||||||
|
|
||||||
// Floor the offsets because even if the offset is 4.9, we want to render to the x=4 pixel anyway.
|
// Floor the offsets because even if the offset is 4.9, we want to render to the x=4 pixel anyway.
|
||||||
renderHeightOff = (int) Math.floor(scaleFactorY * (renderHeightOff)) - padding;
|
renderHeightOff = (int) Math.floor(scaleFactorY * (renderHeightOff)) - padding;
|
||||||
@@ -1195,27 +1206,36 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
gl.glBindVertexArray(vaoHandle);
|
gl.glBindVertexArray(vaoHandle);
|
||||||
|
|
||||||
int vertexBuffer, uvBuffer;
|
int vertexBuffer, uvBuffer;
|
||||||
if (useComputeShaders)
|
if (computeMode != ComputeMode.NONE)
|
||||||
{
|
{
|
||||||
// Before reading the SSBOs written to from postDrawScene() we must insert a barrier
|
if (computeMode == ComputeMode.OPENGL)
|
||||||
gl.glMemoryBarrier(gl.GL_SHADER_STORAGE_BARRIER_BIT);
|
{
|
||||||
|
// Before reading the SSBOs written to from postDrawScene() we must insert a barrier
|
||||||
|
gl.glMemoryBarrier(gl.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Wait for the command queue to finish, so that we know the compute is done
|
||||||
|
openCLManager.finish();
|
||||||
|
}
|
||||||
|
|
||||||
// Draw using the output buffer of the compute
|
// Draw using the output buffer of the compute
|
||||||
vertexBuffer = tmpOutBufferId;
|
vertexBuffer = tmpOutBuffer.glBufferId;
|
||||||
uvBuffer = tmpOutUvBufferId;
|
uvBuffer = tmpOutUvBuffer.glBufferId;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only use the temporary buffers, which will contain the full scene
|
// Only use the temporary buffers, which will contain the full scene
|
||||||
vertexBuffer = tmpBufferId;
|
vertexBuffer = tmpVertexBuffer.glBufferId;
|
||||||
uvBuffer = tmpUvBufferId;
|
uvBuffer = tmpUvBuffer.glBufferId;
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.glEnableVertexAttribArray(0);
|
gl.glEnableVertexAttribArray(0);
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vertexBuffer);
|
gl.glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
|
||||||
gl.glVertexAttribIPointer(0, 4, gl.GL_INT, 0, 0);
|
gl.glVertexAttribIPointer(0, 4, gl.GL_INT, 0, 0);
|
||||||
|
|
||||||
gl.glEnableVertexAttribArray(1);
|
gl.glEnableVertexAttribArray(1);
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, uvBuffer);
|
gl.glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
|
||||||
gl.glVertexAttribPointer(1, 4, gl.GL_FLOAT, false, 0, 0);
|
gl.glVertexAttribPointer(1, 4, gl.GL_FLOAT, false, 0, 0);
|
||||||
|
|
||||||
gl.glDrawArrays(gl.GL_TRIANGLES, 0, targetBufferOffset);
|
gl.glDrawArrays(gl.GL_TRIANGLES, 0, targetBufferOffset);
|
||||||
@@ -1400,12 +1420,12 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||||
{
|
{
|
||||||
if (!useComputeShaders || gameStateChanged.getGameState() != GameState.LOGGED_IN)
|
if (computeMode == ComputeMode.NONE || gameStateChanged.getGameState() != GameState.LOGGED_IN)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadScene();
|
invokeOnMainThread(this::uploadScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadScene()
|
private void uploadScene()
|
||||||
@@ -1421,13 +1441,10 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
IntBuffer vertexBuffer = this.vertexBuffer.getBuffer();
|
IntBuffer vertexBuffer = this.vertexBuffer.getBuffer();
|
||||||
FloatBuffer uvBuffer = this.uvBuffer.getBuffer();
|
FloatBuffer uvBuffer = this.uvBuffer.getBuffer();
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, bufferId);
|
updateBuffer(sceneVertexBuffer, GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, GL_STATIC_COPY, CL_MEM_READ_ONLY);
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, gl.GL_STATIC_COPY);
|
updateBuffer(sceneUvBuffer, GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, GL_STATIC_COPY, CL_MEM_READ_ONLY);
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, uvBufferId);
|
gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, gl.GL_STATIC_COPY);
|
|
||||||
|
|
||||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
vertexBuffer.clear();
|
vertexBuffer.clear();
|
||||||
uvBuffer.clear();
|
uvBuffer.clear();
|
||||||
@@ -1492,7 +1509,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
@Override
|
@Override
|
||||||
public void draw(Renderable renderable, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash)
|
public void draw(Renderable renderable, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash)
|
||||||
{
|
{
|
||||||
if (!useComputeShaders)
|
if (computeMode == ComputeMode.NONE)
|
||||||
{
|
{
|
||||||
Model model = renderable instanceof Model ? (Model) renderable : renderable.getModel();
|
Model model = renderable instanceof Model ? (Model) renderable : renderable.getModel();
|
||||||
if (model != null)
|
if (model != null)
|
||||||
@@ -1673,7 +1690,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
|
|
||||||
private int getDrawDistance()
|
private int getDrawDistance()
|
||||||
{
|
{
|
||||||
final int limit = useComputeShaders ? MAX_DISTANCE : DEFAULT_DISTANCE;
|
final int limit = computeMode != ComputeMode.NONE ? MAX_DISTANCE : DEFAULT_DISTANCE;
|
||||||
return Ints.constrainToRange(config.drawDistance(), 0, limit);
|
return Ints.constrainToRange(config.drawDistance(), 0, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1688,4 +1705,36 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
runnable.run();
|
runnable.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateBuffer(GLBuffer glBuffer, int target, int size, Buffer data, int usage, long clFlags)
|
||||||
|
{
|
||||||
|
gl.glBindBuffer(target, glBuffer.glBufferId);
|
||||||
|
if (size > glBuffer.size)
|
||||||
|
{
|
||||||
|
log.trace("Buffer resize: {} {} -> {}", glBuffer, glBuffer.size, size);
|
||||||
|
|
||||||
|
glBuffer.size = size;
|
||||||
|
gl.glBufferData(target, size, data, usage);
|
||||||
|
|
||||||
|
if (computeMode == ComputeMode.OPENCL)
|
||||||
|
{
|
||||||
|
if (glBuffer.cl_mem != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseMemObject(glBuffer.cl_mem);
|
||||||
|
}
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
glBuffer.cl_mem = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glBuffer.cl_mem = clCreateFromGLBuffer(openCLManager.context, clFlags, glBuffer.glBufferId, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (data != null)
|
||||||
|
{
|
||||||
|
gl.glBufferSubData(target, 0, size, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,521 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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.gpu;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import com.jogamp.nativewindow.NativeSurface;
|
||||||
|
import com.jogamp.opengl.GL4;
|
||||||
|
import com.jogamp.opengl.GLContext;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import jogamp.opengl.GLContextImpl;
|
||||||
|
import jogamp.opengl.GLDrawableImpl;
|
||||||
|
import jogamp.opengl.egl.EGLContext;
|
||||||
|
import jogamp.opengl.macosx.cgl.CGL;
|
||||||
|
import jogamp.opengl.windows.wgl.WindowsWGLContext;
|
||||||
|
import jogamp.opengl.x11.glx.X11GLXContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.runelite.client.plugins.gpu.template.Template;
|
||||||
|
import net.runelite.client.util.OSType;
|
||||||
|
import org.jocl.CL;
|
||||||
|
import static org.jocl.CL.*;
|
||||||
|
import org.jocl.CLException;
|
||||||
|
import org.jocl.Pointer;
|
||||||
|
import org.jocl.Sizeof;
|
||||||
|
import org.jocl.cl_command_queue;
|
||||||
|
import org.jocl.cl_context;
|
||||||
|
import org.jocl.cl_context_properties;
|
||||||
|
import org.jocl.cl_device_id;
|
||||||
|
import org.jocl.cl_event;
|
||||||
|
import org.jocl.cl_kernel;
|
||||||
|
import org.jocl.cl_mem;
|
||||||
|
import org.jocl.cl_platform_id;
|
||||||
|
import org.jocl.cl_program;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Slf4j
|
||||||
|
class OpenCLManager
|
||||||
|
{
|
||||||
|
private static final String GL_SHARING_PLATFORM_EXT = "cl_khr_gl_sharing";
|
||||||
|
|
||||||
|
private static final String KERNEL_NAME_UNORDERED = "computeUnordered";
|
||||||
|
private static final String KERNEL_NAME_LARGE = "computeLarge";
|
||||||
|
|
||||||
|
private static final int MIN_WORK_GROUP_SIZE = 256;
|
||||||
|
private static final int SMALL_SIZE = GpuPlugin.SMALL_TRIANGLE_COUNT;
|
||||||
|
private static final int LARGE_SIZE = GpuPlugin.MAX_TRIANGLE;
|
||||||
|
// struct shared_data {
|
||||||
|
// int totalNum[12];
|
||||||
|
// int totalDistance[12];
|
||||||
|
// int totalMappedNum[18];
|
||||||
|
// int min10;
|
||||||
|
// int dfs[0];
|
||||||
|
// };
|
||||||
|
private static final int SHARED_SIZE = 12 + 12 + 18 + 1; // in ints
|
||||||
|
|
||||||
|
// The number of faces each worker processes in the two kernels
|
||||||
|
private int largeFaceCount;
|
||||||
|
private int smallFaceCount;
|
||||||
|
|
||||||
|
private cl_platform_id platform;
|
||||||
|
private cl_device_id device;
|
||||||
|
cl_context context;
|
||||||
|
private cl_command_queue commandQueue;
|
||||||
|
|
||||||
|
private cl_program programUnordered;
|
||||||
|
private cl_program programSmall;
|
||||||
|
private cl_program programLarge;
|
||||||
|
|
||||||
|
private cl_kernel kernelUnordered;
|
||||||
|
private cl_kernel kernelSmall;
|
||||||
|
private cl_kernel kernelLarge;
|
||||||
|
|
||||||
|
void init(GL4 gl)
|
||||||
|
{
|
||||||
|
CL.setExceptionsEnabled(true);
|
||||||
|
|
||||||
|
switch (OSType.getOSType())
|
||||||
|
{
|
||||||
|
case Windows:
|
||||||
|
case Linux:
|
||||||
|
initPlatform();
|
||||||
|
initDevice();
|
||||||
|
initContext(gl);
|
||||||
|
break;
|
||||||
|
case MacOS:
|
||||||
|
initMacOS(gl);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unsupported OS Type " + OSType.getOSType().name());
|
||||||
|
}
|
||||||
|
ensureMinWorkGroupSize();
|
||||||
|
initQueue();
|
||||||
|
compilePrograms();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup()
|
||||||
|
{
|
||||||
|
if (programUnordered != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseProgram(programUnordered);
|
||||||
|
programUnordered = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (programSmall != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseProgram(programSmall);
|
||||||
|
programSmall = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (programLarge != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseProgram(programLarge);
|
||||||
|
programLarge = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kernelUnordered != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseKernel(kernelUnordered);
|
||||||
|
kernelUnordered = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kernelSmall != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseKernel(kernelSmall);
|
||||||
|
kernelSmall = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kernelLarge != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseKernel(kernelLarge);
|
||||||
|
kernelLarge = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commandQueue != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseCommandQueue(commandQueue);
|
||||||
|
commandQueue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseContext(context);
|
||||||
|
context = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device != null)
|
||||||
|
{
|
||||||
|
CL.clReleaseDevice(device);
|
||||||
|
device = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String logPlatformInfo(cl_platform_id platform, int param)
|
||||||
|
{
|
||||||
|
long[] size = new long[1];
|
||||||
|
clGetPlatformInfo(platform, param, 0, null, size);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[(int) size[0]];
|
||||||
|
clGetPlatformInfo(platform, param, buffer.length, Pointer.to(buffer), null);
|
||||||
|
String platformInfo = new String(buffer, Charsets.UTF_8);
|
||||||
|
log.debug("Platform: {}, {}", stringFor_cl_platform_info(param), platformInfo);
|
||||||
|
return platformInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logBuildInfo(cl_program program, int param)
|
||||||
|
{
|
||||||
|
long[] size = new long[1];
|
||||||
|
clGetProgramBuildInfo(program, device, param, 0, null, size);
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect((int) size[0]);
|
||||||
|
clGetProgramBuildInfo(program, device, param, buffer.limit(), Pointer.toBuffer(buffer), null);
|
||||||
|
|
||||||
|
switch (param)
|
||||||
|
{
|
||||||
|
case CL_PROGRAM_BUILD_STATUS:
|
||||||
|
log.debug("Build status: {}, {}", stringFor_cl_program_build_info(param), stringFor_cl_build_status(buffer.getInt()));
|
||||||
|
break;
|
||||||
|
case CL_PROGRAM_BINARY_TYPE:
|
||||||
|
log.debug("Binary type: {}, {}", stringFor_cl_program_build_info(param), stringFor_cl_program_binary_type(buffer.getInt()));
|
||||||
|
break;
|
||||||
|
case CL_PROGRAM_BUILD_LOG:
|
||||||
|
String buildLog = StandardCharsets.US_ASCII.decode(buffer).toString();
|
||||||
|
log.trace("Build log: {}, {}", stringFor_cl_program_build_info(param), buildLog);
|
||||||
|
break;
|
||||||
|
case CL_PROGRAM_BUILD_OPTIONS:
|
||||||
|
String message = StandardCharsets.US_ASCII.decode(buffer).toString();
|
||||||
|
log.debug("Build options: {}, {}", stringFor_cl_program_build_info(param), message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initPlatform()
|
||||||
|
{
|
||||||
|
int[] platformCount = new int[1];
|
||||||
|
clGetPlatformIDs(0, null, platformCount);
|
||||||
|
if (platformCount[0] == 0)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("No compute platforms found");
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_platform_id[] platforms = new cl_platform_id[platformCount[0]];
|
||||||
|
clGetPlatformIDs(platforms.length, platforms, null);
|
||||||
|
|
||||||
|
for (cl_platform_id platform : platforms)
|
||||||
|
{
|
||||||
|
log.debug("Found cl_platform_id {}", platform);
|
||||||
|
logPlatformInfo(platform, CL_PLATFORM_PROFILE);
|
||||||
|
logPlatformInfo(platform, CL_PLATFORM_VERSION);
|
||||||
|
logPlatformInfo(platform, CL_PLATFORM_NAME);
|
||||||
|
logPlatformInfo(platform, CL_PLATFORM_VENDOR);
|
||||||
|
String[] extensions = logPlatformInfo(platform, CL_PLATFORM_EXTENSIONS).split(" ");
|
||||||
|
if (Arrays.stream(extensions).noneMatch(s -> s.equals(GL_SHARING_PLATFORM_EXT)))
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Platform does not support OpenGL buffer sharing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
platform = platforms[0];
|
||||||
|
log.debug("Selected cl_platform_id {}", platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initDevice()
|
||||||
|
{
|
||||||
|
int[] deviceCount = new int[1];
|
||||||
|
clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, null, deviceCount);
|
||||||
|
if (deviceCount[0] == 0)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("No compute devices found");
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_device_id[] devices = new cl_device_id[(int) deviceCount[0]];
|
||||||
|
clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, devices.length, devices, null);
|
||||||
|
|
||||||
|
for (cl_device_id device : devices)
|
||||||
|
{
|
||||||
|
long[] size = new long[1];
|
||||||
|
clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, 0, null, size);
|
||||||
|
|
||||||
|
byte[] devInfoBuf = new byte[(int) size[0]];
|
||||||
|
clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, devInfoBuf.length, Pointer.to(devInfoBuf), null);
|
||||||
|
|
||||||
|
log.debug("Found cl_device_id: {}", device);
|
||||||
|
log.debug("Device extensions: {}", new String(devInfoBuf, Charsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
device = devices[0];
|
||||||
|
log.debug("Selected cl_device_id {}", device);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initContext(GL4 gl)
|
||||||
|
{
|
||||||
|
// set computation platform
|
||||||
|
cl_context_properties contextProps = new cl_context_properties();
|
||||||
|
contextProps.addProperty(CL_CONTEXT_PLATFORM, platform);
|
||||||
|
|
||||||
|
// pull gl context
|
||||||
|
GLContext glContext = gl.getContext();
|
||||||
|
log.debug("Got GLContext of type {}", glContext.getClass().getSimpleName());
|
||||||
|
if (!glContext.isCurrent())
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Can't create OpenCL context from inactive GL Context");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get correct props based on os
|
||||||
|
long glContextHandle = glContext.getHandle();
|
||||||
|
GLContextImpl glContextImpl = (GLContextImpl) glContext;
|
||||||
|
GLDrawableImpl glDrawableImpl = glContextImpl.getDrawableImpl();
|
||||||
|
NativeSurface nativeSurface = glDrawableImpl.getNativeSurface();
|
||||||
|
|
||||||
|
if (glContext instanceof X11GLXContext)
|
||||||
|
{
|
||||||
|
long displayHandle = nativeSurface.getDisplayHandle();
|
||||||
|
contextProps.addProperty(CL_GL_CONTEXT_KHR, glContextHandle);
|
||||||
|
contextProps.addProperty(CL_GLX_DISPLAY_KHR, displayHandle);
|
||||||
|
}
|
||||||
|
else if (glContext instanceof WindowsWGLContext)
|
||||||
|
{
|
||||||
|
long surfaceHandle = nativeSurface.getSurfaceHandle();
|
||||||
|
contextProps.addProperty(CL_GL_CONTEXT_KHR, glContextHandle);
|
||||||
|
contextProps.addProperty(CL_WGL_HDC_KHR, surfaceHandle);
|
||||||
|
}
|
||||||
|
else if (glContext instanceof EGLContext)
|
||||||
|
{
|
||||||
|
long displayHandle = nativeSurface.getDisplayHandle();
|
||||||
|
contextProps.addProperty(CL_GL_CONTEXT_KHR, glContextHandle);
|
||||||
|
contextProps.addProperty(CL_EGL_DISPLAY_KHR, displayHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Creating context with props: {}", contextProps);
|
||||||
|
context = clCreateContext(contextProps, 1, new cl_device_id[]{device}, null, null, null);
|
||||||
|
log.debug("Created compute context {}", context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initMacOS(GL4 gl)
|
||||||
|
{
|
||||||
|
// get sharegroup from gl context
|
||||||
|
GLContext glContext = gl.getContext();
|
||||||
|
if (!glContext.isCurrent())
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Can't create context from inactive GL");
|
||||||
|
}
|
||||||
|
long cglContext = CGL.CGLGetCurrentContext();
|
||||||
|
long cglShareGroup = CGL.CGLGetShareGroup(cglContext);
|
||||||
|
|
||||||
|
// build context props
|
||||||
|
cl_context_properties contextProps = new cl_context_properties();
|
||||||
|
contextProps.addProperty(CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, cglShareGroup);
|
||||||
|
|
||||||
|
// ask macos to make the context for us
|
||||||
|
log.debug("Creating context with props: {}", contextProps);
|
||||||
|
context = clCreateContext(contextProps, 0, null, null, null, null);
|
||||||
|
|
||||||
|
// pull the compute device out of the provided context
|
||||||
|
device = new cl_device_id();
|
||||||
|
clGetGLContextInfoAPPLE(context, cglContext, CL_CGL_DEVICE_FOR_CURRENT_VIRTUAL_SCREEN_APPLE, Sizeof.cl_device_id, Pointer.to(device), null);
|
||||||
|
|
||||||
|
log.debug("Got macOS CLGL compute device {}", device);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureMinWorkGroupSize()
|
||||||
|
{
|
||||||
|
long[] maxWorkGroupSize = new long[1];
|
||||||
|
clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, Sizeof.size_t, Pointer.to(maxWorkGroupSize), null);
|
||||||
|
log.debug("Device CL_DEVICE_MAX_WORK_GROUP_SIZE: {}", maxWorkGroupSize[0]);
|
||||||
|
|
||||||
|
if (maxWorkGroupSize[0] < MIN_WORK_GROUP_SIZE)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Compute device does not support min work group size " + MIN_WORK_GROUP_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Largest power of 2 less than or equal to maxWorkGroupSize
|
||||||
|
int groupSize = 0x80000000 >>> Integer.numberOfLeadingZeros((int) maxWorkGroupSize[0]);
|
||||||
|
largeFaceCount = LARGE_SIZE / (Math.min(groupSize, LARGE_SIZE));
|
||||||
|
smallFaceCount = SMALL_SIZE / (Math.min(groupSize, SMALL_SIZE));
|
||||||
|
|
||||||
|
log.debug("Face counts: small: {}, large: {}", smallFaceCount, largeFaceCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initQueue()
|
||||||
|
{
|
||||||
|
long[] l = new long[1];
|
||||||
|
clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, Sizeof.cl_long, Pointer.to(l), null);
|
||||||
|
|
||||||
|
commandQueue = clCreateCommandQueue(context, device, l[0] & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, null);
|
||||||
|
log.debug("Created command_queue {}, properties {}", commandQueue, l[0] & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private cl_program compileProgram(String programSource)
|
||||||
|
{
|
||||||
|
log.trace("Compiling program:\n {}", programSource);
|
||||||
|
cl_program program = clCreateProgramWithSource(context, 1, new String[]{programSource}, null, null);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
clBuildProgram(program, 0, null, null, null, null);
|
||||||
|
}
|
||||||
|
catch (CLException e)
|
||||||
|
{
|
||||||
|
logBuildInfo(program, CL_PROGRAM_BUILD_LOG);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
logBuildInfo(program, CL_PROGRAM_BUILD_STATUS);
|
||||||
|
logBuildInfo(program, CL_PROGRAM_BINARY_TYPE);
|
||||||
|
logBuildInfo(program, CL_PROGRAM_BUILD_OPTIONS);
|
||||||
|
logBuildInfo(program, CL_PROGRAM_BUILD_LOG);
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
private cl_kernel getKernel(cl_program program, String kernelName)
|
||||||
|
{
|
||||||
|
cl_kernel kernel = clCreateKernel(program, kernelName, null);
|
||||||
|
log.debug("Loaded kernel {} for program {}", kernelName, program);
|
||||||
|
return kernel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compilePrograms()
|
||||||
|
{
|
||||||
|
Template templateSmall = new Template()
|
||||||
|
.addInclude(OpenCLManager.class)
|
||||||
|
.add(key -> key.equals("FACE_COUNT") ? ("#define FACE_COUNT " + smallFaceCount) : null);
|
||||||
|
Template templateLarge = new Template()
|
||||||
|
.addInclude(OpenCLManager.class)
|
||||||
|
.add(key -> key.equals("FACE_COUNT") ? ("#define FACE_COUNT " + largeFaceCount) : null);
|
||||||
|
|
||||||
|
String unordered = new Template()
|
||||||
|
.addInclude(OpenCLManager.class)
|
||||||
|
.load("comp_unordered.cl");
|
||||||
|
String small = templateSmall.load("comp.cl");
|
||||||
|
String large = templateLarge.load("comp.cl");
|
||||||
|
|
||||||
|
programUnordered = compileProgram(unordered);
|
||||||
|
programSmall = compileProgram(small);
|
||||||
|
programLarge = compileProgram(large);
|
||||||
|
|
||||||
|
kernelUnordered = getKernel(programUnordered, KERNEL_NAME_UNORDERED);
|
||||||
|
kernelSmall = getKernel(programSmall, KERNEL_NAME_LARGE);
|
||||||
|
kernelLarge = getKernel(programLarge, KERNEL_NAME_LARGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compute(int unorderedModels, int smallModels, int largeModels,
|
||||||
|
GLBuffer sceneVertexBuffer,
|
||||||
|
GLBuffer sceneUvBuffer,
|
||||||
|
GLBuffer vertexBuffer,
|
||||||
|
GLBuffer uvBuffer,
|
||||||
|
GLBuffer unorderedBuffer,
|
||||||
|
GLBuffer smallBuffer,
|
||||||
|
GLBuffer largeBuffer,
|
||||||
|
GLBuffer outVertexBuffer,
|
||||||
|
GLBuffer outUvBuffer,
|
||||||
|
GLBuffer uniformBuffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
cl_mem[] glBuffersAll = {
|
||||||
|
sceneVertexBuffer.cl_mem,
|
||||||
|
sceneUvBuffer.cl_mem,
|
||||||
|
unorderedBuffer.cl_mem,
|
||||||
|
smallBuffer.cl_mem,
|
||||||
|
largeBuffer.cl_mem,
|
||||||
|
vertexBuffer.cl_mem,
|
||||||
|
uvBuffer.cl_mem,
|
||||||
|
outVertexBuffer.cl_mem,
|
||||||
|
outUvBuffer.cl_mem,
|
||||||
|
uniformBuffer.cl_mem,
|
||||||
|
};
|
||||||
|
cl_mem[] glBuffers = Arrays.stream(glBuffersAll)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toArray(cl_mem[]::new);
|
||||||
|
|
||||||
|
cl_event acquireGLBuffers = new cl_event();
|
||||||
|
clEnqueueAcquireGLObjects(commandQueue, glBuffers.length, glBuffers, 0, null, acquireGLBuffers);
|
||||||
|
|
||||||
|
cl_event[] computeEvents = {
|
||||||
|
new cl_event(),
|
||||||
|
new cl_event(),
|
||||||
|
new cl_event()
|
||||||
|
};
|
||||||
|
int numComputeEvents = 0;
|
||||||
|
|
||||||
|
if (unorderedModels > 0)
|
||||||
|
{
|
||||||
|
clSetKernelArg(kernelUnordered, 0, Sizeof.cl_mem, unorderedBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelUnordered, 1, Sizeof.cl_mem, sceneVertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelUnordered, 2, Sizeof.cl_mem, vertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelUnordered, 3, Sizeof.cl_mem, sceneUvBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelUnordered, 4, Sizeof.cl_mem, uvBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelUnordered, 5, Sizeof.cl_mem, outVertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelUnordered, 6, Sizeof.cl_mem, outUvBuffer.ptr());
|
||||||
|
|
||||||
|
// queue compute call after acquireGLBuffers
|
||||||
|
clEnqueueNDRangeKernel(commandQueue, kernelUnordered, 1, null,
|
||||||
|
new long[]{unorderedModels * 6L}, new long[]{6}, 1, new cl_event[]{acquireGLBuffers}, computeEvents[numComputeEvents++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smallModels > 0)
|
||||||
|
{
|
||||||
|
clSetKernelArg(kernelSmall, 0, (SHARED_SIZE + SMALL_SIZE) * Integer.BYTES, null);
|
||||||
|
clSetKernelArg(kernelSmall, 1, Sizeof.cl_mem, smallBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelSmall, 2, Sizeof.cl_mem, sceneVertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelSmall, 3, Sizeof.cl_mem, vertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelSmall, 4, Sizeof.cl_mem, sceneUvBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelSmall, 5, Sizeof.cl_mem, uvBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelSmall, 6, Sizeof.cl_mem, outVertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelSmall, 7, Sizeof.cl_mem, outUvBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelSmall, 8, Sizeof.cl_mem, uniformBuffer.ptr());
|
||||||
|
|
||||||
|
clEnqueueNDRangeKernel(commandQueue, kernelSmall, 1, null,
|
||||||
|
new long[]{smallModels * (SMALL_SIZE / smallFaceCount)}, new long[]{SMALL_SIZE / smallFaceCount}, 1, new cl_event[]{acquireGLBuffers}, computeEvents[numComputeEvents++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (largeModels > 0)
|
||||||
|
{
|
||||||
|
clSetKernelArg(kernelLarge, 0, (SHARED_SIZE + LARGE_SIZE) * Integer.BYTES, null);
|
||||||
|
clSetKernelArg(kernelLarge, 1, Sizeof.cl_mem, largeBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelLarge, 2, Sizeof.cl_mem, sceneVertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelLarge, 3, Sizeof.cl_mem, vertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelLarge, 4, Sizeof.cl_mem, sceneUvBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelLarge, 5, Sizeof.cl_mem, uvBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelLarge, 6, Sizeof.cl_mem, outVertexBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelLarge, 7, Sizeof.cl_mem, outUvBuffer.ptr());
|
||||||
|
clSetKernelArg(kernelLarge, 8, Sizeof.cl_mem, uniformBuffer.ptr());
|
||||||
|
|
||||||
|
clEnqueueNDRangeKernel(commandQueue, kernelLarge, 1, null,
|
||||||
|
new long[]{(long) largeModels * (LARGE_SIZE / largeFaceCount)}, new long[]{LARGE_SIZE / largeFaceCount}, 1, new cl_event[]{acquireGLBuffers}, computeEvents[numComputeEvents++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
clEnqueueReleaseGLObjects(commandQueue, glBuffers.length, glBuffers, numComputeEvents, computeEvents, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void finish()
|
||||||
|
{
|
||||||
|
clFinish(commandQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,12 +75,14 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
private static final Duration DESPAWN_TIME_INSTANCE = Duration.ofMinutes(30);
|
private static final Duration DESPAWN_TIME_INSTANCE = Duration.ofMinutes(30);
|
||||||
private static final Duration DESPAWN_TIME_LOOT = Duration.ofMinutes(2);
|
private static final Duration DESPAWN_TIME_LOOT = Duration.ofMinutes(2);
|
||||||
private static final Duration DESPAWN_TIME_DROP = Duration.ofMinutes(3);
|
private static final Duration DESPAWN_TIME_DROP = Duration.ofMinutes(3);
|
||||||
|
private static final Duration DESPAWN_TIME_TABLE = Duration.ofMinutes(10);
|
||||||
private static final int KRAKEN_REGION = 9116;
|
private static final int KRAKEN_REGION = 9116;
|
||||||
private static final int KBD_NMZ_REGION = 9033;
|
private static final int KBD_NMZ_REGION = 9033;
|
||||||
private static final int ZILYANA_REGION = 11602;
|
private static final int ZILYANA_REGION = 11602;
|
||||||
private static final int GRAARDOR_REGION = 11347;
|
private static final int GRAARDOR_REGION = 11347;
|
||||||
private static final int KRIL_TSUTSAROTH_REGION = 11603;
|
private static final int KRIL_TSUTSAROTH_REGION = 11603;
|
||||||
private static final int KREEARRA_REGION = 11346;
|
private static final int KREEARRA_REGION = 11346;
|
||||||
|
private static final int NIGHTMARE_REGION = 15515;
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final GroundItemsPlugin plugin;
|
private final GroundItemsPlugin plugin;
|
||||||
@@ -397,8 +399,11 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
|
|
||||||
private Instant calculateDespawnTime(GroundItem groundItem)
|
private Instant calculateDespawnTime(GroundItem groundItem)
|
||||||
{
|
{
|
||||||
// We can only accurately guess despawn times for our own pvm loot and dropped items
|
// We can only accurately guess despawn times for our own pvm loot, dropped items,
|
||||||
if (groundItem.getLootType() != LootType.PVM && groundItem.getLootType() != LootType.DROPPED)
|
// and items we placed on tables
|
||||||
|
if (groundItem.getLootType() != LootType.PVM
|
||||||
|
&& groundItem.getLootType() != LootType.DROPPED
|
||||||
|
&& groundItem.getLootType() != LootType.TABLE)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -447,9 +452,9 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (playerRegionID == ZILYANA_REGION || playerRegionID == GRAARDOR_REGION ||
|
else if (playerRegionID == ZILYANA_REGION || playerRegionID == GRAARDOR_REGION ||
|
||||||
playerRegionID == KRIL_TSUTSAROTH_REGION || playerRegionID == KREEARRA_REGION)
|
playerRegionID == KRIL_TSUTSAROTH_REGION || playerRegionID == KREEARRA_REGION || playerRegionID == NIGHTMARE_REGION)
|
||||||
{
|
{
|
||||||
// GWD instances use the normal despawn timers
|
// GWD and Nightmare instances use the normal despawn timers
|
||||||
despawnTime = spawnTime.plus(groundItem.getLootType() == LootType.DROPPED
|
despawnTime = spawnTime.plus(groundItem.getLootType() == LootType.DROPPED
|
||||||
? DESPAWN_TIME_DROP
|
? DESPAWN_TIME_DROP
|
||||||
: DESPAWN_TIME_LOOT);
|
: DESPAWN_TIME_LOOT);
|
||||||
@@ -461,9 +466,18 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
despawnTime = spawnTime.plus(groundItem.getLootType() == LootType.DROPPED
|
switch (groundItem.getLootType())
|
||||||
? DESPAWN_TIME_DROP
|
{
|
||||||
: DESPAWN_TIME_LOOT);
|
case DROPPED:
|
||||||
|
despawnTime = spawnTime.plus(DESPAWN_TIME_DROP);
|
||||||
|
break;
|
||||||
|
case TABLE:
|
||||||
|
despawnTime = spawnTime.plus(DESPAWN_TIME_TABLE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
despawnTime = spawnTime.plus(DESPAWN_TIME_LOOT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (now.isBefore(spawnTime) || now.isAfter(despawnTime))
|
if (now.isBefore(spawnTime) || now.isAfter(despawnTime))
|
||||||
@@ -477,8 +491,11 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
|
|
||||||
private Color getItemTimerColor(GroundItem groundItem)
|
private Color getItemTimerColor(GroundItem groundItem)
|
||||||
{
|
{
|
||||||
// We can only accurately guess despawn times for our own pvm loot and dropped items
|
// We can only accurately guess despawn times for our own pvm loot, dropped items,
|
||||||
if (groundItem.getLootType() != LootType.PVM && groundItem.getLootType() != LootType.DROPPED)
|
// and items we placed on tables
|
||||||
|
if (groundItem.getLootType() != LootType.PVM
|
||||||
|
&& groundItem.getLootType() != LootType.DROPPED
|
||||||
|
&& groundItem.getLootType() != LootType.TABLE)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,11 +52,13 @@ import lombok.Setter;
|
|||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.GameState;
|
import net.runelite.api.GameState;
|
||||||
|
import net.runelite.api.InventoryID;
|
||||||
|
import net.runelite.api.Item;
|
||||||
import net.runelite.api.ItemComposition;
|
import net.runelite.api.ItemComposition;
|
||||||
|
import net.runelite.api.ItemContainer;
|
||||||
import net.runelite.api.ItemID;
|
import net.runelite.api.ItemID;
|
||||||
import net.runelite.api.MenuAction;
|
import net.runelite.api.MenuAction;
|
||||||
import net.runelite.api.MenuEntry;
|
import net.runelite.api.MenuEntry;
|
||||||
import net.runelite.api.Player;
|
|
||||||
import net.runelite.api.Tile;
|
import net.runelite.api.Tile;
|
||||||
import net.runelite.api.TileItem;
|
import net.runelite.api.TileItem;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
@@ -180,6 +182,7 @@ public class GroundItemsPlugin extends Plugin
|
|||||||
private LoadingCache<NamedQuantity, Boolean> highlightedItems;
|
private LoadingCache<NamedQuantity, Boolean> highlightedItems;
|
||||||
private LoadingCache<NamedQuantity, Boolean> hiddenItems;
|
private LoadingCache<NamedQuantity, Boolean> hiddenItems;
|
||||||
private final Queue<Integer> droppedItemQueue = EvictingQueue.create(16); // recently dropped items
|
private final Queue<Integer> droppedItemQueue = EvictingQueue.create(16); // recently dropped items
|
||||||
|
private int lastUsedItem;
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
GroundItemsConfig provideConfig(ConfigManager configManager)
|
GroundItemsConfig provideConfig(ConfigManager configManager)
|
||||||
@@ -194,6 +197,7 @@ public class GroundItemsPlugin extends Plugin
|
|||||||
mouseManager.registerMouseListener(inputListener);
|
mouseManager.registerMouseListener(inputListener);
|
||||||
keyManager.registerKeyListener(inputListener);
|
keyManager.registerKeyListener(inputListener);
|
||||||
executor.execute(this::reset);
|
executor.execute(this::reset);
|
||||||
|
lastUsedItem = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -384,6 +388,7 @@ public class GroundItemsPlugin extends Plugin
|
|||||||
final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemId;
|
final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemId;
|
||||||
final int alchPrice = itemComposition.getHaPrice();
|
final int alchPrice = itemComposition.getHaPrice();
|
||||||
final boolean dropped = tile.getWorldLocation().equals(client.getLocalPlayer().getWorldLocation()) && droppedItemQueue.remove(itemId);
|
final boolean dropped = tile.getWorldLocation().equals(client.getLocalPlayer().getWorldLocation()) && droppedItemQueue.remove(itemId);
|
||||||
|
final boolean table = itemId == lastUsedItem && tile.getItemLayer().getHeight() > 0;
|
||||||
|
|
||||||
final GroundItem groundItem = GroundItem.builder()
|
final GroundItem groundItem = GroundItem.builder()
|
||||||
.id(itemId)
|
.id(itemId)
|
||||||
@@ -394,12 +399,11 @@ public class GroundItemsPlugin extends Plugin
|
|||||||
.haPrice(alchPrice)
|
.haPrice(alchPrice)
|
||||||
.height(tile.getItemLayer().getHeight())
|
.height(tile.getItemLayer().getHeight())
|
||||||
.tradeable(itemComposition.isTradeable())
|
.tradeable(itemComposition.isTradeable())
|
||||||
.lootType(dropped ? LootType.DROPPED : LootType.UNKNOWN)
|
.lootType(dropped ? LootType.DROPPED : (table ? LootType.TABLE : LootType.UNKNOWN))
|
||||||
.spawnTime(Instant.now())
|
.spawnTime(Instant.now())
|
||||||
.stackable(itemComposition.isStackable())
|
.stackable(itemComposition.isStackable())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
// Update item price in case it is coins
|
// Update item price in case it is coins
|
||||||
if (realItemId == COINS)
|
if (realItemId == COINS)
|
||||||
{
|
{
|
||||||
@@ -638,11 +642,8 @@ public class GroundItemsPlugin extends Plugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Player local = client.getLocalPlayer();
|
|
||||||
final StringBuilder notificationStringBuilder = new StringBuilder()
|
final StringBuilder notificationStringBuilder = new StringBuilder()
|
||||||
.append('[')
|
.append("You received a ")
|
||||||
.append(local.getName())
|
|
||||||
.append("] received a ")
|
|
||||||
.append(dropType)
|
.append(dropType)
|
||||||
.append(" drop: ")
|
.append(" drop: ")
|
||||||
.append(item.getName());
|
.append(item.getName());
|
||||||
@@ -687,5 +688,21 @@ public class GroundItemsPlugin extends Plugin
|
|||||||
// item spawns that are drops
|
// item spawns that are drops
|
||||||
droppedItemQueue.add(itemId);
|
droppedItemQueue.add(itemId);
|
||||||
}
|
}
|
||||||
|
else if (menuOptionClicked.getMenuAction() == MenuAction.ITEM_USE_ON_GAME_OBJECT)
|
||||||
|
{
|
||||||
|
final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY);
|
||||||
|
if (inventory == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Item clickedItem = inventory.getItem(menuOptionClicked.getSelectedItemIndex());
|
||||||
|
if (clickedItem == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastUsedItem = clickedItem.getId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package net.runelite.client.plugins.grounditems;
|
|||||||
enum LootType
|
enum LootType
|
||||||
{
|
{
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
|
TABLE,
|
||||||
DROPPED,
|
DROPPED,
|
||||||
PVP,
|
PVP,
|
||||||
PVM;
|
PVM;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
@@ -313,21 +314,22 @@ public class GroundMarkerPlugin extends Plugin
|
|||||||
WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, localPoint);
|
WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, localPoint);
|
||||||
final int regionId = worldPoint.getRegionID();
|
final int regionId = worldPoint.getRegionID();
|
||||||
|
|
||||||
|
GroundMarkerPoint searchPoint = new GroundMarkerPoint(regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), client.getPlane(), null, null);
|
||||||
|
Collection<GroundMarkerPoint> points = getPoints(regionId);
|
||||||
|
GroundMarkerPoint existing = points.stream()
|
||||||
|
.filter(p -> p.equals(searchPoint))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
if (existing == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
chatboxPanelManager.openTextInput("Tile label")
|
chatboxPanelManager.openTextInput("Tile label")
|
||||||
|
.value(Optional.ofNullable(existing.getLabel()).orElse(""))
|
||||||
.onDone((input) ->
|
.onDone((input) ->
|
||||||
{
|
{
|
||||||
input = Strings.emptyToNull(input);
|
input = Strings.emptyToNull(input);
|
||||||
|
|
||||||
GroundMarkerPoint searchPoint = new GroundMarkerPoint(regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), client.getPlane(), null, null);
|
|
||||||
Collection<GroundMarkerPoint> points = getPoints(regionId);
|
|
||||||
GroundMarkerPoint existing = points.stream()
|
|
||||||
.filter(p -> p.equals(searchPoint))
|
|
||||||
.findFirst().orElse(null);
|
|
||||||
if (existing == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GroundMarkerPoint newPoint = new GroundMarkerPoint(regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), client.getPlane(), existing.getColor(), input);
|
GroundMarkerPoint newPoint = new GroundMarkerPoint(regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), client.getPlane(), existing.getColor(), input);
|
||||||
points.remove(searchPoint);
|
points.remove(searchPoint);
|
||||||
points.add(newPoint);
|
points.add(newPoint);
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ public class IdleNotifierPlugin extends Plugin
|
|||||||
case COOKING_FIRE:
|
case COOKING_FIRE:
|
||||||
case COOKING_RANGE:
|
case COOKING_RANGE:
|
||||||
case COOKING_WINE:
|
case COOKING_WINE:
|
||||||
/* Crafting(Gem Cutting, Glassblowing, Spinning, Battlestaves, Pottery) */
|
/* Crafting(Gem Cutting, Glassblowing, Spinning, Weaving, Battlestaves, Pottery) */
|
||||||
case GEM_CUTTING_OPAL:
|
case GEM_CUTTING_OPAL:
|
||||||
case GEM_CUTTING_JADE:
|
case GEM_CUTTING_JADE:
|
||||||
case GEM_CUTTING_REDTOPAZ:
|
case GEM_CUTTING_REDTOPAZ:
|
||||||
@@ -158,6 +158,7 @@ public class IdleNotifierPlugin extends Plugin
|
|||||||
case GEM_CUTTING_AMETHYST:
|
case GEM_CUTTING_AMETHYST:
|
||||||
case CRAFTING_GLASSBLOWING:
|
case CRAFTING_GLASSBLOWING:
|
||||||
case CRAFTING_SPINNING:
|
case CRAFTING_SPINNING:
|
||||||
|
case CRAFTING_LOOM:
|
||||||
case CRAFTING_BATTLESTAVES:
|
case CRAFTING_BATTLESTAVES:
|
||||||
case CRAFTING_LEATHER:
|
case CRAFTING_LEATHER:
|
||||||
case CRAFTING_POTTERS_WHEEL:
|
case CRAFTING_POTTERS_WHEEL:
|
||||||
@@ -268,6 +269,10 @@ public class IdleNotifierPlugin extends Plugin
|
|||||||
case MAGIC_ENCHANTING_BOLTS:
|
case MAGIC_ENCHANTING_BOLTS:
|
||||||
/* Prayer */
|
/* Prayer */
|
||||||
case USING_GILDED_ALTAR:
|
case USING_GILDED_ALTAR:
|
||||||
|
case ECTOFUNTUS_FILL_SLIME_BUCKET:
|
||||||
|
case ECTOFUNTUS_INSERT_BONES:
|
||||||
|
case ECTOFUNTUS_GRIND_BONES:
|
||||||
|
case ECTOFUNTUS_EMPTY_BIN:
|
||||||
/* Farming */
|
/* Farming */
|
||||||
case FARMING_MIX_ULTRACOMPOST:
|
case FARMING_MIX_ULTRACOMPOST:
|
||||||
case FARMING_HARVEST_BUSH:
|
case FARMING_HARVEST_BUSH:
|
||||||
@@ -433,64 +438,64 @@ public class IdleNotifierPlugin extends Plugin
|
|||||||
|
|
||||||
if (config.logoutIdle() && checkIdleLogout())
|
if (config.logoutIdle() && checkIdleLogout())
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] is about to log out from idling too long!");
|
notifier.notify("You are about to log out from idling too long!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check6hrLogout())
|
if (check6hrLogout())
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] is about to log out from being online for 6 hours!");
|
notifier.notify("You are about to log out from being online for 6 hours!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.animationIdle() && checkAnimationIdle(waitDuration, local))
|
if (config.animationIdle() && checkAnimationIdle(waitDuration, local))
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] is now idle!");
|
notifier.notify("You are now idle!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.movementIdle() && checkMovementIdle(waitDuration, local))
|
if (config.movementIdle() && checkMovementIdle(waitDuration, local))
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] has stopped moving!");
|
notifier.notify("You have stopped moving!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.interactionIdle() && checkInteractionIdle(waitDuration, local))
|
if (config.interactionIdle() && checkInteractionIdle(waitDuration, local))
|
||||||
{
|
{
|
||||||
if (lastInteractWasCombat)
|
if (lastInteractWasCombat)
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] is now out of combat!");
|
notifier.notify("You are now out of combat!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] is now idle!");
|
notifier.notify("You are now idle!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkLowHitpoints())
|
if (checkLowHitpoints())
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] has low hitpoints!");
|
notifier.notify("You have low hitpoints!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkLowPrayer())
|
if (checkLowPrayer())
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] has low prayer!");
|
notifier.notify("You have low prayer!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkLowEnergy())
|
if (checkLowEnergy())
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] has low run energy!");
|
notifier.notify("You have low run energy!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkHighEnergy())
|
if (checkHighEnergy())
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] has restored run energy!");
|
notifier.notify("You have restored run energy!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkLowOxygen())
|
if (checkLowOxygen())
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] has low oxygen!");
|
notifier.notify("You have low oxygen!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkFullSpecEnergy())
|
if (checkFullSpecEnergy())
|
||||||
{
|
{
|
||||||
notifier.notify("[" + local.getName() + "] has restored spec energy!");
|
notifier.notify("You have restored spec energy!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,17 @@ public interface MenuEntrySwapperConfig extends Config
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "swapBattlestaves",
|
||||||
|
name = "Battlestaff",
|
||||||
|
description = "Swap Wield with Use on Battlestaves without orbs",
|
||||||
|
section = itemSection
|
||||||
|
)
|
||||||
|
default boolean swapBattlestaves()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "swapPrayerBook",
|
keyName = "swapPrayerBook",
|
||||||
name = "Recite-Prayer",
|
name = "Recite-Prayer",
|
||||||
|
|||||||
@@ -334,6 +334,8 @@ public class MenuEntrySwapperPlugin extends Plugin
|
|||||||
|
|
||||||
swap("bury", "use", config::swapBones);
|
swap("bury", "use", config::swapBones);
|
||||||
|
|
||||||
|
swap("wield", "battlestaff", "use", config::swapBattlestaves);
|
||||||
|
|
||||||
swap("clean", "use", config::swapHerbs);
|
swap("clean", "use", config::swapHerbs);
|
||||||
|
|
||||||
swap("read", "recite-prayer", config::swapPrayerBook);
|
swap("read", "recite-prayer", config::swapPrayerBook);
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ public class RegenMeterPlugin extends Plugin
|
|||||||
|
|
||||||
if (config.getNotifyBeforeHpRegenSeconds() > 0 && currentHP < maxHP && shouldNotifyHpRegenThisTick(ticksPerHPRegen))
|
if (config.getNotifyBeforeHpRegenSeconds() > 0 && currentHP < maxHP && shouldNotifyHpRegenThisTick(ticksPerHPRegen))
|
||||||
{
|
{
|
||||||
notifier.notify("[" + client.getLocalPlayer().getName() + "] regenerates their next hitpoint soon!");
|
notifier.notify("Your next hitpoint will regenerate soon!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,11 +205,23 @@ public interface ScreenshotConfig extends Config
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "valuableDropThreshold",
|
||||||
|
name = "Valuable Threshold",
|
||||||
|
description = "The minimum value to save screenshots of valuable drops.",
|
||||||
|
position = 14,
|
||||||
|
section = whatSection
|
||||||
|
)
|
||||||
|
default int valuableDropThreshold()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "untradeableDrop",
|
keyName = "untradeableDrop",
|
||||||
name = "Screenshot Untradeable drops",
|
name = "Screenshot Untradeable drops",
|
||||||
description = "Configures whether or not screenshots are automatically taken when you receive an untradeable drop.",
|
description = "Configures whether or not screenshots are automatically taken when you receive an untradeable drop.",
|
||||||
position = 14,
|
position = 15,
|
||||||
section = whatSection
|
section = whatSection
|
||||||
)
|
)
|
||||||
default boolean screenshotUntradeableDrop()
|
default boolean screenshotUntradeableDrop()
|
||||||
@@ -221,7 +233,7 @@ public interface ScreenshotConfig extends Config
|
|||||||
keyName = "ccKick",
|
keyName = "ccKick",
|
||||||
name = "Screenshot Kicks from FC",
|
name = "Screenshot Kicks from FC",
|
||||||
description = "Take a screenshot when you kick a user from a friends chat.",
|
description = "Take a screenshot when you kick a user from a friends chat.",
|
||||||
position = 15,
|
position = 16,
|
||||||
section = whatSection
|
section = whatSection
|
||||||
)
|
)
|
||||||
default boolean screenshotKick()
|
default boolean screenshotKick()
|
||||||
@@ -233,7 +245,7 @@ public interface ScreenshotConfig extends Config
|
|||||||
keyName = "baHighGamble",
|
keyName = "baHighGamble",
|
||||||
name = "Screenshot BA high gambles",
|
name = "Screenshot BA high gambles",
|
||||||
description = "Take a screenshot of your reward from a high gamble at Barbarian Assault.",
|
description = "Take a screenshot of your reward from a high gamble at Barbarian Assault.",
|
||||||
position = 16,
|
position = 17,
|
||||||
section = whatSection
|
section = whatSection
|
||||||
)
|
)
|
||||||
default boolean screenshotHighGamble()
|
default boolean screenshotHighGamble()
|
||||||
@@ -245,7 +257,7 @@ public interface ScreenshotConfig extends Config
|
|||||||
keyName = "hotkey",
|
keyName = "hotkey",
|
||||||
name = "Screenshot hotkey",
|
name = "Screenshot hotkey",
|
||||||
description = "When you press this key a screenshot will be taken",
|
description = "When you press this key a screenshot will be taken",
|
||||||
position = 17
|
position = 18
|
||||||
)
|
)
|
||||||
default Keybind hotkey()
|
default Keybind hotkey()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public class ScreenshotPlugin extends Plugin
|
|||||||
private static final Pattern NUMBER_PATTERN = Pattern.compile("([0-9]+)");
|
private static final Pattern NUMBER_PATTERN = Pattern.compile("([0-9]+)");
|
||||||
private static final Pattern LEVEL_UP_PATTERN = Pattern.compile(".*Your ([a-zA-Z]+) (?:level is|are)? now (\\d+)\\.");
|
private static final Pattern LEVEL_UP_PATTERN = Pattern.compile(".*Your ([a-zA-Z]+) (?:level is|are)? now (\\d+)\\.");
|
||||||
private static final Pattern BOSSKILL_MESSAGE_PATTERN = Pattern.compile("Your (.+) kill count is: <col=ff0000>(\\d+)</col>.");
|
private static final Pattern BOSSKILL_MESSAGE_PATTERN = Pattern.compile("Your (.+) kill count is: <col=ff0000>(\\d+)</col>.");
|
||||||
private static final Pattern VALUABLE_DROP_PATTERN = Pattern.compile(".*Valuable drop: ([^<>]+)(?:</col>)?");
|
private static final Pattern VALUABLE_DROP_PATTERN = Pattern.compile(".*Valuable drop: ([^<>]+?\\(((?:\\d+,?)+) coins\\))(?:</col>)?");
|
||||||
private static final Pattern UNTRADEABLE_DROP_PATTERN = Pattern.compile(".*Untradeable drop: ([^<>]+)(?:</col>)?");
|
private static final Pattern UNTRADEABLE_DROP_PATTERN = Pattern.compile(".*Untradeable drop: ([^<>]+)(?:</col>)?");
|
||||||
private static final Pattern DUEL_END_PATTERN = Pattern.compile("You have now (won|lost) ([0-9]+) duels?\\.");
|
private static final Pattern DUEL_END_PATTERN = Pattern.compile("You have now (won|lost) ([0-9]+) duels?\\.");
|
||||||
private static final Pattern QUEST_PATTERN_1 = Pattern.compile(".+?ve\\.*? (?<verb>been|rebuilt|.+?ed)? ?(?:the )?'?(?<quest>.+?)'?(?: [Qq]uest)?[!.]?$");
|
private static final Pattern QUEST_PATTERN_1 = Pattern.compile(".+?ve\\.*? (?<verb>been|rebuilt|.+?ed)? ?(?:the )?'?(?<quest>.+?)'?(?: [Qq]uest)?[!.]?$");
|
||||||
@@ -417,9 +417,13 @@ public class ScreenshotPlugin extends Plugin
|
|||||||
Matcher m = VALUABLE_DROP_PATTERN.matcher(chatMessage);
|
Matcher m = VALUABLE_DROP_PATTERN.matcher(chatMessage);
|
||||||
if (m.matches())
|
if (m.matches())
|
||||||
{
|
{
|
||||||
String valuableDropName = m.group(1);
|
int valuableDropValue = Integer.parseInt(m.group(2).replaceAll(",", ""));
|
||||||
String fileName = "Valuable drop " + valuableDropName;
|
if (valuableDropValue >= config.valuableDropThreshold())
|
||||||
takeScreenshot(fileName, "Valuable Drops");
|
{
|
||||||
|
String valuableDropName = m.group(1);
|
||||||
|
String fileName = "Valuable drop " + valuableDropName;
|
||||||
|
takeScreenshot(fileName, "Valuable Drops");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import java.awt.Color;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.event.FocusAdapter;
|
import java.awt.event.FocusAdapter;
|
||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
|
import java.awt.event.KeyAdapter;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
@@ -95,7 +97,14 @@ class SkillCalculator extends JPanel
|
|||||||
searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
|
searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
|
||||||
searchBar.addClearListener(this::onSearch);
|
searchBar.addClearListener(this::onSearch);
|
||||||
searchBar.addKeyListener(e -> onSearch());
|
searchBar.addKeyListener(new KeyAdapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void keyTyped(KeyEvent e)
|
||||||
|
{
|
||||||
|
onSearch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
setLayout(new DynamicGridLayout(0, 1, 0, 5));
|
setLayout(new DynamicGridLayout(0, 1, 0, 5));
|
||||||
|
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ enum Task
|
|||||||
"Fremennik Slayer Dungeon",
|
"Fremennik Slayer Dungeon",
|
||||||
"God Wars Dungeon",
|
"God Wars Dungeon",
|
||||||
"Iorwerth Dungeon",
|
"Iorwerth Dungeon",
|
||||||
|
"Isle of Souls",
|
||||||
"Jormungand's Prison",
|
"Jormungand's Prison",
|
||||||
"Kalphite Lair",
|
"Kalphite Lair",
|
||||||
"Karuulm Slayer Dungeon",
|
"Karuulm Slayer Dungeon",
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ public class TimersPlugin extends Plugin
|
|||||||
private static final String CANNON_FURNACE_MESSAGE = "You add the furnace.";
|
private static final String CANNON_FURNACE_MESSAGE = "You add the furnace.";
|
||||||
private static final String CANNON_PICKUP_MESSAGE = "You pick up the cannon. It's really heavy.";
|
private static final String CANNON_PICKUP_MESSAGE = "You pick up the cannon. It's really heavy.";
|
||||||
private static final String CANNON_REPAIR_MESSAGE = "You repair your cannon, restoring it to working order.";
|
private static final String CANNON_REPAIR_MESSAGE = "You repair your cannon, restoring it to working order.";
|
||||||
|
private static final String CANNON_DESTROYED_MESSAGE = "Your cannon has been destroyed!";
|
||||||
private static final String CHARGE_EXPIRED_MESSAGE = "<col=ef1020>Your magical charge fades away.</col>";
|
private static final String CHARGE_EXPIRED_MESSAGE = "<col=ef1020>Your magical charge fades away.</col>";
|
||||||
private static final String CHARGE_MESSAGE = "<col=ef1020>You feel charged with magic power.</col>";
|
private static final String CHARGE_MESSAGE = "<col=ef1020>You feel charged with magic power.</col>";
|
||||||
private static final String EXTENDED_ANTIFIRE_DRINK_MESSAGE = "You drink some of your extended antifire potion.";
|
private static final String EXTENDED_ANTIFIRE_DRINK_MESSAGE = "You drink some of your extended antifire potion.";
|
||||||
@@ -517,7 +518,7 @@ public class TimersPlugin extends Plugin
|
|||||||
cannonTimer.setTooltip(cannonTimer.getTooltip() + " - World " + client.getWorld());
|
cannonTimer.setTooltip(cannonTimer.getTooltip() + " - World " + client.getWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.showCannon() && message.equals(CANNON_PICKUP_MESSAGE))
|
if (config.showCannon() && (message.equals(CANNON_PICKUP_MESSAGE) || message.equals(CANNON_DESTROYED_MESSAGE)))
|
||||||
{
|
{
|
||||||
removeGameTimer(CANNON);
|
removeGameTimer(CANNON);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public abstract class TabContentPanel extends JPanel
|
|||||||
LocalDateTime currentTime = LocalDateTime.now();
|
LocalDateTime currentTime = LocalDateTime.now();
|
||||||
if (endTime.getDayOfWeek() != currentTime.getDayOfWeek())
|
if (endTime.getDayOfWeek() != currentTime.getDayOfWeek())
|
||||||
{
|
{
|
||||||
sb.append(endTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())).append(" ");
|
sb.append(endTime.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.getDefault())).append(" ");
|
||||||
}
|
}
|
||||||
sb.append("at ");
|
sb.append("at ");
|
||||||
sb.append(formatter.format(endTime));
|
sb.append(formatter.format(endTime));
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public interface TimeTrackingConfig extends Config
|
|||||||
String TIMERS = "timers";
|
String TIMERS = "timers";
|
||||||
String STOPWATCHES = "stopwatches";
|
String STOPWATCHES = "stopwatches";
|
||||||
String PREFER_SOONEST = "preferSoonest";
|
String PREFER_SOONEST = "preferSoonest";
|
||||||
|
String NOTIFY = "notify";
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "timeFormatMode",
|
keyName = "timeFormatMode",
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import com.google.inject.Inject;
|
|||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -58,7 +57,6 @@ import net.runelite.client.plugins.timetracking.clocks.ClockManager;
|
|||||||
import net.runelite.client.plugins.timetracking.farming.FarmingContractManager;
|
import net.runelite.client.plugins.timetracking.farming.FarmingContractManager;
|
||||||
import net.runelite.client.plugins.timetracking.farming.FarmingTracker;
|
import net.runelite.client.plugins.timetracking.farming.FarmingTracker;
|
||||||
import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker;
|
import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker;
|
||||||
import net.runelite.client.task.Schedule;
|
|
||||||
import net.runelite.client.ui.ClientToolbar;
|
import net.runelite.client.ui.ClientToolbar;
|
||||||
import net.runelite.client.ui.NavigationButton;
|
import net.runelite.client.ui.NavigationButton;
|
||||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||||
@@ -102,6 +100,8 @@ public class TimeTrackingPlugin extends Plugin
|
|||||||
|
|
||||||
private ScheduledFuture panelUpdateFuture;
|
private ScheduledFuture panelUpdateFuture;
|
||||||
|
|
||||||
|
private ScheduledFuture notifierFuture;
|
||||||
|
|
||||||
private TimeTrackingPanel panel;
|
private TimeTrackingPanel panel;
|
||||||
|
|
||||||
private NavigationButton navButton;
|
private NavigationButton navButton;
|
||||||
@@ -139,6 +139,7 @@ public class TimeTrackingPlugin extends Plugin
|
|||||||
clientToolbar.addNavigation(navButton);
|
clientToolbar.addNavigation(navButton);
|
||||||
|
|
||||||
panelUpdateFuture = executorService.scheduleAtFixedRate(this::updatePanel, 200, 200, TimeUnit.MILLISECONDS);
|
panelUpdateFuture = executorService.scheduleAtFixedRate(this::updatePanel, 200, 200, TimeUnit.MILLISECONDS);
|
||||||
|
notifierFuture = executorService.scheduleAtFixedRate(this::checkCompletion, 10, 10, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -153,6 +154,7 @@ public class TimeTrackingPlugin extends Plugin
|
|||||||
panelUpdateFuture = null;
|
panelUpdateFuture = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notifierFuture.cancel(true);
|
||||||
clientToolbar.removeNavigation(navButton);
|
clientToolbar.removeNavigation(navButton);
|
||||||
infoBoxManager.removeInfoBox(farmingContractManager.getInfoBox());
|
infoBoxManager.removeInfoBox(farmingContractManager.getInfoBox());
|
||||||
farmingContractManager.setInfoBox(null);
|
farmingContractManager.setInfoBox(null);
|
||||||
@@ -260,8 +262,7 @@ public class TimeTrackingPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schedule(period = 10, unit = ChronoUnit.SECONDS)
|
private void checkCompletion()
|
||||||
public void checkCompletion()
|
|
||||||
{
|
{
|
||||||
boolean birdHouseDataChanged = birdHouseTracker.checkCompletion();
|
boolean birdHouseDataChanged = birdHouseTracker.checkCompletion();
|
||||||
|
|
||||||
@@ -269,6 +270,8 @@ public class TimeTrackingPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
panel.update();
|
panel.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
farmingTracker.checkCompletion();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePanel()
|
private void updatePanel()
|
||||||
|
|||||||
@@ -29,22 +29,29 @@ import java.awt.BorderLayout;
|
|||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.GridLayout;
|
import java.awt.GridLayout;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JToggleButton;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.Constants;
|
import net.runelite.api.Constants;
|
||||||
import net.runelite.client.ui.ColorScheme;
|
import net.runelite.client.ui.ColorScheme;
|
||||||
import net.runelite.client.ui.FontManager;
|
import net.runelite.client.ui.FontManager;
|
||||||
import net.runelite.client.ui.components.ThinProgressBar;
|
import net.runelite.client.ui.components.ThinProgressBar;
|
||||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||||
|
import net.runelite.client.util.ImageUtil;
|
||||||
|
import net.runelite.client.util.SwingUtil;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Getter
|
@Getter
|
||||||
public class TimeablePanel<T> extends JPanel
|
public class TimeablePanel<T> extends JPanel
|
||||||
{
|
{
|
||||||
private final T timeable;
|
private final T timeable;
|
||||||
private final JLabel icon = new JLabel();
|
private final JLabel icon = new JLabel();
|
||||||
private final JLabel farmingContractIcon = new JLabel();
|
private final JLabel farmingContractIcon = new JLabel();
|
||||||
|
private final JToggleButton notifyButton = new JToggleButton();
|
||||||
private final JLabel estimate = new JLabel();
|
private final JLabel estimate = new JLabel();
|
||||||
private final ThinProgressBar progress = new ThinProgressBar();
|
private final ThinProgressBar progress = new ThinProgressBar();
|
||||||
private final JLabel text;
|
private final JLabel text;
|
||||||
@@ -79,8 +86,29 @@ public class TimeablePanel<T> extends JPanel
|
|||||||
infoPanel.add(text);
|
infoPanel.add(text);
|
||||||
infoPanel.add(estimate);
|
infoPanel.add(estimate);
|
||||||
|
|
||||||
|
ImageIcon notifyIcon = new ImageIcon(ImageUtil.loadImageResource(TimeTrackingPlugin.class, "notify_icon.png"));
|
||||||
|
ImageIcon notifySelectedIcon = new ImageIcon(ImageUtil.loadImageResource(TimeTrackingPlugin.class, "notify_selected_icon.png"));
|
||||||
|
|
||||||
|
notifyButton.setPreferredSize(new Dimension(30, 16));
|
||||||
|
notifyButton.setBorder(new EmptyBorder(0, 0, 0, 10));
|
||||||
|
notifyButton.setIcon(notifyIcon);
|
||||||
|
notifyButton.setSelectedIcon(notifySelectedIcon);
|
||||||
|
SwingUtil.removeButtonDecorations(notifyButton);
|
||||||
|
SwingUtil.addModalTooltip(notifyButton, "Disable notifications", "Enable notifications");
|
||||||
|
|
||||||
|
JPanel notifyPanel = new JPanel();
|
||||||
|
notifyPanel.setLayout(new BorderLayout());
|
||||||
|
notifyPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
notifyPanel.add(notifyButton, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JPanel iconPanel = new JPanel();
|
||||||
|
iconPanel.setLayout(new BorderLayout());
|
||||||
|
iconPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
iconPanel.add(notifyPanel, BorderLayout.EAST);
|
||||||
|
iconPanel.add(farmingContractIcon, BorderLayout.WEST);
|
||||||
|
|
||||||
|
topContainer.add(iconPanel, BorderLayout.EAST);
|
||||||
topContainer.add(icon, BorderLayout.WEST);
|
topContainer.add(icon, BorderLayout.WEST);
|
||||||
topContainer.add(farmingContractIcon, BorderLayout.EAST);
|
|
||||||
topContainer.add(infoPanel, BorderLayout.CENTER);
|
topContainer.add(infoPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
progress.setValue(0);
|
progress.setValue(0);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import lombok.Getter;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.runelite.api.Varbits;
|
import net.runelite.api.Varbits;
|
||||||
|
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||||
|
|
||||||
@RequiredArgsConstructor(
|
@RequiredArgsConstructor(
|
||||||
access = AccessLevel.PACKAGE
|
access = AccessLevel.PACKAGE
|
||||||
@@ -41,4 +42,14 @@ class FarmingPatch
|
|||||||
private final String name;
|
private final String name;
|
||||||
private final Varbits varbit;
|
private final Varbits varbit;
|
||||||
private final PatchImplementation implementation;
|
private final PatchImplementation implementation;
|
||||||
}
|
|
||||||
|
String configKey()
|
||||||
|
{
|
||||||
|
return region.getRegionID() + "." + varbit.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
String notifyConfigKey()
|
||||||
|
{
|
||||||
|
return TimeTrackingConfig.NOTIFY + "." + region.getRegionID() + "." + varbit.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,13 +33,15 @@ public class FarmingRegion
|
|||||||
{
|
{
|
||||||
private final String name;
|
private final String name;
|
||||||
private final int regionID;
|
private final int regionID;
|
||||||
|
private final boolean definite;
|
||||||
private final FarmingPatch[] patches;
|
private final FarmingPatch[] patches;
|
||||||
private final Varbits[] varbits;
|
private final Varbits[] varbits;
|
||||||
|
|
||||||
FarmingRegion(String name, int regionID, FarmingPatch... patches)
|
FarmingRegion(String name, int regionID, boolean definite, FarmingPatch... patches)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.regionID = regionID;
|
this.regionID = regionID;
|
||||||
|
this.definite = definite;
|
||||||
this.patches = patches;
|
this.patches = patches;
|
||||||
this.varbits = new Varbits[patches.length];
|
this.varbits = new Varbits[patches.length];
|
||||||
for (int i = 0; i < patches.length; i++)
|
for (int i = 0; i < patches.length; i++)
|
||||||
|
|||||||
@@ -33,8 +33,11 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JToggleButton;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.ItemID;
|
import net.runelite.api.ItemID;
|
||||||
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
import net.runelite.client.plugins.timetracking.TabContentPanel;
|
import net.runelite.client.plugins.timetracking.TabContentPanel;
|
||||||
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||||
@@ -42,10 +45,12 @@ import net.runelite.client.plugins.timetracking.TimeablePanel;
|
|||||||
import net.runelite.client.ui.ColorScheme;
|
import net.runelite.client.ui.ColorScheme;
|
||||||
import net.runelite.client.ui.FontManager;
|
import net.runelite.client.ui.FontManager;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class FarmingTabPanel extends TabContentPanel
|
public class FarmingTabPanel extends TabContentPanel
|
||||||
{
|
{
|
||||||
private final FarmingTracker farmingTracker;
|
private final FarmingTracker farmingTracker;
|
||||||
private final ItemManager itemManager;
|
private final ItemManager itemManager;
|
||||||
|
private final ConfigManager configManager;
|
||||||
private final TimeTrackingConfig config;
|
private final TimeTrackingConfig config;
|
||||||
private final List<TimeablePanel<FarmingPatch>> patchPanels;
|
private final List<TimeablePanel<FarmingPatch>> patchPanels;
|
||||||
private final FarmingContractManager farmingContractManager;
|
private final FarmingContractManager farmingContractManager;
|
||||||
@@ -53,6 +58,7 @@ public class FarmingTabPanel extends TabContentPanel
|
|||||||
FarmingTabPanel(
|
FarmingTabPanel(
|
||||||
FarmingTracker farmingTracker,
|
FarmingTracker farmingTracker,
|
||||||
ItemManager itemManager,
|
ItemManager itemManager,
|
||||||
|
ConfigManager configManager,
|
||||||
TimeTrackingConfig config,
|
TimeTrackingConfig config,
|
||||||
Set<FarmingPatch> patches,
|
Set<FarmingPatch> patches,
|
||||||
FarmingContractManager farmingContractManager
|
FarmingContractManager farmingContractManager
|
||||||
@@ -60,6 +66,7 @@ public class FarmingTabPanel extends TabContentPanel
|
|||||||
{
|
{
|
||||||
this.farmingTracker = farmingTracker;
|
this.farmingTracker = farmingTracker;
|
||||||
this.itemManager = itemManager;
|
this.itemManager = itemManager;
|
||||||
|
this.configManager = configManager;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.patchPanels = new ArrayList<>();
|
this.patchPanels = new ArrayList<>();
|
||||||
this.farmingContractManager = farmingContractManager;
|
this.farmingContractManager = farmingContractManager;
|
||||||
@@ -103,6 +110,18 @@ public class FarmingTabPanel extends TabContentPanel
|
|||||||
lastImpl = patch.getImplementation();
|
lastImpl = patch.getImplementation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set toggle state of notification menu on icon click;
|
||||||
|
JToggleButton toggleNotify = p.getNotifyButton();
|
||||||
|
String configKey = patch.notifyConfigKey();
|
||||||
|
|
||||||
|
toggleNotify.addActionListener(e ->
|
||||||
|
{
|
||||||
|
if (configManager.getRSProfileKey() != null)
|
||||||
|
{
|
||||||
|
configManager.setRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, configKey, toggleNotify.isSelected());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
patchPanels.add(p);
|
patchPanels.add(p);
|
||||||
add(p, c);
|
add(p, c);
|
||||||
c.gridy++;
|
c.gridy++;
|
||||||
@@ -197,18 +216,26 @@ public class FarmingTabPanel extends TabContentPanel
|
|||||||
{
|
{
|
||||||
panel.getProgress().setVisible(false);
|
panel.getProgress().setVisible(false);
|
||||||
}
|
}
|
||||||
JLabel farmingContractIcon = panel.getFarmingContractIcon();
|
|
||||||
if (farmingContractManager.shouldHighlightFarmingTabPanel(patch))
|
|
||||||
{
|
|
||||||
itemManager.getImage(ItemID.SEED_PACK).addTo(farmingContractIcon);
|
|
||||||
farmingContractIcon.setToolTipText(farmingContractManager.getContract().getName());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
farmingContractIcon.setIcon(null);
|
|
||||||
farmingContractIcon.setToolTipText("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JLabel farmingContractIcon = panel.getFarmingContractIcon();
|
||||||
|
if (farmingContractManager.shouldHighlightFarmingTabPanel(patch))
|
||||||
|
{
|
||||||
|
itemManager.getImage(ItemID.SEED_PACK).addTo(farmingContractIcon);
|
||||||
|
farmingContractIcon.setToolTipText(farmingContractManager.getContract().getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
farmingContractIcon.setIcon(null);
|
||||||
|
farmingContractIcon.setToolTipText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
String configKey = patch.notifyConfigKey();
|
||||||
|
JToggleButton toggleNotify = panel.getNotifyButton();
|
||||||
|
boolean notifyEnabled = Boolean.TRUE
|
||||||
|
.equals(configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, configKey, Boolean.class));
|
||||||
|
|
||||||
|
toggleNotify.setSelected(notifyEnabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,25 +24,34 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.timetracking.farming;
|
package net.runelite.client.plugins.timetracking.farming;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.GameState;
|
||||||
import net.runelite.api.Varbits;
|
import net.runelite.api.Varbits;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import net.runelite.api.vars.Autoweed;
|
import net.runelite.api.vars.Autoweed;
|
||||||
import net.runelite.api.widgets.WidgetModalMode;
|
import net.runelite.api.widgets.WidgetModalMode;
|
||||||
|
import net.runelite.client.Notifier;
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
|
import net.runelite.client.config.RuneScapeProfile;
|
||||||
|
import net.runelite.client.config.RuneScapeProfileType;
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
import net.runelite.client.plugins.timetracking.SummaryState;
|
import net.runelite.client.plugins.timetracking.SummaryState;
|
||||||
import net.runelite.client.plugins.timetracking.Tab;
|
import net.runelite.client.plugins.timetracking.Tab;
|
||||||
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||||
|
import net.runelite.client.util.Text;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -53,6 +62,7 @@ public class FarmingTracker
|
|||||||
private final ConfigManager configManager;
|
private final ConfigManager configManager;
|
||||||
private final TimeTrackingConfig config;
|
private final TimeTrackingConfig config;
|
||||||
private final FarmingWorld farmingWorld;
|
private final FarmingWorld farmingWorld;
|
||||||
|
private final Notifier notifier;
|
||||||
|
|
||||||
private final Map<Tab, SummaryState> summaries = new EnumMap<>(Tab.class);
|
private final Map<Tab, SummaryState> summaries = new EnumMap<>(Tab.class);
|
||||||
|
|
||||||
@@ -61,23 +71,26 @@ public class FarmingTracker
|
|||||||
* or {@code -1} if we have no data about any patch of the given type.
|
* or {@code -1} if we have no data about any patch of the given type.
|
||||||
*/
|
*/
|
||||||
private final Map<Tab, Long> completionTimes = new EnumMap<>(Tab.class);
|
private final Map<Tab, Long> completionTimes = new EnumMap<>(Tab.class);
|
||||||
|
Map<ProfilePatch, Boolean> wasNotified = new HashMap<>();
|
||||||
|
|
||||||
private boolean newRegionLoaded;
|
private boolean newRegionLoaded;
|
||||||
private Collection<FarmingRegion> lastRegions;
|
private Collection<FarmingRegion> lastRegions;
|
||||||
|
private boolean firstNotifyCheck = true;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private FarmingTracker(Client client, ItemManager itemManager, ConfigManager configManager, TimeTrackingConfig config, FarmingWorld farmingWorld)
|
private FarmingTracker(Client client, ItemManager itemManager, ConfigManager configManager, TimeTrackingConfig config, FarmingWorld farmingWorld, Notifier notifier)
|
||||||
{
|
{
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.itemManager = itemManager;
|
this.itemManager = itemManager;
|
||||||
this.configManager = configManager;
|
this.configManager = configManager;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.farmingWorld = farmingWorld;
|
this.farmingWorld = farmingWorld;
|
||||||
|
this.notifier = notifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FarmingTabPanel createTabPanel(Tab tab, FarmingContractManager farmingContractManager)
|
public FarmingTabPanel createTabPanel(Tab tab, FarmingContractManager farmingContractManager)
|
||||||
{
|
{
|
||||||
return new FarmingTabPanel(this, itemManager, config, farmingWorld.getTabs().get(tab), farmingContractManager);
|
return new FarmingTabPanel(this, itemManager, configManager, config, farmingWorld.getTabs().get(tab), farmingContractManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,7 +143,7 @@ public class FarmingTracker
|
|||||||
{
|
{
|
||||||
// Write the config value if it doesn't match what is current, or it is more than 5 minutes old
|
// Write the config value if it doesn't match what is current, or it is more than 5 minutes old
|
||||||
Varbits varbit = patch.getVarbit();
|
Varbits varbit = patch.getVarbit();
|
||||||
String key = region.getRegionID() + "." + varbit.getId();
|
String key = patch.configKey();
|
||||||
String strVarbit = Integer.toString(client.getVar(varbit));
|
String strVarbit = Integer.toString(client.getVar(varbit));
|
||||||
String storedValue = configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, key);
|
String storedValue = configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, key);
|
||||||
|
|
||||||
@@ -189,6 +202,12 @@ public class FarmingTracker
|
|||||||
configManager.setRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.FARM_TICK_OFFSET, offsetMins);
|
configManager.setRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.FARM_TICK_OFFSET, offsetMins);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (currentPatchState.getTickRate() != 0
|
||||||
|
// Don't set wasNotified to false if witnessing a check-health action
|
||||||
|
&& !(previousPatchState.getCropState() == CropState.GROWING && currentPatchState.getCropState() == CropState.HARVESTABLE && currentPatchState.getProduce().getPatchImplementation().isHealthCheckRequired()))
|
||||||
|
{
|
||||||
|
wasNotified.put(new ProfilePatch(patch, configManager.getRSProfileKey()), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -258,17 +277,23 @@ public class FarmingTracker
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public PatchPrediction predictPatch(FarmingPatch patch)
|
public PatchPrediction predictPatch(FarmingPatch patch)
|
||||||
|
{
|
||||||
|
return predictPatch(patch, configManager.getRSProfileKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public PatchPrediction predictPatch(FarmingPatch patch, String profile)
|
||||||
{
|
{
|
||||||
long unixNow = Instant.now().getEpochSecond();
|
long unixNow = Instant.now().getEpochSecond();
|
||||||
|
|
||||||
boolean autoweed = Integer.toString(Autoweed.ON.ordinal())
|
boolean autoweed = Integer.toString(Autoweed.ON.ordinal())
|
||||||
.equals(configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.AUTOWEED));
|
.equals(configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile, TimeTrackingConfig.AUTOWEED));
|
||||||
|
|
||||||
boolean botanist = Boolean.TRUE
|
boolean botanist = Boolean.TRUE
|
||||||
.equals(configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.BOTANIST, Boolean.class));
|
.equals(configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile, TimeTrackingConfig.BOTANIST, Boolean.class));
|
||||||
|
|
||||||
String key = patch.getRegion().getRegionID() + "." + patch.getVarbit().getId();
|
String key = patch.configKey();
|
||||||
String storedValue = configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, key);
|
String storedValue = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile, key);
|
||||||
|
|
||||||
if (storedValue == null)
|
if (storedValue == null)
|
||||||
{
|
{
|
||||||
@@ -323,11 +348,11 @@ public class FarmingTracker
|
|||||||
long doneEstimate = 0;
|
long doneEstimate = 0;
|
||||||
if (tickrate > 0)
|
if (tickrate > 0)
|
||||||
{
|
{
|
||||||
long tickNow = getTickTime(tickrate, 0, unixNow);
|
long tickNow = getTickTime(tickrate, 0, unixNow, profile);
|
||||||
long tickTime = getTickTime(tickrate, 0, unixTime);
|
long tickTime = getTickTime(tickrate, 0, unixTime, profile);
|
||||||
int delta = (int) (tickNow - tickTime) / (tickrate * 60);
|
int delta = (int) (tickNow - tickTime) / (tickrate * 60);
|
||||||
|
|
||||||
doneEstimate = getTickTime(tickrate, stages - 1 - stage, tickTime);
|
doneEstimate = getTickTime(tickrate, stages - 1 - stage, tickTime, profile);
|
||||||
|
|
||||||
stage += delta;
|
stage += delta;
|
||||||
if (stage >= stages)
|
if (stage >= stages)
|
||||||
@@ -347,13 +372,13 @@ public class FarmingTracker
|
|||||||
|
|
||||||
public long getTickTime(int tickRate, int ticks)
|
public long getTickTime(int tickRate, int ticks)
|
||||||
{
|
{
|
||||||
return getTickTime(tickRate, ticks, Instant.now().getEpochSecond());
|
return getTickTime(tickRate, ticks, Instant.now().getEpochSecond(), configManager.getRSProfileKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTickTime(int tickRate, int ticks, long requestedTime)
|
public long getTickTime(int tickRate, int ticks, long requestedTime, String profile)
|
||||||
{
|
{
|
||||||
Integer offsetPrecisionMins = configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.FARM_TICK_OFFSET_PRECISION, int.class);
|
Integer offsetPrecisionMins = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile, TimeTrackingConfig.FARM_TICK_OFFSET_PRECISION, int.class);
|
||||||
Integer offsetTimeMins = configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.FARM_TICK_OFFSET, int.class);
|
Integer offsetTimeMins = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile, TimeTrackingConfig.FARM_TICK_OFFSET, int.class);
|
||||||
|
|
||||||
//All offsets are negative but are stored as positive
|
//All offsets are negative but are stored as positive
|
||||||
long calculatedOffsetTime = 0L;
|
long calculatedOffsetTime = 0L;
|
||||||
@@ -465,4 +490,133 @@ public class FarmingTracker
|
|||||||
completionTimes.put(tab.getKey(), completionTime);
|
completionTimes.put(tab.getKey(), completionTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkCompletion()
|
||||||
|
{
|
||||||
|
List<RuneScapeProfile> rsProfiles = configManager.getRSProfiles();
|
||||||
|
long unixNow = Instant.now().getEpochSecond();
|
||||||
|
|
||||||
|
for (RuneScapeProfile profile : rsProfiles)
|
||||||
|
{
|
||||||
|
Integer offsetPrecisionMins = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile.getKey(), TimeTrackingConfig.FARM_TICK_OFFSET_PRECISION, int.class);
|
||||||
|
Integer offsetTimeMins = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile.getKey(), TimeTrackingConfig.FARM_TICK_OFFSET, int.class);
|
||||||
|
|
||||||
|
for (Map.Entry<Tab, Set<FarmingPatch>> tab : farmingWorld.getTabs().entrySet())
|
||||||
|
{
|
||||||
|
for (FarmingPatch patch : tab.getValue())
|
||||||
|
{
|
||||||
|
ProfilePatch profilePatch = new ProfilePatch(patch, profile.getKey());
|
||||||
|
boolean patchNotified = wasNotified.getOrDefault(profilePatch, false);
|
||||||
|
String configKey = patch.notifyConfigKey();
|
||||||
|
boolean shouldNotify = Boolean.TRUE
|
||||||
|
.equals(configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile.getKey(), configKey, Boolean.class));
|
||||||
|
PatchPrediction prediction = predictPatch(patch, profile.getKey());
|
||||||
|
|
||||||
|
if (prediction == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tickRate = prediction.getProduce().getTickrate();
|
||||||
|
|
||||||
|
if (offsetPrecisionMins == null || offsetTimeMins == null || (offsetPrecisionMins < tickRate && offsetPrecisionMins < 40) || prediction.getProduce() == Produce.WEEDS
|
||||||
|
|| unixNow <= prediction.getDoneEstimate() || patchNotified || prediction.getCropState() == CropState.FILLING || prediction.getCropState() == CropState.EMPTY)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasNotified.put(profilePatch, true);
|
||||||
|
|
||||||
|
if (!firstNotifyCheck && shouldNotify)
|
||||||
|
{
|
||||||
|
sendNotification(profile, prediction, patch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
firstNotifyCheck = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void sendNotification(RuneScapeProfile profile, PatchPrediction prediction, FarmingPatch patch)
|
||||||
|
{
|
||||||
|
final RuneScapeProfileType profileType = profile.getType();
|
||||||
|
|
||||||
|
final StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
// Same RS account
|
||||||
|
if (client.getGameState() == GameState.LOGGED_IN && profile.getDisplayName().equals(client.getLocalPlayer().getName()))
|
||||||
|
{
|
||||||
|
// Same RS account but different profile type
|
||||||
|
if (profileType != RuneScapeProfileType.getCurrent(client))
|
||||||
|
{
|
||||||
|
stringBuilder.append("(")
|
||||||
|
.append(Text.titleCase(profile.getType()))
|
||||||
|
.append(") ");
|
||||||
|
}
|
||||||
|
// Same RS account AND profile falls through here so no bracketed prefix is added
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Different RS account AND profile type
|
||||||
|
if (profileType != RuneScapeProfileType.getCurrent(client) || client.getGameState() == GameState.LOGIN_SCREEN)
|
||||||
|
{
|
||||||
|
//Don't print profile type when logged out if is STANDARD
|
||||||
|
if (client.getGameState() == GameState.LOGIN_SCREEN && profileType == RuneScapeProfileType.STANDARD)
|
||||||
|
{
|
||||||
|
stringBuilder.append("(")
|
||||||
|
.append(profile.getDisplayName())
|
||||||
|
.append(") ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stringBuilder.append("(")
|
||||||
|
.append(profile.getDisplayName())
|
||||||
|
.append(" - ")
|
||||||
|
.append(Text.titleCase(profile.getType()))
|
||||||
|
.append(") ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Different RS account but same profile type
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stringBuilder.append("(")
|
||||||
|
.append(profile.getDisplayName())
|
||||||
|
.append(") ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stringBuilder
|
||||||
|
.append("Your ")
|
||||||
|
.append(prediction.getProduce().getName());
|
||||||
|
|
||||||
|
switch (prediction.getCropState())
|
||||||
|
{
|
||||||
|
case HARVESTABLE:
|
||||||
|
case GROWING:
|
||||||
|
if (prediction.getProduce().getName().toLowerCase(Locale.ENGLISH).contains("compost"))
|
||||||
|
{
|
||||||
|
stringBuilder.append(" is ready to collect in ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stringBuilder.append(" is ready to harvest in ");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DISEASED:
|
||||||
|
stringBuilder.append(" has become diseased in ");
|
||||||
|
break;
|
||||||
|
case DEAD:
|
||||||
|
stringBuilder.append(" has died in ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// EMPTY and FILLING are caught above
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
stringBuilder.append(patch.getRegion().isDefinite() ? "the " : "")
|
||||||
|
.append(patch.getRegion().getName())
|
||||||
|
.append(".");
|
||||||
|
|
||||||
|
notifier.notify(stringBuilder.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,14 +64,14 @@ class FarmingWorld
|
|||||||
{
|
{
|
||||||
// Some of these patches get updated in multiple regions.
|
// Some of these patches get updated in multiple regions.
|
||||||
// It may be worth it to add a specialization for these patches
|
// It may be worth it to add a specialization for these patches
|
||||||
add(new FarmingRegion("Al Kharid", 13106,
|
add(new FarmingRegion("Al Kharid", 13106, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.CACTUS)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.CACTUS)
|
||||||
), 13362, 13105);
|
), 13362, 13105);
|
||||||
|
|
||||||
add(new FarmingRegion("Ardougne", 10290,
|
add(new FarmingRegion("Ardougne", 10290, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||||
), 10546);
|
), 10546);
|
||||||
add(new FarmingRegion("Ardougne", 10548,
|
add(new FarmingRegion("Ardougne", 10548, false,
|
||||||
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||||
@@ -79,12 +79,12 @@ class FarmingWorld
|
|||||||
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST)
|
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Brimhaven", 11058,
|
add(new FarmingRegion("Brimhaven", 11058, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE),
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE),
|
||||||
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
|
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
|
||||||
), 11057);
|
), 11057);
|
||||||
|
|
||||||
add(new FarmingRegion("Catherby", 11062,
|
add(new FarmingRegion("Catherby", 11062, false,
|
||||||
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||||
@@ -103,7 +103,7 @@ class FarmingWorld
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}, 11061, 11318, 11317);
|
}, 11061, 11318, 11317);
|
||||||
add(new FarmingRegion("Catherby", 11317,
|
add(new FarmingRegion("Catherby", 11317, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -115,27 +115,27 @@ class FarmingWorld
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
add(new FarmingRegion("Champions' Guild", 12596,
|
add(new FarmingRegion("Champions' Guild", 12596, true,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Draynor Manor", 12340,
|
add(new FarmingRegion("Draynor Manor", 12340, false,
|
||||||
new FarmingPatch("Belladonna", Varbits.FARMING_4771, PatchImplementation.BELLADONNA)
|
new FarmingPatch("Belladonna", Varbits.FARMING_4771, PatchImplementation.BELLADONNA)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Entrana", 11060,
|
add(new FarmingRegion("Entrana", 11060, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||||
), 11316);
|
), 11316);
|
||||||
|
|
||||||
add(new FarmingRegion("Etceteria", 10300,
|
add(new FarmingRegion("Etceteria", 10300, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH),
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH),
|
||||||
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
|
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Falador", 11828,
|
add(new FarmingRegion("Falador", 11828, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
||||||
), 12084);
|
), 12084);
|
||||||
add(new FarmingRegion("Falador", 12083,
|
add(new FarmingRegion("Falador", 12083, false,
|
||||||
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||||
@@ -151,7 +151,7 @@ class FarmingWorld
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
add(new FarmingRegion("Fossil Island", 14651,
|
add(new FarmingRegion("Fossil Island", 14651, false,
|
||||||
new FarmingPatch("East", Varbits.FARMING_4771, PatchImplementation.HARDWOOD_TREE),
|
new FarmingPatch("East", Varbits.FARMING_4771, PatchImplementation.HARDWOOD_TREE),
|
||||||
new FarmingPatch("Middle", Varbits.FARMING_4772, PatchImplementation.HARDWOOD_TREE),
|
new FarmingPatch("Middle", Varbits.FARMING_4772, PatchImplementation.HARDWOOD_TREE),
|
||||||
new FarmingPatch("West", Varbits.FARMING_4773, PatchImplementation.HARDWOOD_TREE)
|
new FarmingPatch("West", Varbits.FARMING_4773, PatchImplementation.HARDWOOD_TREE)
|
||||||
@@ -179,22 +179,22 @@ class FarmingWorld
|
|||||||
return loc.getPlane() == 0;
|
return loc.getPlane() == 0;
|
||||||
}
|
}
|
||||||
}, 14907, 14908, 15164, 14652, 14906, 14650, 15162, 15163);
|
}, 14907, 14908, 15164, 14652, 14906, 14650, 15162, 15163);
|
||||||
add(new FarmingRegion("Seaweed", 15008,
|
add(new FarmingRegion("Seaweed", 15008, false,
|
||||||
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.SEAWEED),
|
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.SEAWEED),
|
||||||
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.SEAWEED)
|
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.SEAWEED)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Gnome Stronghold", 9781,
|
add(new FarmingRegion("Gnome Stronghold", 9781, true,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE),
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE),
|
||||||
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.FRUIT_TREE)
|
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.FRUIT_TREE)
|
||||||
), 9782, 9526, 9525);
|
), 9782, 9526, 9525);
|
||||||
|
|
||||||
add(new FarmingRegion("Harmony", 15148,
|
add(new FarmingRegion("Harmony", 15148, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.HERB)
|
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.HERB)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Kourend", 6967,
|
add(new FarmingRegion("Kourend", 6967, false,
|
||||||
new FarmingPatch("North East", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("North East", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("South West", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("South West", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||||
@@ -202,7 +202,7 @@ class FarmingWorld
|
|||||||
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST),
|
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST),
|
||||||
new FarmingPatch("", Varbits.FARMING_7904, PatchImplementation.SPIRIT_TREE)
|
new FarmingPatch("", Varbits.FARMING_7904, PatchImplementation.SPIRIT_TREE)
|
||||||
), 6711);
|
), 6711);
|
||||||
add(new FarmingRegion("Kourend", 7223,
|
add(new FarmingRegion("Kourend", 7223, false,
|
||||||
new FarmingPatch("East 1", Varbits.GRAPES_4953, PatchImplementation.GRAPES),
|
new FarmingPatch("East 1", Varbits.GRAPES_4953, PatchImplementation.GRAPES),
|
||||||
new FarmingPatch("East 2", Varbits.GRAPES_4954, PatchImplementation.GRAPES),
|
new FarmingPatch("East 2", Varbits.GRAPES_4954, PatchImplementation.GRAPES),
|
||||||
new FarmingPatch("East 3", Varbits.GRAPES_4955, PatchImplementation.GRAPES),
|
new FarmingPatch("East 3", Varbits.GRAPES_4955, PatchImplementation.GRAPES),
|
||||||
@@ -217,21 +217,21 @@ class FarmingWorld
|
|||||||
new FarmingPatch("West 6", Varbits.GRAPES_4964, PatchImplementation.GRAPES)
|
new FarmingPatch("West 6", Varbits.GRAPES_4964, PatchImplementation.GRAPES)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Lletya", 9265,
|
add(new FarmingRegion("Lletya", 9265, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
|
||||||
), 11103);
|
), 11103);
|
||||||
|
|
||||||
add(new FarmingRegion("Lumbridge", 12851,
|
add(new FarmingRegion("Lumbridge", 12851, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||||
));
|
));
|
||||||
add(new FarmingRegion("Lumbridge", 12594,
|
add(new FarmingRegion("Lumbridge", 12594, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
||||||
), 12850);
|
), 12850);
|
||||||
|
|
||||||
add(new FarmingRegion("Morytania", 13622,
|
add(new FarmingRegion("Morytania", 13622, false,
|
||||||
new FarmingPatch("Mushroom", Varbits.FARMING_4771, PatchImplementation.MUSHROOM)
|
new FarmingPatch("Mushroom", Varbits.FARMING_4771, PatchImplementation.MUSHROOM)
|
||||||
), 13878);
|
), 13878);
|
||||||
add(new FarmingRegion("Morytania", 14391,
|
add(new FarmingRegion("Morytania", 14391, false,
|
||||||
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||||
@@ -239,7 +239,7 @@ class FarmingWorld
|
|||||||
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST)
|
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST)
|
||||||
), 14390);
|
), 14390);
|
||||||
|
|
||||||
add(new FarmingRegion("Port Sarim", 12082,
|
add(new FarmingRegion("Port Sarim", 12082, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -250,48 +250,48 @@ class FarmingWorld
|
|||||||
}
|
}
|
||||||
}, 12083);
|
}, 12083);
|
||||||
|
|
||||||
add(new FarmingRegion("Rimmington", 11570,
|
add(new FarmingRegion("Rimmington", 11570, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||||
), 11826);
|
), 11826);
|
||||||
|
|
||||||
add(new FarmingRegion("Seers' Village", 10551,
|
add(new FarmingRegion("Seers' Village", 10551, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||||
), 10550);
|
), 10550);
|
||||||
|
|
||||||
add(new FarmingRegion("Tai Bwo Wannai", 11056,
|
add(new FarmingRegion("Tai Bwo Wannai", 11056, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.CALQUAT)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.CALQUAT)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Taverley", 11573,
|
add(new FarmingRegion("Taverley", 11573, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
||||||
), 11829);
|
), 11829);
|
||||||
|
|
||||||
add(new FarmingRegion("Tree Gnome Village", 9777,
|
add(new FarmingRegion("Tree Gnome Village", 9777, true,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
|
||||||
), 10033);
|
), 10033);
|
||||||
|
|
||||||
add(new FarmingRegion("Troll Stronghold", 11321,
|
add(new FarmingRegion("Troll Stronghold", 11321, true,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HERB)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HERB)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Varrock", 12854,
|
add(new FarmingRegion("Varrock", 12854, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
||||||
), 12853);
|
), 12853);
|
||||||
|
|
||||||
add(new FarmingRegion("Yanille", 10288,
|
add(new FarmingRegion("Yanille", 10288, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Weiss", 11325,
|
add(new FarmingRegion("Weiss", 11325, false,
|
||||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HERB)
|
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HERB)
|
||||||
));
|
));
|
||||||
|
|
||||||
add(new FarmingRegion("Farming Guild", 5021,
|
add(new FarmingRegion("Farming Guild", 5021, true,
|
||||||
new FarmingPatch("Hespori", Varbits.FARMING_7908, PatchImplementation.HESPORI)
|
new FarmingPatch("Hespori", Varbits.FARMING_7908, PatchImplementation.HESPORI)
|
||||||
));
|
));
|
||||||
|
|
||||||
//Full 3x3 region area centered on farming guild
|
//Full 3x3 region area centered on farming guild
|
||||||
add(farmingGuildRegion = new FarmingRegion("Farming Guild", 4922,
|
add(farmingGuildRegion = new FarmingRegion("Farming Guild", 4922, true,
|
||||||
new FarmingPatch("", Varbits.FARMING_7905, PatchImplementation.TREE),
|
new FarmingPatch("", Varbits.FARMING_7905, PatchImplementation.TREE),
|
||||||
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.HERB),
|
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.HERB),
|
||||||
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.BUSH),
|
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.BUSH),
|
||||||
@@ -308,7 +308,7 @@ class FarmingWorld
|
|||||||
), 5177, 5178, 5179, 4921, 4923, 4665, 4666, 4667);
|
), 5177, 5178, 5179, 4921, 4923, 4665, 4666, 4667);
|
||||||
|
|
||||||
//All of Prifddinas, and all of Prifddinas Underground
|
//All of Prifddinas, and all of Prifddinas Underground
|
||||||
add(new FarmingRegion("Prifddinas", 13151,
|
add(new FarmingRegion("Prifddinas", 13151, false,
|
||||||
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Hannah Ryan <https://github.com/loldudester>
|
||||||
|
* 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.timetracking.farming;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
class ProfilePatch
|
||||||
|
{
|
||||||
|
FarmingPatch patch;
|
||||||
|
String rsProfileKey;
|
||||||
|
}
|
||||||
@@ -58,6 +58,7 @@ enum DungeonLocation
|
|||||||
CRABCLAW_CAVES_TUNNEL("Crabclaw Caves Tunnel (quest)", new WorldPoint(1671, 9800, 0)),
|
CRABCLAW_CAVES_TUNNEL("Crabclaw Caves Tunnel (quest)", new WorldPoint(1671, 9800, 0)),
|
||||||
CRANDOR("Crandor Dungeon", new WorldPoint(2833, 3256, 0)),
|
CRANDOR("Crandor Dungeon", new WorldPoint(2833, 3256, 0)),
|
||||||
CRASH_ISLAND("Crash Island Dungeon", new WorldPoint(2920, 2721, 0)),
|
CRASH_ISLAND("Crash Island Dungeon", new WorldPoint(2920, 2721, 0)),
|
||||||
|
CRUMBLING_TOWER("Crumbling Tower basement", new WorldPoint(2130, 2994, 0)),
|
||||||
DEEP_WILDERNESS("Deep Wilderness Dungeon", new WorldPoint(3044, 3924, 0)),
|
DEEP_WILDERNESS("Deep Wilderness Dungeon", new WorldPoint(3044, 3924, 0)),
|
||||||
DRAYNOR_MANOR_E("Draynor Manor basement", new WorldPoint(3114, 3357, 0)),
|
DRAYNOR_MANOR_E("Draynor Manor basement", new WorldPoint(3114, 3357, 0)),
|
||||||
DRAYNOR_MANOR_W("Draynor Manor basement", new WorldPoint(3091, 3362, 0)),
|
DRAYNOR_MANOR_W("Draynor Manor basement", new WorldPoint(3091, 3362, 0)),
|
||||||
@@ -89,6 +90,7 @@ enum DungeonLocation
|
|||||||
ICE_QUEEN_W("Ice Queen's Lair", new WorldPoint(2822, 3510, 0)),
|
ICE_QUEEN_W("Ice Queen's Lair", new WorldPoint(2822, 3510, 0)),
|
||||||
ICE_TROLL_E("Ice Troll Caves", new WorldPoint(2400, 3889, 0)),
|
ICE_TROLL_E("Ice Troll Caves", new WorldPoint(2400, 3889, 0)),
|
||||||
ICE_TROLL_W("Ice Troll Caves", new WorldPoint(2315, 3894, 0)),
|
ICE_TROLL_W("Ice Troll Caves", new WorldPoint(2315, 3894, 0)),
|
||||||
|
ISLE_OF_SOULS_DUNGEON("Isle of Souls Dungeon", new WorldPoint(2308, 2919, 0)),
|
||||||
IORWERTH("Iorwerth Dungeon", new WorldPoint(3224, 6044, 0)),
|
IORWERTH("Iorwerth Dungeon", new WorldPoint(3224, 6044, 0)),
|
||||||
IORWERTH_CAMP_CAVE("Iorwerth Camp cave", new WorldPoint(2200, 3262, 0)),
|
IORWERTH_CAMP_CAVE("Iorwerth Camp cave", new WorldPoint(2200, 3262, 0)),
|
||||||
IORWERTH_CAMP_CAVE_PRIF("Iorwerth Camp cave", new WorldPoint(3224, 6014, 0)),
|
IORWERTH_CAMP_CAVE_PRIF("Iorwerth Camp cave", new WorldPoint(3224, 6014, 0)),
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ enum FishingSpotLocation
|
|||||||
IORWERTH_CAMP_OUTSIDE(FishingSpot.SALMON, new WorldPoint(2215, 3245, 0)),
|
IORWERTH_CAMP_OUTSIDE(FishingSpot.SALMON, new WorldPoint(2215, 3245, 0)),
|
||||||
ISAFDAR_NORTH_EAST_INSIDE(FishingSpot.SALMON, new WorldPoint(3293, 6005, 0)),
|
ISAFDAR_NORTH_EAST_INSIDE(FishingSpot.SALMON, new WorldPoint(3293, 6005, 0)),
|
||||||
ISAFDAR_NORTH_EAST_OUTSIDE(FishingSpot.SALMON, new WorldPoint(2269, 3253, 0)),
|
ISAFDAR_NORTH_EAST_OUTSIDE(FishingSpot.SALMON, new WorldPoint(2269, 3253, 0)),
|
||||||
|
ISLE_OF_SOULS_EAST(FishingSpot.SHARK, new WorldPoint(2281, 2841, 0)),
|
||||||
|
ISLE_OF_SOULS_NORTH(FishingSpot.LOBSTER, new WorldPoint(2280, 2975, 0)),
|
||||||
|
ISLE_OF_SOULS_SOUTH_WEST(FishingSpot.SHRIMP, new WorldPoint(2162, 2782, 0)),
|
||||||
JATISZO(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER},
|
JATISZO(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER},
|
||||||
new WorldPoint(2400, 3780, 0), new WorldPoint(2412, 3780, 0),
|
new WorldPoint(2400, 3780, 0), new WorldPoint(2412, 3780, 0),
|
||||||
new WorldPoint(2419, 3789, 0)),
|
new WorldPoint(2419, 3789, 0)),
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ enum HunterAreaLocation
|
|||||||
FOSSIL_ISLAND_UNDERWATER(new WorldPoint(3743, 10295, 0), HunterCreature.FISH_SHOAL),
|
FOSSIL_ISLAND_UNDERWATER(new WorldPoint(3743, 10295, 0), HunterCreature.FISH_SHOAL),
|
||||||
GWENITH_HUNTER_AREA_OUTSIDE(new WorldPoint(2269, 3408, 0), HunterCreature.CARNIVOROUS_CHINCHOMPA),
|
GWENITH_HUNTER_AREA_OUTSIDE(new WorldPoint(2269, 3408, 0), HunterCreature.CARNIVOROUS_CHINCHOMPA),
|
||||||
GWENITH_HUNTER_AREA_INSIDE(new WorldPoint(3293, 6160, 0), HunterCreature.CARNIVOROUS_CHINCHOMPA),
|
GWENITH_HUNTER_AREA_INSIDE(new WorldPoint(3293, 6160, 0), HunterCreature.CARNIVOROUS_CHINCHOMPA),
|
||||||
|
ISLE_OF_SOULS_NORTH(new WorldPoint(2207, 2964, 0), HunterCreature.COPPER_LONGTAIL),
|
||||||
|
ISLE_OF_SOULS_NORTH_WEST(new WorldPoint(2127, 2950, 0), HunterCreature.CHINCHOMPA),
|
||||||
|
ISLE_OF_SOULS_SOUTH_WEST(new WorldPoint(2158, 2822, 0), HunterCreature.CRIMSON_SWIFT),
|
||||||
KARAMJA_HUNTER_AREA(new WorldPoint(2786, 3001, 0), HunterCreature.HORNED_GRAAHK),
|
KARAMJA_HUNTER_AREA(new WorldPoint(2786, 3001, 0), HunterCreature.HORNED_GRAAHK),
|
||||||
KEBOS_SWAMP(new WorldPoint(1184, 3595, 0), HunterCreature.CRIMSON_SWIFT),
|
KEBOS_SWAMP(new WorldPoint(1184, 3595, 0), HunterCreature.CRIMSON_SWIFT),
|
||||||
KOUREND_WOODLAND_CENTER(new WorldPoint(1512, 3478, 0), HunterCreature.RUBY_HARVEST),
|
KOUREND_WOODLAND_CENTER(new WorldPoint(1512, 3478, 0), HunterCreature.RUBY_HARVEST),
|
||||||
|
|||||||
@@ -117,6 +117,11 @@ enum MiningSiteLocation
|
|||||||
new Rock(10, Ore.CLAY), new Rock(11, Ore.COPPER), new Rock(4, Ore.TIN), new Rock(9, Ore.IRON),
|
new Rock(10, Ore.CLAY), new Rock(11, Ore.COPPER), new Rock(4, Ore.TIN), new Rock(9, Ore.IRON),
|
||||||
new Rock(2, Ore.SILVER)),
|
new Rock(2, Ore.SILVER)),
|
||||||
ISAFDAR(new WorldPoint(2277, 3159, 0), new Rock(4, Ore.ADAMANTITE), new Rock(2, Ore.RUNITE)),
|
ISAFDAR(new WorldPoint(2277, 3159, 0), new Rock(4, Ore.ADAMANTITE), new Rock(2, Ore.RUNITE)),
|
||||||
|
ISLE_OF_SOULS_DUNGEON_EAST(new WorldPoint(1831, 9109, 0), new Rock(1, Ore.RUNITE)),
|
||||||
|
ISLE_OF_SOULS_DUNGEON_WEST(new WorldPoint(1814, 9116, 0), new Rock(2, Ore.ADAMANTITE)),
|
||||||
|
ISLE_OF_SOULS_SOUTH(new WorldPoint(2195, 2793, 0),
|
||||||
|
new Rock(3, Ore.CLAY), new Rock(3, Ore.TIN), new Rock(3, Ore.COPPER), new Rock(10, Ore.IRON),
|
||||||
|
new Rock(3, Ore.SILVER), new Rock(6, Ore.COAL), new Rock(4, Ore.GOLD), new Rock(2, Ore.MITHRIL)),
|
||||||
JATIZSO(new WorldPoint(2396, 3812, 0),
|
JATIZSO(new WorldPoint(2396, 3812, 0),
|
||||||
new Rock(11, Ore.TIN), new Rock(7, Ore.IRON), new Rock(8, Ore.COAL), new Rock(15, Ore.MITHRIL),
|
new Rock(11, Ore.TIN), new Rock(7, Ore.IRON), new Rock(8, Ore.COAL), new Rock(15, Ore.MITHRIL),
|
||||||
new Rock(11, Ore.ADAMANTITE)),
|
new Rock(11, Ore.ADAMANTITE)),
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ enum RareTreeLocation
|
|||||||
new WorldPoint(2748, 3466, 0),
|
new WorldPoint(2748, 3466, 0),
|
||||||
new WorldPoint(2710, 3570, 0),
|
new WorldPoint(2710, 3570, 0),
|
||||||
|
|
||||||
|
// Isle of Souls
|
||||||
|
new WorldPoint(2254, 2808, 0),
|
||||||
|
|
||||||
// Prifddinas
|
// Prifddinas
|
||||||
new WorldPoint(2209, 3427, 0),
|
new WorldPoint(2209, 3427, 0),
|
||||||
new WorldPoint(3233, 6179, 0)),
|
new WorldPoint(3233, 6179, 0)),
|
||||||
@@ -111,6 +114,9 @@ enum RareTreeLocation
|
|||||||
// Mos Le'Harmless
|
// Mos Le'Harmless
|
||||||
new WorldPoint(3810, 3058, 0),
|
new WorldPoint(3810, 3058, 0),
|
||||||
|
|
||||||
|
// Isle of Souls
|
||||||
|
new WorldPoint(2194, 2991, 0),
|
||||||
|
|
||||||
// Karamja
|
// Karamja
|
||||||
new WorldPoint(2821, 3084, 0)),
|
new WorldPoint(2821, 3084, 0)),
|
||||||
|
|
||||||
@@ -180,6 +186,10 @@ enum RareTreeLocation
|
|||||||
new WorldPoint(3674, 3447, 0),
|
new WorldPoint(3674, 3447, 0),
|
||||||
new WorldPoint(3684, 3385, 0),
|
new WorldPoint(3684, 3385, 0),
|
||||||
|
|
||||||
|
// Isle of Souls
|
||||||
|
new WorldPoint(2147, 2972, 0),
|
||||||
|
new WorldPoint(2165, 2863, 0),
|
||||||
|
|
||||||
// Zanaris
|
// Zanaris
|
||||||
new WorldPoint(2412, 4464, 0),
|
new WorldPoint(2412, 4464, 0),
|
||||||
new WorldPoint(2465, 4427, 0),
|
new WorldPoint(2465, 4427, 0),
|
||||||
|
|||||||
@@ -33,14 +33,12 @@ import java.awt.Font;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.FocusAdapter;
|
import java.awt.event.FocusAdapter;
|
||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.KeyEvent;
|
|
||||||
import java.awt.event.KeyListener;
|
import java.awt.event.KeyListener;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.MouseListener;
|
import java.awt.event.MouseListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import javax.swing.DefaultListModel;
|
import javax.swing.DefaultListModel;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
@@ -335,30 +333,6 @@ public class IconTextField extends JPanel
|
|||||||
clearListeners.add(clearListener);
|
clearListeners.add(clearListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addKeyListener(Consumer<KeyEvent> keyEventConsumer)
|
|
||||||
{
|
|
||||||
addKeyListener(new net.runelite.client.input.KeyListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void keyTyped(KeyEvent e)
|
|
||||||
{
|
|
||||||
keyEventConsumer.accept(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void keyPressed(KeyEvent e)
|
|
||||||
{
|
|
||||||
keyEventConsumer.accept(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void keyReleased(KeyEvent e)
|
|
||||||
{
|
|
||||||
keyEventConsumer.accept(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeKeyListener(KeyListener keyListener)
|
public void removeKeyListener(KeyListener keyListener)
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 116 B After Width: | Height: | Size: 134 B |
Binary file not shown.
|
After Width: | Height: | Size: 129 B |
Binary file not shown.
|
After Width: | Height: | Size: 339 B |
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct uniform {
|
||||||
|
int cameraYaw;
|
||||||
|
int cameraPitch;
|
||||||
|
int centerX;
|
||||||
|
int centerY;
|
||||||
|
int zoom;
|
||||||
|
int cameraX;
|
||||||
|
int cameraY;
|
||||||
|
int cameraZ;
|
||||||
|
int4 sinCosTable[2048];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct shared_data {
|
||||||
|
int totalNum[12]; // number of faces with a given priority
|
||||||
|
int totalDistance[12]; // sum of distances to faces of a given priority
|
||||||
|
int totalMappedNum[18]; // number of faces with a given adjusted priority
|
||||||
|
int min10; // minimum distance to a face of priority 10
|
||||||
|
int dfs[0]; // packed face id and distance, size 512 for small, 4096 for large
|
||||||
|
};
|
||||||
|
|
||||||
|
struct modelinfo {
|
||||||
|
int offset; // offset into buffer
|
||||||
|
int uvOffset; // offset into uv buffer
|
||||||
|
int size; // length in faces
|
||||||
|
int idx; // write idx in target buffer
|
||||||
|
int flags; // radius, orientation
|
||||||
|
int x; // scene position x
|
||||||
|
int y; // scene position y
|
||||||
|
int z; // scene position z
|
||||||
|
};
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PI 3.1415926535897932384626433832795f
|
||||||
|
#define UNIT PI / 1024.0f
|
||||||
|
|
||||||
|
float3 toScreen(int4 vertex, int cameraYaw, int cameraPitch, int centerX, int centerY, int zoom) {
|
||||||
|
float yawSin = sin(cameraYaw * UNIT);
|
||||||
|
float yawCos = cos(cameraYaw * UNIT);
|
||||||
|
|
||||||
|
float pitchSin = sin(cameraPitch * UNIT);
|
||||||
|
float pitchCos = cos(cameraPitch * UNIT);
|
||||||
|
|
||||||
|
float rotatedX = (vertex.z * yawSin) + (vertex.x * yawCos);
|
||||||
|
float rotatedZ = (vertex.z * yawCos) - (vertex.x * yawSin);
|
||||||
|
|
||||||
|
float var13 = (vertex.y * pitchCos) - (rotatedZ * pitchSin);
|
||||||
|
float var12 = (vertex.y * pitchSin) + (rotatedZ * pitchCos);
|
||||||
|
|
||||||
|
float x = rotatedX * zoom / var12 + centerX;
|
||||||
|
float y = var13 * zoom / var12 + centerY;
|
||||||
|
float z = -var12; // in OpenGL depth is negative
|
||||||
|
|
||||||
|
return (float3) (x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rotate a vertex by a given orientation in JAU
|
||||||
|
*/
|
||||||
|
int4 rotate_vertex(__constant struct uniform *uni, int4 vertex, int orientation) {
|
||||||
|
int4 sinCos = uni->sinCosTable[orientation];
|
||||||
|
int s = sinCos.x;
|
||||||
|
int c = sinCos.y;
|
||||||
|
int x = vertex.z * s + vertex.x * c >> 16;
|
||||||
|
int z = vertex.z * c - vertex.x * s >> 16;
|
||||||
|
return (int4)(x, vertex.y, z, vertex.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the distance to a vertex given the camera angle
|
||||||
|
*/
|
||||||
|
int vertex_distance(int4 vertex, int cameraYaw, int cameraPitch) {
|
||||||
|
int yawSin = (int)(65536.0f * sin(cameraYaw * UNIT));
|
||||||
|
int yawCos = (int)(65536.0f * cos(cameraYaw * UNIT));
|
||||||
|
|
||||||
|
int pitchSin = (int)(65536.0f * sin(cameraPitch * UNIT));
|
||||||
|
int pitchCos = (int)(65536.0f * cos(cameraPitch * UNIT));
|
||||||
|
|
||||||
|
int j = vertex.z * yawCos - vertex.x * yawSin >> 16;
|
||||||
|
int l = vertex.y * pitchSin + j * pitchCos >> 16;
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the distance to a face
|
||||||
|
*/
|
||||||
|
int face_distance(int4 vA, int4 vB, int4 vC, int cameraYaw, int cameraPitch) {
|
||||||
|
int dvA = vertex_distance(vA, cameraYaw, cameraPitch);
|
||||||
|
int dvB = vertex_distance(vB, cameraYaw, cameraPitch);
|
||||||
|
int dvC = vertex_distance(vC, cameraYaw, cameraPitch);
|
||||||
|
int faceDistance = (dvA + dvB + dvC) / 3;
|
||||||
|
return faceDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test if a face is visible (not backward facing)
|
||||||
|
*/
|
||||||
|
bool face_visible(__constant struct uniform *uni, int4 vA, int4 vB, int4 vC, int4 position) {
|
||||||
|
// Move model to scene location, and account for camera offset
|
||||||
|
int4 cameraPos = (int4)(uni->cameraX, uni->cameraY, uni->cameraZ, 0);
|
||||||
|
vA += position - cameraPos;
|
||||||
|
vB += position - cameraPos;
|
||||||
|
vC += position - cameraPos;
|
||||||
|
|
||||||
|
float3 sA = toScreen(vA, uni->cameraYaw, uni->cameraPitch, uni->centerX, uni->centerY, uni->zoom);
|
||||||
|
float3 sB = toScreen(vB, uni->cameraYaw, uni->cameraPitch, uni->centerX, uni->centerY, uni->zoom);
|
||||||
|
float3 sC = toScreen(vC, uni->cameraYaw, uni->cameraPitch, uni->centerX, uni->centerY, uni->zoom);
|
||||||
|
|
||||||
|
return (sA.x - sB.x) * (sC.y - sB.y) - (sC.x - sB.x) * (sA.y - sB.y) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include FACE_COUNT
|
||||||
|
|
||||||
|
#include cl_types.cl
|
||||||
|
#include to_screen.cl
|
||||||
|
#include common.cl
|
||||||
|
#include priority_render.cl
|
||||||
|
|
||||||
|
__kernel
|
||||||
|
__attribute__((work_group_size_hint(256, 1, 1)))
|
||||||
|
void computeLarge(
|
||||||
|
__local struct shared_data *shared,
|
||||||
|
__global const struct modelinfo *ol,
|
||||||
|
__global const int4 *vb,
|
||||||
|
__global const int4 *tempvb,
|
||||||
|
__global const float4 *uv,
|
||||||
|
__global const float4 *tempuv,
|
||||||
|
__global int4 *vout,
|
||||||
|
__global float4 *uvout,
|
||||||
|
__constant struct uniform *uni) {
|
||||||
|
|
||||||
|
size_t groupId = get_group_id(0);
|
||||||
|
size_t localId = get_local_id(0) * FACE_COUNT;
|
||||||
|
struct modelinfo minfo = ol[groupId];
|
||||||
|
int4 pos = (int4)(minfo.x, minfo.y, minfo.z, 0);
|
||||||
|
|
||||||
|
if (localId == 0) {
|
||||||
|
shared->min10 = 1600;
|
||||||
|
for (int i = 0; i < 12; ++i) {
|
||||||
|
shared->totalNum[i] = 0;
|
||||||
|
shared->totalDistance[i] = 0;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 18; ++i) {
|
||||||
|
shared->totalMappedNum[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int prio[FACE_COUNT];
|
||||||
|
int dis[FACE_COUNT];
|
||||||
|
int4 v1[FACE_COUNT];
|
||||||
|
int4 v2[FACE_COUNT];
|
||||||
|
int4 v3[FACE_COUNT];
|
||||||
|
|
||||||
|
for (int i = 0; i < FACE_COUNT; i++) {
|
||||||
|
get_face(shared, uni, vb, tempvb, localId + i, minfo, uni->cameraYaw, uni->cameraPitch, &prio[i], &dis[i], &v1[i], &v2[i], &v3[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier(CLK_LOCAL_MEM_FENCE);
|
||||||
|
|
||||||
|
for (int i = 0; i < FACE_COUNT; i++) {
|
||||||
|
add_face_prio_distance(shared, uni, localId + i, minfo, v1[i], v2[i], v3[i], prio[i], dis[i], pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier(CLK_LOCAL_MEM_FENCE);
|
||||||
|
|
||||||
|
int prioAdj[FACE_COUNT];
|
||||||
|
int idx[FACE_COUNT];
|
||||||
|
for (int i = 0; i < FACE_COUNT; i++) {
|
||||||
|
idx[i] = map_face_priority(shared, localId + i, minfo, prio[i], dis[i], &prioAdj[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier(CLK_LOCAL_MEM_FENCE);
|
||||||
|
|
||||||
|
for (int i = 0; i < FACE_COUNT; i++) {
|
||||||
|
insert_dfs(shared, localId + i, minfo, prioAdj[i], dis[i], idx[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier(CLK_LOCAL_MEM_FENCE);
|
||||||
|
|
||||||
|
for (int i = 0; i < FACE_COUNT; i++) {
|
||||||
|
sort_and_insert(shared, uv, tempuv, vout, uvout, localId + i, minfo, prioAdj[i], dis[i], v1[i], v2[i], v3[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include cl_types.cl
|
||||||
|
|
||||||
|
__kernel
|
||||||
|
__attribute__((reqd_work_group_size(6, 1, 1)))
|
||||||
|
void computeUnordered(__global const struct modelinfo *ol,
|
||||||
|
__global const int4 *vb,
|
||||||
|
__global const int4 *tempvb,
|
||||||
|
__global const float4 *uv,
|
||||||
|
__global const float4 *tempuv,
|
||||||
|
__global int4 *vout,
|
||||||
|
__global float4 *uvout) {
|
||||||
|
size_t groupId = get_group_id(0);
|
||||||
|
size_t localId = get_local_id(0);
|
||||||
|
struct modelinfo minfo = ol[groupId];
|
||||||
|
|
||||||
|
int offset = minfo.offset;
|
||||||
|
int size = minfo.size;
|
||||||
|
int outOffset = minfo.idx;
|
||||||
|
int uvOffset = minfo.uvOffset;
|
||||||
|
int flags = minfo.flags;
|
||||||
|
int4 pos = (int4)(minfo.x, minfo.y, minfo.z, 0);
|
||||||
|
|
||||||
|
if (localId >= size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint ssboOffset = localId;
|
||||||
|
int4 thisA, thisB, thisC;
|
||||||
|
|
||||||
|
// Grab triangle vertices from the correct buffer
|
||||||
|
if (flags < 0) {
|
||||||
|
thisA = vb[offset + ssboOffset * 3];
|
||||||
|
thisB = vb[offset + ssboOffset * 3 + 1];
|
||||||
|
thisC = vb[offset + ssboOffset * 3 + 2];
|
||||||
|
} else {
|
||||||
|
thisA = tempvb[offset + ssboOffset * 3];
|
||||||
|
thisB = tempvb[offset + ssboOffset * 3 + 1];
|
||||||
|
thisC = tempvb[offset + ssboOffset * 3 + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint myOffset = localId;
|
||||||
|
|
||||||
|
// position vertices in scene and write to out buffer
|
||||||
|
vout[outOffset + myOffset * 3] = pos + thisA;
|
||||||
|
vout[outOffset + myOffset * 3 + 1] = pos + thisB;
|
||||||
|
vout[outOffset + myOffset * 3 + 2] = pos + thisC;
|
||||||
|
|
||||||
|
if (uvOffset < 0) {
|
||||||
|
uvout[outOffset + myOffset * 3] = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
uvout[outOffset + myOffset * 3 + 1] = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
uvout[outOffset + myOffset * 3 + 2] = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
} else if (flags >= 0) {
|
||||||
|
uvout[outOffset + myOffset * 3] = tempuv[uvOffset + localId * 3];
|
||||||
|
uvout[outOffset + myOffset * 3 + 1] = tempuv[uvOffset + localId * 3 + 1];
|
||||||
|
uvout[outOffset + myOffset * 3 + 2] = tempuv[uvOffset + localId * 3 + 2];
|
||||||
|
} else {
|
||||||
|
uvout[outOffset + myOffset * 3] = uv[uvOffset + localId * 3];
|
||||||
|
uvout[outOffset + myOffset * 3 + 1] = uv[uvOffset + localId * 3 + 1];
|
||||||
|
uvout[outOffset + myOffset * 3 + 2] = uv[uvOffset + localId * 3 + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Calculate adjusted priority for a face with a given priority, distance, and
|
||||||
|
// model global min10 and face distance averages. This allows positioning faces
|
||||||
|
// with priorities 10/11 into the correct 'slots' resulting in 18 possible
|
||||||
|
// adjusted priorities
|
||||||
|
int priority_map(int p, int distance, int _min10, int avg1, int avg2, int avg3) {
|
||||||
|
// (10, 11) 0 1 2 (10, 11) 3 4 (10, 11) 5 6 7 8 9 (10, 11)
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
||||||
|
switch (p) {
|
||||||
|
case 0: return 2;
|
||||||
|
case 1: return 3;
|
||||||
|
case 2: return 4;
|
||||||
|
case 3: return 7;
|
||||||
|
case 4: return 8;
|
||||||
|
case 5: return 11;
|
||||||
|
case 6: return 12;
|
||||||
|
case 7: return 13;
|
||||||
|
case 8: return 14;
|
||||||
|
case 9: return 15;
|
||||||
|
case 10:
|
||||||
|
if (distance > avg1) {
|
||||||
|
return 0;
|
||||||
|
} else if (distance > avg2) {
|
||||||
|
return 5;
|
||||||
|
} else if (distance > avg3) {
|
||||||
|
return 9;
|
||||||
|
} else {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
case 11:
|
||||||
|
if (distance > avg1 && _min10 > avg1) {
|
||||||
|
return 1;
|
||||||
|
} else if (distance > avg2 && (_min10 > avg1 || _min10 > avg2)) {
|
||||||
|
return 6;
|
||||||
|
} else if (distance > avg3 && (_min10 > avg1 || _min10 > avg2 || _min10 > avg3)) {
|
||||||
|
return 10;
|
||||||
|
} else {
|
||||||
|
return 17;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the number of faces with a lower adjusted priority than
|
||||||
|
// the given adjusted priority
|
||||||
|
int count_prio_offset(__local struct shared_data *shared, int priority) {
|
||||||
|
int total = 0;
|
||||||
|
switch (priority) {
|
||||||
|
case 17:
|
||||||
|
total += shared->totalMappedNum[16];
|
||||||
|
case 16:
|
||||||
|
total += shared->totalMappedNum[15];
|
||||||
|
case 15:
|
||||||
|
total += shared->totalMappedNum[14];
|
||||||
|
case 14:
|
||||||
|
total += shared->totalMappedNum[13];
|
||||||
|
case 13:
|
||||||
|
total += shared->totalMappedNum[12];
|
||||||
|
case 12:
|
||||||
|
total += shared->totalMappedNum[11];
|
||||||
|
case 11:
|
||||||
|
total += shared->totalMappedNum[10];
|
||||||
|
case 10:
|
||||||
|
total += shared->totalMappedNum[9];
|
||||||
|
case 9:
|
||||||
|
total += shared->totalMappedNum[8];
|
||||||
|
case 8:
|
||||||
|
total += shared->totalMappedNum[7];
|
||||||
|
case 7:
|
||||||
|
total += shared->totalMappedNum[6];
|
||||||
|
case 6:
|
||||||
|
total += shared->totalMappedNum[5];
|
||||||
|
case 5:
|
||||||
|
total += shared->totalMappedNum[4];
|
||||||
|
case 4:
|
||||||
|
total += shared->totalMappedNum[3];
|
||||||
|
case 3:
|
||||||
|
total += shared->totalMappedNum[2];
|
||||||
|
case 2:
|
||||||
|
total += shared->totalMappedNum[1];
|
||||||
|
case 1:
|
||||||
|
total += shared->totalMappedNum[0];
|
||||||
|
case 0:
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_face(
|
||||||
|
__local struct shared_data *shared,
|
||||||
|
__constant struct uniform *uni,
|
||||||
|
__global const int4 *vb,
|
||||||
|
__global const int4 *tempvb,
|
||||||
|
uint localId, struct modelinfo minfo, int cameraYaw, int cameraPitch,
|
||||||
|
/* out */ int *prio, int *dis, int4 *o1, int4 *o2, int4 *o3) {
|
||||||
|
int size = minfo.size;
|
||||||
|
int offset = minfo.offset;
|
||||||
|
int flags = minfo.flags;
|
||||||
|
uint ssboOffset;
|
||||||
|
|
||||||
|
if (localId < size) {
|
||||||
|
ssboOffset = localId;
|
||||||
|
} else {
|
||||||
|
ssboOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 thisA;
|
||||||
|
int4 thisB;
|
||||||
|
int4 thisC;
|
||||||
|
|
||||||
|
// Grab triangle vertices from the correct buffer
|
||||||
|
if (flags < 0) {
|
||||||
|
thisA = vb[offset + ssboOffset * 3];
|
||||||
|
thisB = vb[offset + ssboOffset * 3 + 1];
|
||||||
|
thisC = vb[offset + ssboOffset * 3 + 2];
|
||||||
|
} else {
|
||||||
|
thisA = tempvb[offset + ssboOffset * 3];
|
||||||
|
thisB = tempvb[offset + ssboOffset * 3 + 1];
|
||||||
|
thisC = tempvb[offset + ssboOffset * 3 + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localId < size) {
|
||||||
|
int radius = (flags & 0x7fffffff) >> 12;
|
||||||
|
int orientation = flags & 0x7ff;
|
||||||
|
|
||||||
|
// rotate for model orientation
|
||||||
|
int4 thisrvA = rotate_vertex(uni, thisA, orientation);
|
||||||
|
int4 thisrvB = rotate_vertex(uni, thisB, orientation);
|
||||||
|
int4 thisrvC = rotate_vertex(uni, thisC, orientation);
|
||||||
|
|
||||||
|
// calculate distance to face
|
||||||
|
int thisPriority = (thisA.w >> 16) & 0xff;// all vertices on the face have the same priority
|
||||||
|
int thisDistance;
|
||||||
|
if (radius == 0) {
|
||||||
|
thisDistance = 0;
|
||||||
|
} else {
|
||||||
|
thisDistance = face_distance(thisrvA, thisrvB, thisrvC, cameraYaw, cameraPitch) + radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
*o1 = thisrvA;
|
||||||
|
*o2 = thisrvB;
|
||||||
|
*o3 = thisrvC;
|
||||||
|
|
||||||
|
*prio = thisPriority;
|
||||||
|
*dis = thisDistance;
|
||||||
|
} else {
|
||||||
|
*o1 = (int4)(0, 0, 0, 0);
|
||||||
|
*o2 = (int4)(0, 0, 0, 0);
|
||||||
|
*o3 = (int4)(0, 0, 0, 0);
|
||||||
|
*prio = 0;
|
||||||
|
*dis = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_face_prio_distance(
|
||||||
|
__local struct shared_data *shared,
|
||||||
|
__constant struct uniform *uni,
|
||||||
|
uint localId, struct modelinfo minfo, int4 thisrvA, int4 thisrvB, int4 thisrvC, int thisPriority, int thisDistance, int4 pos) {
|
||||||
|
if (localId < minfo.size) {
|
||||||
|
// if the face is not culled, it is calculated into priority distance averages
|
||||||
|
if (face_visible(uni, thisrvA, thisrvB, thisrvC, pos)) {
|
||||||
|
atomic_add(&shared->totalNum[thisPriority], 1);
|
||||||
|
atomic_add(&shared->totalDistance[thisPriority], thisDistance);
|
||||||
|
|
||||||
|
// calculate minimum distance to any face of priority 10 for positioning the 11 faces later
|
||||||
|
if (thisPriority == 10) {
|
||||||
|
atomic_min(&shared->min10, thisDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int map_face_priority(__local struct shared_data *shared, uint localId, struct modelinfo minfo, int thisPriority, int thisDistance, int *prio) {
|
||||||
|
int size = minfo.size;
|
||||||
|
|
||||||
|
// Compute average distances for 0/2, 3/4, and 6/8
|
||||||
|
|
||||||
|
if (localId < size) {
|
||||||
|
int avg1 = 0;
|
||||||
|
int avg2 = 0;
|
||||||
|
int avg3 = 0;
|
||||||
|
|
||||||
|
if (shared->totalNum[1] > 0 || shared->totalNum[2] > 0) {
|
||||||
|
avg1 = (shared->totalDistance[1] + shared->totalDistance[2]) / (shared->totalNum[1] + shared->totalNum[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shared->totalNum[3] > 0 || shared->totalNum[4] > 0) {
|
||||||
|
avg2 = (shared->totalDistance[3] + shared->totalDistance[4]) / (shared->totalNum[3] + shared->totalNum[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shared->totalNum[6] > 0 || shared->totalNum[8] > 0) {
|
||||||
|
avg3 = (shared->totalDistance[6] + shared->totalDistance[8]) / (shared->totalNum[6] + shared->totalNum[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int adjPrio = priority_map(thisPriority, thisDistance, shared->min10, avg1, avg2, avg3);
|
||||||
|
int prioIdx = atomic_add(&shared->totalMappedNum[adjPrio], 1);
|
||||||
|
|
||||||
|
*prio = adjPrio;
|
||||||
|
return prioIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
*prio = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_dfs(__local struct shared_data *shared, uint localId, struct modelinfo minfo, int adjPrio, int distance, int prioIdx) {
|
||||||
|
int size = minfo.size;
|
||||||
|
|
||||||
|
if (localId < size) {
|
||||||
|
// calculate base offset into dfs based on number of faces with a lower priority
|
||||||
|
int baseOff = count_prio_offset(shared, adjPrio);
|
||||||
|
// store into face array offset array by unique index
|
||||||
|
shared->dfs[baseOff + prioIdx] = ((int) localId << 16) | distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sort_and_insert(
|
||||||
|
__local struct shared_data *shared,
|
||||||
|
__global const float4 *uv,
|
||||||
|
__global const float4 *tempuv,
|
||||||
|
__global int4 *vout,
|
||||||
|
__global float4 *uvout,
|
||||||
|
uint localId, struct modelinfo minfo, int thisPriority, int thisDistance, int4 thisrvA, int4 thisrvB, int4 thisrvC) {
|
||||||
|
/* compute face distance */
|
||||||
|
int size = minfo.size;
|
||||||
|
|
||||||
|
if (localId < size) {
|
||||||
|
int outOffset = minfo.idx;
|
||||||
|
int uvOffset = minfo.uvOffset;
|
||||||
|
int flags = minfo.flags;
|
||||||
|
int4 pos = (int4)(minfo.x, minfo.y, minfo.z, 0);
|
||||||
|
|
||||||
|
const int priorityOffset = count_prio_offset(shared, thisPriority);
|
||||||
|
const int numOfPriority = shared->totalMappedNum[thisPriority];
|
||||||
|
int start = priorityOffset; // index of first face with this priority
|
||||||
|
int end = priorityOffset + numOfPriority; // index of last face with this priority
|
||||||
|
int myOffset = priorityOffset;
|
||||||
|
|
||||||
|
// we only have to order faces against others of the same priority
|
||||||
|
// calculate position this face will be in
|
||||||
|
for (int i = start; i < end; ++i) {
|
||||||
|
int d1 = shared->dfs[i];
|
||||||
|
int theirId = d1 >> 16;
|
||||||
|
int theirDistance = d1 & 0xffff;
|
||||||
|
|
||||||
|
// the closest faces draw last, so have the highest index
|
||||||
|
// if two faces have the same distance, the one with the
|
||||||
|
// higher id draws last
|
||||||
|
if ((theirDistance > thisDistance)
|
||||||
|
|| (theirDistance == thisDistance && theirId < localId)) {
|
||||||
|
++myOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// position vertices in scene and write to out buffer
|
||||||
|
vout[outOffset + myOffset * 3] = pos + thisrvA;
|
||||||
|
vout[outOffset + myOffset * 3 + 1] = pos + thisrvB;
|
||||||
|
vout[outOffset + myOffset * 3 + 2] = pos + thisrvC;
|
||||||
|
|
||||||
|
if (uvOffset < 0) {
|
||||||
|
uvout[outOffset + myOffset * 3] = (float4)(0, 0, 0, 0);
|
||||||
|
uvout[outOffset + myOffset * 3 + 1] = (float4)(0, 0, 0, 0);
|
||||||
|
uvout[outOffset + myOffset * 3 + 2] = (float4)(0, 0, 0, 0);
|
||||||
|
} else if (flags >= 0) {
|
||||||
|
uvout[outOffset + myOffset * 3] = tempuv[uvOffset + localId * 3];
|
||||||
|
uvout[outOffset + myOffset * 3 + 1] = tempuv[uvOffset + localId * 3 + 1];
|
||||||
|
uvout[outOffset + myOffset * 3 + 2] = tempuv[uvOffset + localId * 3 + 2];
|
||||||
|
} else {
|
||||||
|
uvout[outOffset + myOffset * 3] = uv[uvOffset + localId * 3];
|
||||||
|
uvout[outOffset + myOffset * 3 + 1] = uv[uvOffset + localId * 3 + 1];
|
||||||
|
uvout[outOffset + myOffset * 3 + 2] = uv[uvOffset + localId * 3 + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 463 B |
Binary file not shown.
|
After Width: | Height: | Size: 310 B |
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* 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.chat;
|
||||||
|
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.testing.fieldbinder.Bind;
|
||||||
|
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||||
|
import java.awt.Color;
|
||||||
|
import net.runelite.api.ChatMessageType;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.MessageNode;
|
||||||
|
import net.runelite.api.Player;
|
||||||
|
import net.runelite.api.events.ChatMessage;
|
||||||
|
import net.runelite.client.config.ChatColorConfig;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class ChatMessageManagerTest
|
||||||
|
{
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private ChatColorConfig chatColorConfig;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ChatMessageManager chatMessageManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before()
|
||||||
|
{
|
||||||
|
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||||
|
|
||||||
|
chatMessageManager.loadColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMessageRecoloring()
|
||||||
|
{
|
||||||
|
when(chatColorConfig.opaqueServerMessage()).thenReturn(Color.decode("#b20000"));
|
||||||
|
|
||||||
|
chatMessageManager.loadColors();
|
||||||
|
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.GAMEMESSAGE);
|
||||||
|
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
|
||||||
|
when(messageNode.getValue()).thenReturn("Your dodgy necklace protects you. It has <col=ff0000>1</col> charge left.");
|
||||||
|
chatMessageManager.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setValue("<col=b20000>Your dodgy necklace protects you. It has <col=ff0000>1<col=b20000> charge left.</col>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPublicFriendUsernameRecolouring()
|
||||||
|
{
|
||||||
|
final String localPlayerName = "RuneLite";
|
||||||
|
final String friendName = "Zezima";
|
||||||
|
|
||||||
|
when(chatColorConfig.opaquePublicFriendUsernames()).thenReturn(Color.decode("#b20000"));
|
||||||
|
|
||||||
|
chatMessageManager.loadColors();
|
||||||
|
|
||||||
|
// Setup message
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.PUBLICCHAT);
|
||||||
|
chatMessage.setName(friendName);
|
||||||
|
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
when(messageNode.getName()).thenReturn(friendName);
|
||||||
|
|
||||||
|
// Setup friend checking
|
||||||
|
Player localPlayer = mock(Player.class);
|
||||||
|
|
||||||
|
when(client.isFriended(friendName, true)).thenReturn(true);
|
||||||
|
when(client.getLocalPlayer()).thenReturn(localPlayer);
|
||||||
|
when(localPlayer.getName()).thenReturn(localPlayerName);
|
||||||
|
|
||||||
|
chatMessageManager.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setName("<col=b20000>" + friendName + "</col>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPublicIronmanFriendUsernameRecolouring()
|
||||||
|
{
|
||||||
|
final String localPlayerName = "RuneLite";
|
||||||
|
final String friendName = "<img=3>BuddhaPuck";
|
||||||
|
final String sanitizedFriendName = "BuddhaPuck";
|
||||||
|
|
||||||
|
when(chatColorConfig.opaquePublicFriendUsernames()).thenReturn(Color.decode("#b20000"));
|
||||||
|
|
||||||
|
chatMessageManager.loadColors();
|
||||||
|
|
||||||
|
// Setup message
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.PUBLICCHAT);
|
||||||
|
chatMessage.setName(friendName);
|
||||||
|
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
when(messageNode.getName()).thenReturn(friendName);
|
||||||
|
|
||||||
|
// Setup friend checking
|
||||||
|
Player localPlayer = mock(Player.class);
|
||||||
|
|
||||||
|
when(client.isFriended(sanitizedFriendName, true)).thenReturn(true);
|
||||||
|
when(client.getLocalPlayer()).thenReturn(localPlayer);
|
||||||
|
when(localPlayer.getName()).thenReturn(localPlayerName);
|
||||||
|
|
||||||
|
chatMessageManager.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setName("<col=b20000>" + friendName + "</col>");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Hydrox6 <ikada@protonmail.ch>
|
||||||
|
* Copyright (c) 2019 Adam <Adam@sigterm.info>
|
||||||
|
* 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.cluescrolls;
|
||||||
|
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
|
import com.google.inject.testing.fieldbinder.Bind;
|
||||||
|
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||||
|
import net.runelite.api.ChatMessageType;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.NPC;
|
||||||
|
import net.runelite.api.Player;
|
||||||
|
import net.runelite.api.coords.WorldPoint;
|
||||||
|
import net.runelite.api.events.ChatMessage;
|
||||||
|
import net.runelite.api.events.GameTick;
|
||||||
|
import net.runelite.api.widgets.Widget;
|
||||||
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
|
import net.runelite.client.game.ItemManager;
|
||||||
|
import net.runelite.client.plugins.banktags.TagManager;
|
||||||
|
import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation;
|
||||||
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class ClueScrollPluginTest
|
||||||
|
{
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
Client client;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ClueScrollPlugin plugin;
|
||||||
|
|
||||||
|
@Bind
|
||||||
|
@Named("developerMode")
|
||||||
|
boolean developerMode;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
ClueScrollConfig config;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
OverlayManager overlayManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
ItemManager itemManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
TagManager tagManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before()
|
||||||
|
{
|
||||||
|
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getGetMirrorPoint()
|
||||||
|
{
|
||||||
|
WorldPoint point, converted;
|
||||||
|
|
||||||
|
// Zalcano's entrance portal
|
||||||
|
point = new WorldPoint(3282, 6058, 0);
|
||||||
|
converted = ClueScrollPlugin.getMirrorPoint(point, true);
|
||||||
|
assertNotEquals(point, converted);
|
||||||
|
|
||||||
|
// Elven Crystal Chest, which is upstairs
|
||||||
|
point = new WorldPoint(3273, 6082, 2);
|
||||||
|
converted = ClueScrollPlugin.getMirrorPoint(point, true);
|
||||||
|
assertNotEquals(point, converted);
|
||||||
|
|
||||||
|
// Around the area of the Elite coordinate clue
|
||||||
|
point = new WorldPoint(2185, 3280, 0);
|
||||||
|
// To overworld
|
||||||
|
converted = ClueScrollPlugin.getMirrorPoint(point, true);
|
||||||
|
assertEquals(point, converted);
|
||||||
|
// To real
|
||||||
|
converted = ClueScrollPlugin.getMirrorPoint(point, false);
|
||||||
|
assertNotEquals(point, converted);
|
||||||
|
|
||||||
|
// Brugsen Bursen, Grand Exchange
|
||||||
|
point = new WorldPoint(3165, 3477, 0);
|
||||||
|
converted = ClueScrollPlugin.getMirrorPoint(point, false);
|
||||||
|
assertEquals(point, converted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocationHintArrowCleared()
|
||||||
|
{
|
||||||
|
final Widget clueWidget = mock(Widget.class);
|
||||||
|
when(clueWidget.getText()).thenReturn("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Reldo may have a clue.");
|
||||||
|
final ChatMessage hotColdMessage = new ChatMessage();
|
||||||
|
hotColdMessage.setType(ChatMessageType.GAMEMESSAGE);
|
||||||
|
final Player localPlayer = mock(Player.class);
|
||||||
|
|
||||||
|
when(client.getWidget(WidgetInfo.CLUE_SCROLL_TEXT)).thenReturn(clueWidget);
|
||||||
|
when(client.getLocalPlayer()).thenReturn(localPlayer);
|
||||||
|
when(client.getPlane()).thenReturn(0);
|
||||||
|
when(client.getCachedNPCs()).thenReturn(new NPC[] {});
|
||||||
|
when(config.displayHintArrows()).thenReturn(true);
|
||||||
|
|
||||||
|
// The hint arrow should be reset each game tick from when the clue is read onward
|
||||||
|
// This is to verify the arrow is cleared the correct number of times during the clue updating process.
|
||||||
|
int clueSetupHintArrowClears = 0;
|
||||||
|
|
||||||
|
// Initialize a beginner hot-cold clue (which will have an end point of LUMBRIDGE_COW_FIELD)
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(client, times(++clueSetupHintArrowClears)).clearHintArrow();
|
||||||
|
|
||||||
|
// Perform the first hot-cold check in Lumbridge near sheep pen (get 2 possible points: LUMBRIDGE_COW_FIELD and DRAYNOR_WHEAT_FIELD)
|
||||||
|
when(localPlayer.getWorldLocation()).thenReturn(new WorldPoint(3208, 3254, 0));
|
||||||
|
hotColdMessage.setMessage("The device is hot.");
|
||||||
|
plugin.onChatMessage(hotColdMessage);
|
||||||
|
|
||||||
|
// Move to SW of DRAYNOR_WHEAT_FIELD (hint arrow should be visible here)
|
||||||
|
when(localPlayer.getWorldLocation()).thenReturn(new WorldPoint(3105, 3265, 0));
|
||||||
|
when(client.getBaseX()).thenReturn(3056);
|
||||||
|
when(client.getBaseY()).thenReturn(3216);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(client, times(++clueSetupHintArrowClears)).clearHintArrow();
|
||||||
|
verify(client).setHintArrow(HotColdLocation.DRAYNOR_WHEAT_FIELD.getWorldPoint());
|
||||||
|
|
||||||
|
// Test in that location (get 1 possible location: LUMBRIDGE_COW_FIELD)
|
||||||
|
hotColdMessage.setMessage("The device is hot, and warmer than last time.");
|
||||||
|
plugin.onChatMessage(hotColdMessage);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
|
||||||
|
// Hint arrow should be cleared and not re-set now as the only remaining location is outside of the current
|
||||||
|
// scene
|
||||||
|
verify(client, times(++clueSetupHintArrowClears)).clearHintArrow();
|
||||||
|
verify(client, times(1)).setHintArrow(any(WorldPoint.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* 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.emojis;
|
||||||
|
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.testing.fieldbinder.Bind;
|
||||||
|
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||||
|
import net.runelite.api.ChatMessageType;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.GameState;
|
||||||
|
import net.runelite.api.IndexedSprite;
|
||||||
|
import net.runelite.api.MessageNode;
|
||||||
|
import net.runelite.api.events.ChatMessage;
|
||||||
|
import net.runelite.api.events.GameStateChanged;
|
||||||
|
import net.runelite.client.chat.ChatMessageManager;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class EmojiPluginTest
|
||||||
|
{
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private ChatMessageManager chatMessageManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private EmojiPlugin emojiPlugin;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before()
|
||||||
|
{
|
||||||
|
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnChatMessage()
|
||||||
|
{
|
||||||
|
when(client.getGameState()).thenReturn(GameState.LOGGED_IN);
|
||||||
|
when(client.getModIcons()).thenReturn(new IndexedSprite[0]);
|
||||||
|
when(client.createIndexedSprite()).thenReturn(mock(IndexedSprite.class));
|
||||||
|
|
||||||
|
// Trip emoji loading
|
||||||
|
GameStateChanged gameStateChanged = new GameStateChanged();
|
||||||
|
gameStateChanged.setGameState(GameState.LOGGED_IN);
|
||||||
|
emojiPlugin.onGameStateChanged(gameStateChanged);
|
||||||
|
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
// With chat recolor, message may be wrapped in col tags
|
||||||
|
when(messageNode.getValue()).thenReturn("<col=ff0000>:) :) :)</col>");
|
||||||
|
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.PUBLICCHAT);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
|
||||||
|
emojiPlugin.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setValue("<col=ff0000><img=0> <img=0> <img=0></col>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGtLt()
|
||||||
|
{
|
||||||
|
when(client.getGameState()).thenReturn(GameState.LOGGED_IN);
|
||||||
|
when(client.getModIcons()).thenReturn(new IndexedSprite[0]);
|
||||||
|
when(client.createIndexedSprite()).thenReturn(mock(IndexedSprite.class));
|
||||||
|
|
||||||
|
// Trip emoji loading
|
||||||
|
GameStateChanged gameStateChanged = new GameStateChanged();
|
||||||
|
gameStateChanged.setGameState(GameState.LOGGED_IN);
|
||||||
|
emojiPlugin.onGameStateChanged(gameStateChanged);
|
||||||
|
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
when(messageNode.getValue()).thenReturn("<gt>:D<lt>");
|
||||||
|
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.PUBLICCHAT);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
|
||||||
|
emojiPlugin.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setValue("<img=10>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmojiUpdateMessage()
|
||||||
|
{
|
||||||
|
String PARTY_POPPER = "<img=" + (-1 + Emoji.getEmoji("@@@").ordinal()) + '>';
|
||||||
|
String OPEN_MOUTH = "<img=" + (-1 + Emoji.getEmoji(":O").ordinal()) + '>';
|
||||||
|
assertNull(emojiPlugin.updateMessage("@@@@@"));
|
||||||
|
assertEquals(PARTY_POPPER, emojiPlugin.updateMessage("@@@"));
|
||||||
|
assertEquals(PARTY_POPPER + ' ' + PARTY_POPPER, emojiPlugin.updateMessage("@@@ @@@"));
|
||||||
|
assertEquals(PARTY_POPPER + ' ' + OPEN_MOUTH, emojiPlugin.updateMessage("@@@\u00A0:O"));
|
||||||
|
assertEquals(PARTY_POPPER + ' ' + OPEN_MOUTH + ' ' + PARTY_POPPER, emojiPlugin.updateMessage("@@@\u00A0:O @@@"));
|
||||||
|
assertEquals(PARTY_POPPER + " Hello World " + PARTY_POPPER, emojiPlugin.updateMessage("@@@\u00A0Hello World\u00A0@@@"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Adam <Adam@sigterm.info>
|
||||||
|
* 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.grounditems;
|
||||||
|
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.testing.fieldbinder.Bind;
|
||||||
|
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.ItemComposition;
|
||||||
|
import net.runelite.api.ItemID;
|
||||||
|
import net.runelite.api.ItemLayer;
|
||||||
|
import net.runelite.api.Player;
|
||||||
|
import net.runelite.api.Tile;
|
||||||
|
import net.runelite.api.TileItem;
|
||||||
|
import net.runelite.api.coords.WorldPoint;
|
||||||
|
import net.runelite.api.events.ItemSpawned;
|
||||||
|
import net.runelite.client.Notifier;
|
||||||
|
import net.runelite.client.events.ConfigChanged;
|
||||||
|
import net.runelite.client.game.ItemManager;
|
||||||
|
import net.runelite.client.input.KeyManager;
|
||||||
|
import net.runelite.client.input.MouseManager;
|
||||||
|
import net.runelite.client.plugins.grounditems.config.HighlightTier;
|
||||||
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class GroundItemsPluginTest
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
private GroundItemsPlugin groundItemsPlugin;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private MouseManager mouseManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private KeyManager keyManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private ItemManager itemManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private OverlayManager overlayManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private GroundItemsConfig config;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private GroundItemsOverlay overlay;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Notifier notifier;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private ScheduledExecutorService executor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||||
|
|
||||||
|
doAnswer(a ->
|
||||||
|
{
|
||||||
|
a.<Runnable>getArgument(0).run();
|
||||||
|
return null;
|
||||||
|
}).when(executor).execute(any(Runnable.class));
|
||||||
|
|
||||||
|
when(client.getLocalPlayer()).thenReturn(mock(Player.class));
|
||||||
|
when(config.getHiddenItems()).thenReturn("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyHighlightedItem()
|
||||||
|
{
|
||||||
|
when(config.getHighlightItems()).thenReturn("abyssal whip");
|
||||||
|
when(config.notifyTier()).thenReturn(HighlightTier.OFF);
|
||||||
|
when(config.notifyHighlightedDrops()).thenReturn(true);
|
||||||
|
|
||||||
|
when(itemManager.getItemComposition(ItemID.ABYSSAL_WHIP)).thenAnswer(a ->
|
||||||
|
{
|
||||||
|
ItemComposition itemComposition = mock(ItemComposition.class);
|
||||||
|
when(itemComposition.getName()).thenReturn("Abyssal whip");
|
||||||
|
return itemComposition;
|
||||||
|
});
|
||||||
|
|
||||||
|
// trigger reload of highlighted items list
|
||||||
|
ConfigChanged configChanged = new ConfigChanged();
|
||||||
|
configChanged.setGroup("grounditems");
|
||||||
|
groundItemsPlugin.onConfigChanged(configChanged);
|
||||||
|
|
||||||
|
// spawn whip
|
||||||
|
Tile tile = mock(Tile.class);
|
||||||
|
when(tile.getItemLayer()).thenReturn(mock(ItemLayer.class));
|
||||||
|
when(tile.getWorldLocation()).thenReturn(new WorldPoint(0, 0, 0));
|
||||||
|
|
||||||
|
TileItem tileItem = mock(TileItem.class);
|
||||||
|
when(tileItem.getId()).thenReturn(ItemID.ABYSSAL_WHIP);
|
||||||
|
when(tileItem.getQuantity()).thenReturn(1);
|
||||||
|
|
||||||
|
groundItemsPlugin.onItemSpawned(new ItemSpawned(tile, tileItem));
|
||||||
|
|
||||||
|
verify(notifier).notify("You received a highlighted drop: Abyssal whip");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* 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.Guice;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.testing.fieldbinder.Bind;
|
||||||
|
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||||
|
import net.runelite.api.Actor;
|
||||||
|
import net.runelite.api.AnimationID;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.GameState;
|
||||||
|
import net.runelite.api.Hitsplat;
|
||||||
|
import net.runelite.api.NPC;
|
||||||
|
import net.runelite.api.NPCComposition;
|
||||||
|
import net.runelite.api.Player;
|
||||||
|
import net.runelite.api.VarPlayer;
|
||||||
|
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.HitsplatApplied;
|
||||||
|
import net.runelite.api.events.InteractingChanged;
|
||||||
|
import net.runelite.client.Notifier;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class IdleNotifierPluginTest
|
||||||
|
{
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private IdleNotifierConfig config;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Notifier notifier;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private IdleNotifierPlugin plugin;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private NPC monster;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private NPC randomEvent;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private NPC fishingSpot;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||||
|
|
||||||
|
// Mock monster
|
||||||
|
final String[] monsterActions = new String[] { "Attack", "Examine" };
|
||||||
|
final NPCComposition monsterComp = mock(NPCComposition.class);
|
||||||
|
when(monsterComp.getActions()).thenReturn(monsterActions);
|
||||||
|
when(monster.getComposition()).thenReturn(monsterComp);
|
||||||
|
|
||||||
|
// Mock random event
|
||||||
|
final String[] randomEventActions = new String[] { "Talk-to", "Dismiss", "Examine" };
|
||||||
|
final NPCComposition randomEventComp = mock(NPCComposition.class);
|
||||||
|
when(randomEventComp.getActions()).thenReturn(randomEventActions);
|
||||||
|
when(randomEvent.getComposition()).thenReturn(randomEventComp);
|
||||||
|
|
||||||
|
// Mock Fishing Spot
|
||||||
|
final String[] fishingSpotActions = new String[] { "Use-rod", "Examine" };
|
||||||
|
final NPCComposition fishingSpotComp = mock(NPCComposition.class);
|
||||||
|
when(fishingSpotComp.getActions()).thenReturn(fishingSpotActions);
|
||||||
|
when(fishingSpot.getComposition()).thenReturn(fishingSpotComp);
|
||||||
|
when(fishingSpot.getName()).thenReturn("Fishing spot");
|
||||||
|
|
||||||
|
// Mock player
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.IDLE);
|
||||||
|
when(client.getLocalPlayer()).thenReturn(player);
|
||||||
|
|
||||||
|
// Mock config
|
||||||
|
when(config.logoutIdle()).thenReturn(true);
|
||||||
|
when(config.animationIdle()).thenReturn(true);
|
||||||
|
when(config.interactionIdle()).thenReturn(true);
|
||||||
|
when(config.getIdleNotificationDelay()).thenReturn(0);
|
||||||
|
when(config.getHitpointsThreshold()).thenReturn(42);
|
||||||
|
when(config.getPrayerThreshold()).thenReturn(42);
|
||||||
|
|
||||||
|
// Mock client
|
||||||
|
when(client.getGameState()).thenReturn(GameState.LOGGED_IN);
|
||||||
|
when(client.getKeyboardIdleTicks()).thenReturn(42);
|
||||||
|
when(client.getMouseLastPressedMillis()).thenReturn(System.currentTimeMillis() - 100_000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkAnimationIdle()
|
||||||
|
{
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.WOODCUTTING_BRONZE);
|
||||||
|
AnimationChanged animationChanged = new AnimationChanged();
|
||||||
|
animationChanged.setActor(player);
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.IDLE);
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier).notify("You are now idle!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkAnimationReset()
|
||||||
|
{
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.WOODCUTTING_BRONZE);
|
||||||
|
AnimationChanged animationChanged = new AnimationChanged();
|
||||||
|
animationChanged.setActor(player);
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.LOOKING_INTO);
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.IDLE);
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier, times(0)).notify(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkAnimationLogout()
|
||||||
|
{
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.WOODCUTTING_BRONZE);
|
||||||
|
AnimationChanged animationChanged = new AnimationChanged();
|
||||||
|
animationChanged.setActor(player);
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
|
||||||
|
// Logout
|
||||||
|
when(client.getGameState()).thenReturn(GameState.LOGIN_SCREEN);
|
||||||
|
GameStateChanged gameStateChanged = new GameStateChanged();
|
||||||
|
gameStateChanged.setGameState(GameState.LOGIN_SCREEN);
|
||||||
|
plugin.onGameStateChanged(gameStateChanged);
|
||||||
|
|
||||||
|
// Log back in
|
||||||
|
when(client.getGameState()).thenReturn(GameState.LOGGED_IN);
|
||||||
|
gameStateChanged.setGameState(GameState.LOGGED_IN);
|
||||||
|
plugin.onGameStateChanged(gameStateChanged);
|
||||||
|
|
||||||
|
// Tick
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.IDLE);
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier, times(0)).notify(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkCombatIdle()
|
||||||
|
{
|
||||||
|
when(player.getInteracting()).thenReturn(monster);
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, monster));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
when(player.getInteracting()).thenReturn(null);
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, null));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier).notify("You are now out of combat!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkCombatReset()
|
||||||
|
{
|
||||||
|
when(player.getInteracting()).thenReturn(mock(Actor.class));
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, monster));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, randomEvent));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, null));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier, times(0)).notify(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkCombatLogout()
|
||||||
|
{
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, monster));
|
||||||
|
when(player.getInteracting()).thenReturn(mock(Actor.class));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
|
||||||
|
// Logout
|
||||||
|
when(client.getGameState()).thenReturn(GameState.LOGIN_SCREEN);
|
||||||
|
GameStateChanged gameStateChanged = new GameStateChanged();
|
||||||
|
gameStateChanged.setGameState(GameState.LOGIN_SCREEN);
|
||||||
|
plugin.onGameStateChanged(gameStateChanged);
|
||||||
|
|
||||||
|
// Log back in
|
||||||
|
when(client.getGameState()).thenReturn(GameState.LOGGED_IN);
|
||||||
|
gameStateChanged.setGameState(GameState.LOGGED_IN);
|
||||||
|
plugin.onGameStateChanged(gameStateChanged);
|
||||||
|
|
||||||
|
// Tick
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, null));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier, times(0)).notify(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkCombatLogoutIdle()
|
||||||
|
{
|
||||||
|
// Player is idle
|
||||||
|
when(client.getMouseIdleTicks()).thenReturn(80_000);
|
||||||
|
|
||||||
|
// But player is being damaged (is in combat)
|
||||||
|
final HitsplatApplied hitsplatApplied = new HitsplatApplied();
|
||||||
|
hitsplatApplied.setActor(player);
|
||||||
|
hitsplatApplied.setHitsplat(new Hitsplat(Hitsplat.HitsplatType.DAMAGE_ME, 0, 0));
|
||||||
|
plugin.onHitsplatApplied(hitsplatApplied);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier, times(0)).notify(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doubleNotifyOnMouseReset()
|
||||||
|
{
|
||||||
|
// Player is idle, but in combat so the idle packet is getting set repeatedly
|
||||||
|
// make sure we are not notifying
|
||||||
|
|
||||||
|
when(client.getKeyboardIdleTicks()).thenReturn(80_000);
|
||||||
|
when(client.getMouseIdleTicks()).thenReturn(14_500);
|
||||||
|
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier, times(1)).notify(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendOneNotificationForAnimationAndInteract()
|
||||||
|
{
|
||||||
|
when(player.getInteracting()).thenReturn(fishingSpot);
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.FISHING_POLE_CAST);
|
||||||
|
|
||||||
|
AnimationChanged animationChanged = new AnimationChanged();
|
||||||
|
animationChanged.setActor(player);
|
||||||
|
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, fishingSpot));
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
|
||||||
|
verify(notifier, never()).notify(anyString());
|
||||||
|
|
||||||
|
when(player.getAnimation()).thenReturn(AnimationID.IDLE);
|
||||||
|
lenient().when(player.getInteracting()).thenReturn(null);
|
||||||
|
|
||||||
|
plugin.onAnimationChanged(animationChanged);
|
||||||
|
plugin.onInteractingChanged(new InteractingChanged(player, null));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
|
||||||
|
verify(notifier).notify("You are now idle!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpecRegen()
|
||||||
|
{
|
||||||
|
when(config.getSpecEnergyThreshold()).thenReturn(50);
|
||||||
|
|
||||||
|
when(client.getVar(eq(VarPlayer.SPECIAL_ATTACK_PERCENT))).thenReturn(400); // 40%
|
||||||
|
plugin.onGameTick(new GameTick()); // once to set lastSpecEnergy to 400
|
||||||
|
verify(notifier, never()).notify(any());
|
||||||
|
|
||||||
|
when(client.getVar(eq(VarPlayer.SPECIAL_ATTACK_PERCENT))).thenReturn(500); // 50%
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
verify(notifier).notify(eq("You have restored spec energy!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMovementIdle()
|
||||||
|
{
|
||||||
|
when(config.movementIdle()).thenReturn(true);
|
||||||
|
|
||||||
|
when(player.getWorldLocation()).thenReturn(new WorldPoint(0, 0, 0));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
when(player.getWorldLocation()).thenReturn(new WorldPoint(1, 0, 0));
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
// No movement here
|
||||||
|
plugin.onGameTick(new GameTick());
|
||||||
|
|
||||||
|
verify(notifier).notify(eq("You have stopped moving!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,6 +57,7 @@ import org.mockito.Mock;
|
|||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
@@ -67,7 +68,8 @@ public class ScreenshotPluginTest
|
|||||||
private static final String BARROWS_CHEST = "Your Barrows chest count is <col=ff0000>310</col>";
|
private static final String BARROWS_CHEST = "Your Barrows chest count is <col=ff0000>310</col>";
|
||||||
private static final String CHAMBERS_OF_XERIC_CHEST = "Your completed Chambers of Xeric count is: <col=ff0000>489</col>.";
|
private static final String CHAMBERS_OF_XERIC_CHEST = "Your completed Chambers of Xeric count is: <col=ff0000>489</col>.";
|
||||||
private static final String THEATRE_OF_BLOOD_CHEST = "Your completed Theatre of Blood count is: <col=ff0000>73</col>.";
|
private static final String THEATRE_OF_BLOOD_CHEST = "Your completed Theatre of Blood count is: <col=ff0000>73</col>.";
|
||||||
private static final String VALUABLE_DROP = "<col=ef1020>Valuable drop: 6 x Bronze arrow (42 coins)</col>";
|
private static final String NOT_SO_VALUABLE_DROP = "<col=ef1020>Valuable drop: 6 x Bronze arrow (42 coins)</col>";
|
||||||
|
private static final String VALUABLE_DROP = "<col=ef1020>Valuable drop: Rune scimitar (25,600 coins)</col>";
|
||||||
private static final String UNTRADEABLE_DROP = "<col=ef1020>Untradeable drop: Rusty sword";
|
private static final String UNTRADEABLE_DROP = "<col=ef1020>Untradeable drop: Rusty sword";
|
||||||
private static final String BA_HIGH_GAMBLE_REWARD = "Raw shark (x 300)!<br>High level gamble count: <col=7f0000>100</col>";
|
private static final String BA_HIGH_GAMBLE_REWARD = "Raw shark (x 300)!<br>High level gamble count: <col=7f0000>100</col>";
|
||||||
private static final String HUNTER_LEVEL_2_TEXT = "<col=000080>Congratulations, you've just advanced a Hunter level.<col=000000><br><br>Your Hunter level is now 2.";
|
private static final String HUNTER_LEVEL_2_TEXT = "<col=000080>Congratulations, you've just advanced a Hunter level.<col=000000><br><br>Your Hunter level is now 2.";
|
||||||
@@ -121,6 +123,7 @@ public class ScreenshotPluginTest
|
|||||||
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||||
when(screenshotConfig.screenshotLevels()).thenReturn(true);
|
when(screenshotConfig.screenshotLevels()).thenReturn(true);
|
||||||
when(screenshotConfig.screenshotValuableDrop()).thenReturn(true);
|
when(screenshotConfig.screenshotValuableDrop()).thenReturn(true);
|
||||||
|
when(screenshotConfig.valuableDropThreshold()).thenReturn(1000);
|
||||||
when(screenshotConfig.screenshotUntradeableDrop()).thenReturn(true);
|
when(screenshotConfig.screenshotUntradeableDrop()).thenReturn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,10 +164,30 @@ public class ScreenshotPluginTest
|
|||||||
assertEquals(73, screenshotPlugin.gettheatreOfBloodNumber());
|
assertEquals(73, screenshotPlugin.gettheatreOfBloodNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotSoValuableDrop()
|
||||||
|
{
|
||||||
|
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", NOT_SO_VALUABLE_DROP, null, 0);
|
||||||
|
screenshotPlugin.onChatMessage(chatMessageEvent);
|
||||||
|
|
||||||
|
verifyNoInteractions(drawManager);
|
||||||
|
|
||||||
|
when(screenshotConfig.valuableDropThreshold()).thenReturn(0);
|
||||||
|
screenshotPlugin.onChatMessage(chatMessageEvent);
|
||||||
|
|
||||||
|
verify(drawManager).requestNextFrameListener(any(Consumer.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValuableDrop()
|
public void testValuableDrop()
|
||||||
{
|
{
|
||||||
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", VALUABLE_DROP, null, 0);
|
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", VALUABLE_DROP, null, 0);
|
||||||
|
when(screenshotConfig.valuableDropThreshold()).thenReturn(100_000);
|
||||||
|
screenshotPlugin.onChatMessage(chatMessageEvent);
|
||||||
|
|
||||||
|
verifyNoInteractions(drawManager);
|
||||||
|
|
||||||
|
when(screenshotConfig.valuableDropThreshold()).thenReturn(1000);
|
||||||
screenshotPlugin.onChatMessage(chatMessageEvent);
|
screenshotPlugin.onChatMessage(chatMessageEvent);
|
||||||
|
|
||||||
verify(drawManager).requestNextFrameListener(any(Consumer.class));
|
verify(drawManager).requestNextFrameListener(any(Consumer.class));
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||||
|
* 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.timetracking.farming;
|
||||||
|
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.testing.fieldbinder.Bind;
|
||||||
|
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.GameState;
|
||||||
|
import net.runelite.api.Player;
|
||||||
|
import net.runelite.api.Varbits;
|
||||||
|
import net.runelite.api.WorldType;
|
||||||
|
import net.runelite.client.Notifier;
|
||||||
|
import net.runelite.client.config.ConfigManager;
|
||||||
|
import net.runelite.client.config.RuneScapeProfile;
|
||||||
|
import net.runelite.client.config.RuneScapeProfileType;
|
||||||
|
import net.runelite.client.game.ItemManager;
|
||||||
|
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class FarmingTrackerTest
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
private FarmingTracker farmingTracker;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private ItemManager itemManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private ConfigManager configManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private TimeTrackingConfig config;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private FarmingWorld farmingWorld;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Notifier notifier;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before()
|
||||||
|
{
|
||||||
|
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||||
|
|
||||||
|
when(client.getGameState()).thenReturn(GameState.LOGGED_IN);
|
||||||
|
when(client.getWorldType()).thenReturn(EnumSet.noneOf(WorldType.class));
|
||||||
|
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
when(player.getName()).thenReturn("Adam");
|
||||||
|
when(client.getLocalPlayer()).thenReturn(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testEmptyNotification()
|
||||||
|
{
|
||||||
|
RuneScapeProfile runeScapeProfile = new RuneScapeProfile("Adam", RuneScapeProfileType.STANDARD, null, null);
|
||||||
|
|
||||||
|
PatchPrediction patchPrediction = new PatchPrediction(Produce.EMPTY_COMPOST_BIN, CropState.EMPTY, 0L, 0, 0);
|
||||||
|
FarmingRegion region = new FarmingRegion("Ardougne", 10548, false,
|
||||||
|
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
|
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||||
|
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||||
|
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB),
|
||||||
|
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST)
|
||||||
|
);
|
||||||
|
FarmingPatch patch = region.getPatches()[4];
|
||||||
|
patch.setRegion(region);
|
||||||
|
farmingTracker.sendNotification(runeScapeProfile, patchPrediction, patch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHarvestableNotification()
|
||||||
|
{
|
||||||
|
RuneScapeProfile runeScapeProfile = new RuneScapeProfile("Adam", RuneScapeProfileType.STANDARD, null, null);
|
||||||
|
|
||||||
|
PatchPrediction patchPrediction = new PatchPrediction(Produce.RANARR, CropState.HARVESTABLE, 0L, 0, 0);
|
||||||
|
FarmingRegion region = new FarmingRegion("Ardougne", 10548, false,
|
||||||
|
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||||
|
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||||
|
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||||
|
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB),
|
||||||
|
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST)
|
||||||
|
);
|
||||||
|
FarmingPatch patch = region.getPatches()[3];
|
||||||
|
patch.setRegion(region);
|
||||||
|
farmingTracker.sendNotification(runeScapeProfile, patchPrediction, patch);
|
||||||
|
|
||||||
|
verify(notifier).notify("Your Ranarr is ready to harvest in Ardougne.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -536,17 +536,36 @@ public abstract class RSClientMixin implements RSClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void addChatMessage(int type, String name, String message, String sender)
|
public MessageNode addChatMessage(ChatMessageType type, String name, String message, String sender, boolean postEvent)
|
||||||
{
|
{
|
||||||
assert this.isClientThread() : "addChatMessage must be called on client thread";
|
assert this.isClientThread() : "addChatMessage must be called on client thread";
|
||||||
addRSChatMessage(type, name, message, sender);
|
copy$addChatMessage(type.getType(), name, message, sender);
|
||||||
|
|
||||||
|
Logger logger = client.getLogger();
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Chat message type {}: {}", type.name(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the message node which was added
|
||||||
|
@SuppressWarnings("unchecked") Map<Integer, RSChatChannel> chatLineMap = client.getChatLineMap();
|
||||||
|
RSChatChannel chatLineBuffer = chatLineMap.get(type.getType());
|
||||||
|
MessageNode messageNode = chatLineBuffer.getLines()[0];
|
||||||
|
|
||||||
|
if (postEvent)
|
||||||
|
{
|
||||||
|
final ChatMessage chatMessage = new ChatMessage(messageNode, type, name, message, sender, messageNode.getTimestamp());
|
||||||
|
client.getCallbacks().post(chatMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@Override
|
@Override
|
||||||
public void addChatMessage(ChatMessageType type, String name, String message, String sender)
|
public MessageNode addChatMessage(ChatMessageType type, String name, String message, String sender)
|
||||||
{
|
{
|
||||||
addChatMessage(type.getType(), name, message, sender);
|
return addChatMessage(type, name, message, sender, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -1484,14 +1503,17 @@ public abstract class RSClientMixin implements RSClient
|
|||||||
client.getCallbacks().updateNpcs();
|
client.getCallbacks().updateNpcs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Copy("addChatMessage")
|
||||||
@MethodHook(value = "addChatMessage", end = true)
|
@Replace("addChatMessage")
|
||||||
public static void onAddChatMessage(int type, String name, String message, String sender)
|
public static void copy$addChatMessage(int type, String name, String message, String sender)
|
||||||
{
|
{
|
||||||
|
copy$addChatMessage(type, name, message, sender);
|
||||||
|
|
||||||
Logger logger = client.getLogger();
|
Logger logger = client.getLogger();
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Chat message type {}: {}", ChatMessageType.of(type), message);
|
ChatMessageType msgType = ChatMessageType.of(type);
|
||||||
|
logger.debug("Chat message type {}: {}", msgType == ChatMessageType.UNKNOWN ? String.valueOf(type) : msgType.name(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the message node which was added
|
// Get the message node which was added
|
||||||
|
|||||||
Reference in New Issue
Block a user