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:
@@ -59,6 +59,7 @@ import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.client.chat.ChatColorType;
|
||||
import net.runelite.client.chat.ChatMessageBuilder;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
@@ -175,7 +176,7 @@ public class Notifier
|
||||
|
||||
if (runeLiteConfig.enableTrayNotifications())
|
||||
{
|
||||
sendNotification(appName, message, type);
|
||||
sendNotification(buildTitle(), message, type);
|
||||
}
|
||||
|
||||
switch (runeLiteConfig.notificationSound())
|
||||
@@ -210,6 +211,23 @@ public class Notifier
|
||||
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)
|
||||
{
|
||||
FlashNotification flashNotification = runeLiteConfig.flashNotification();
|
||||
|
||||
@@ -106,11 +106,6 @@ public class ChatCommandManager implements ChatboxInputListener
|
||||
String message = chatMessage.getMessage();
|
||||
|
||||
String command = extractCommand(message);
|
||||
if (command == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
||||
if (chatCommand == null)
|
||||
{
|
||||
@@ -137,11 +132,6 @@ public class ChatCommandManager implements ChatboxInputListener
|
||||
}
|
||||
|
||||
String command = extractCommand(message);
|
||||
if (command == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
||||
if (chatCommand == null)
|
||||
{
|
||||
@@ -163,11 +153,6 @@ public class ChatCommandManager implements ChatboxInputListener
|
||||
final String message = privateMessageInput.getMessage();
|
||||
|
||||
String command = extractCommand(message);
|
||||
if (command == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
||||
if (chatCommand == null)
|
||||
{
|
||||
|
||||
@@ -39,22 +39,22 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import net.runelite.api.ChatLineBuffer;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.MessageNode;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.api.events.ResizeableChanged;
|
||||
import net.runelite.api.events.ScriptCallbackEvent;
|
||||
import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ChatColorConfig;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.client.ui.JagexColors;
|
||||
import net.runelite.client.util.ColorUtil;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@Singleton
|
||||
public class ChatMessageManager
|
||||
@@ -126,7 +126,8 @@ public class ChatMessageManager
|
||||
case PUBLICCHAT:
|
||||
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)
|
||||
{
|
||||
@@ -571,18 +572,15 @@ public class ChatMessageManager
|
||||
return;
|
||||
}
|
||||
|
||||
final String formattedMessage = formatRuneLiteMessage(message.getRuneLiteFormattedMessage(), message.getType());
|
||||
|
||||
// this updates chat cycle
|
||||
client.addChatMessage(
|
||||
final MessageNode line = client.addChatMessage(
|
||||
message.getType(),
|
||||
MoreObjects.firstNonNull(message.getName(), ""),
|
||||
MoreObjects.firstNonNull(message.getValue(), message.getRuneLiteFormattedMessage()),
|
||||
MoreObjects.firstNonNull(formattedMessage, message.getValue()),
|
||||
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
|
||||
line.setRuneLiteFormatMessage(message.getRuneLiteFormattedMessage());
|
||||
|
||||
@@ -590,34 +588,38 @@ public class ChatMessageManager
|
||||
{
|
||||
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 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())
|
||||
{
|
||||
target.setValue(target.getRuneLiteFormatMessage());
|
||||
return;
|
||||
return runeLiteFormatMessage;
|
||||
}
|
||||
|
||||
target.setValue(recolorMessage(transparent, target.getRuneLiteFormatMessage(), target.getType()));
|
||||
}
|
||||
|
||||
private String recolorMessage(boolean transparent, String message, ChatMessageType messageType)
|
||||
{
|
||||
final Collection<ChatColor> chatColors = colorCache.get(messageType);
|
||||
final AtomicReference<String> resultMessage = new AtomicReference<>(message);
|
||||
final AtomicReference<String> resultMessage = new AtomicReference<>(runeLiteFormatMessage);
|
||||
|
||||
// Replace custom formatting with actual colors
|
||||
chatColors.stream()
|
||||
|
||||
@@ -152,6 +152,11 @@ public class ConfigManager
|
||||
scheduledExecutorService.scheduleWithFixedDelay(this::sendConfig, 30, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public String getRSProfileKey()
|
||||
{
|
||||
return rsProfileKey;
|
||||
}
|
||||
|
||||
public final void switchSession(AccountSession session)
|
||||
{
|
||||
// Ensure existing config is saved
|
||||
@@ -507,6 +512,11 @@ public class ConfigManager
|
||||
|
||||
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 + ".");
|
||||
String wholeKey = getWholeKey(groupName, profile, key);
|
||||
String oldValue = (String) properties.setProperty(wholeKey, value);
|
||||
|
||||
@@ -29,6 +29,9 @@ import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.ItemID;
|
||||
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_1498;
|
||||
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_1544, FISHING_SPOT_3913, FISHING_SPOT_7155,
|
||||
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,
|
||||
FISHING_SPOT_1510, FISHING_SPOT_1519, FISHING_SPOT_1522,
|
||||
FISHING_SPOT_3914, FISHING_SPOT_5820, FISHING_SPOT_7199,
|
||||
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,
|
||||
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_7200, FISHING_SPOT_7461, FISHING_SPOT_7466,
|
||||
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,
|
||||
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.MouseWheelListener;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDependency;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.banktags.tabs.TabInterface;
|
||||
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.TagTab;
|
||||
import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@PluginDescriptor(
|
||||
@@ -89,7 +87,6 @@ import net.runelite.client.util.Text;
|
||||
description = "Enable tagging of bank items and searching of bank tags",
|
||||
tags = {"searching", "tagging"}
|
||||
)
|
||||
@PluginDependency(ClueScrollPlugin.class)
|
||||
public class BankTagsPlugin extends Plugin implements MouseWheelListener
|
||||
{
|
||||
public static final String CONFIG_GROUP = "banktags";
|
||||
|
||||
@@ -27,24 +27,17 @@ package net.runelite.client.plugins.banktags;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.ItemVariationMapping;
|
||||
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;
|
||||
|
||||
@Singleton
|
||||
@@ -53,17 +46,15 @@ public class TagManager
|
||||
static final String ITEM_KEY_PREFIX = "item_";
|
||||
private final ConfigManager configManager;
|
||||
private final ItemManager itemManager;
|
||||
private final ClueScrollService clueScrollService;
|
||||
private final Map<String, BankTag> customTags = new HashMap<>();
|
||||
|
||||
@Inject
|
||||
private TagManager(
|
||||
final ItemManager itemManager,
|
||||
final ConfigManager configManager,
|
||||
final ClueScrollService clueScrollService)
|
||||
final ConfigManager configManager)
|
||||
{
|
||||
this.itemManager = itemManager;
|
||||
this.configManager = configManager;
|
||||
this.clueScrollService = clueScrollService;
|
||||
}
|
||||
|
||||
String getTagString(int itemId, boolean variation)
|
||||
@@ -123,7 +114,8 @@ public class TagManager
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -194,38 +186,13 @@ public class TagManager
|
||||
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)
|
||||
{
|
||||
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;
|
||||
public void unregisterTag(String name)
|
||||
{
|
||||
customTags.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,8 @@ public class CannonPlugin extends Plugin
|
||||
}
|
||||
|
||||
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;
|
||||
cballsLeft = 0;
|
||||
|
||||
@@ -49,7 +49,7 @@ enum CannonSpots
|
||||
DUST_DEVIL(new WorldPoint(3218, 9366, 0)),
|
||||
EARTH_WARRIOR(new WorldPoint(3120, 9987, 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)),
|
||||
GREATER_DEMONS(new WorldPoint(1435, 10086, 2), new WorldPoint(3224, 10132, 0)),
|
||||
GREEN_DRAGON(new WorldPoint(3225, 10068, 0)),
|
||||
|
||||
@@ -666,7 +666,7 @@ public class ChatCommandsPlugin extends Plugin
|
||||
.append(ChatColorType.NORMAL)
|
||||
.append(" kill count: ")
|
||||
.append(ChatColorType.HIGHLIGHT)
|
||||
.append(Integer.toString(kc))
|
||||
.append(String.format("%,d", kc))
|
||||
.build();
|
||||
|
||||
log.debug("Setting response {}", response);
|
||||
@@ -748,15 +748,15 @@ public class ChatCommandsPlugin extends Plugin
|
||||
.append(ChatColorType.NORMAL)
|
||||
.append("Duel Arena wins: ")
|
||||
.append(ChatColorType.HIGHLIGHT)
|
||||
.append(Integer.toString(wins))
|
||||
.append(String.format("%,d", wins))
|
||||
.append(ChatColorType.NORMAL)
|
||||
.append(" losses: ")
|
||||
.append(ChatColorType.HIGHLIGHT)
|
||||
.append(Integer.toString(losses))
|
||||
.append(String.format("%,d", losses))
|
||||
.append(ChatColorType.NORMAL)
|
||||
.append(" streak: ")
|
||||
.append(ChatColorType.HIGHLIGHT)
|
||||
.append(Integer.toString((winningStreak != 0 ? winningStreak : -losingStreak)))
|
||||
.append(String.format("%,d", winningStreak != 0 ? winningStreak : -losingStreak))
|
||||
.build();
|
||||
|
||||
log.debug("Setting response {}", response);
|
||||
@@ -957,7 +957,7 @@ public class ChatCommandsPlugin extends Plugin
|
||||
.append(ChatColorType.NORMAL)
|
||||
.append("Barbarian Assault High-level gambles: ")
|
||||
.append(ChatColorType.HIGHLIGHT)
|
||||
.append(Integer.toString(gc))
|
||||
.append(String.format("%,d", gc))
|
||||
.build();
|
||||
|
||||
log.debug("Setting response {}", response);
|
||||
@@ -1420,7 +1420,7 @@ public class ChatCommandsPlugin extends Plugin
|
||||
.append(ChatColorType.NORMAL)
|
||||
.append("Clue scroll (" + level + ")").append(": ")
|
||||
.append(ChatColorType.HIGHLIGHT)
|
||||
.append(Integer.toString(quantity));
|
||||
.append(String.format("%,d", quantity));
|
||||
|
||||
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_GROUP;
|
||||
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.eventbus.Subscribe;
|
||||
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 FRIENDS_MAX_SIZE = 5;
|
||||
|
||||
private Queue<QueuedMessage> messageQueue;
|
||||
private Queue<MessageNode> messageQueue;
|
||||
private Deque<String> friends;
|
||||
|
||||
private String currentMessage = null;
|
||||
@@ -99,9 +97,6 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
@Inject
|
||||
private KeyManager keyManager;
|
||||
|
||||
@Inject
|
||||
private ChatMessageManager chatMessageManager;
|
||||
|
||||
@Provides
|
||||
ChatHistoryConfig getConfig(ConfigManager configManager)
|
||||
{
|
||||
@@ -111,6 +106,9 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
@Override
|
||||
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);
|
||||
friends = new ArrayDeque<>(FRIENDS_MAX_SIZE + 1);
|
||||
keyManager.registerKeyListener(this);
|
||||
@@ -140,11 +138,16 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
return;
|
||||
}
|
||||
|
||||
QueuedMessage queuedMessage;
|
||||
|
||||
while ((queuedMessage = messageQueue.poll()) != null)
|
||||
for (MessageNode queuedMessage : messageQueue)
|
||||
{
|
||||
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;
|
||||
@@ -171,19 +174,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
case MODCHAT:
|
||||
case FRIENDSCHAT:
|
||||
case CONSOLE:
|
||||
final QueuedMessage queuedMessage = QueuedMessage.builder()
|
||||
.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);
|
||||
}
|
||||
messageQueue.offer(chatMessage.getMessageNode());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,21 +339,6 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
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
|
||||
public void keyPressed(KeyEvent e)
|
||||
{
|
||||
|
||||
@@ -108,4 +108,15 @@ public interface ChatNotificationsConfig extends Config
|
||||
{
|
||||
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));
|
||||
}
|
||||
break;
|
||||
case PRIVATECHAT:
|
||||
case MODPRIVATECHAT:
|
||||
if (config.notifyOnPM())
|
||||
{
|
||||
notifier.notify(Text.removeTags(chatMessage.getName()) + ": " + chatMessage.getMessage());
|
||||
}
|
||||
break;
|
||||
case CONSOLE:
|
||||
// Don't notify for notification messages
|
||||
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.game.ItemManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDependency;
|
||||
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.BeginnerMapClue;
|
||||
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.TextClueScroll;
|
||||
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.OverlayMenuEntry;
|
||||
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",
|
||||
tags = {"arrow", "hints", "world", "map", "coordinates", "emotes"}
|
||||
)
|
||||
@PluginDependency(BankTagsPlugin.class)
|
||||
@Slf4j
|
||||
public class ClueScrollPlugin extends Plugin
|
||||
{
|
||||
@@ -144,6 +149,7 @@ public class ClueScrollPlugin extends Plugin
|
||||
13150, 9011,
|
||||
13151, 9012
|
||||
};
|
||||
private static final String CLUE_TAG_NAME = "clue";
|
||||
|
||||
@Getter
|
||||
private ClueScroll clue;
|
||||
@@ -191,6 +197,9 @@ public class ClueScrollPlugin extends Plugin
|
||||
@Inject
|
||||
private WorldMapPointManager worldMapPointManager;
|
||||
|
||||
@Inject
|
||||
private TagManager tagManager;
|
||||
|
||||
@Inject
|
||||
@Named("developerMode")
|
||||
boolean developerMode;
|
||||
@@ -227,11 +236,13 @@ public class ClueScrollPlugin extends Plugin
|
||||
overlayManager.add(clueScrollEmoteOverlay);
|
||||
overlayManager.add(clueScrollWorldOverlay);
|
||||
overlayManager.add(clueScrollMusicOverlay);
|
||||
tagManager.registerTag(CLUE_TAG_NAME, this::testClueTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
tagManager.unregisterTag(CLUE_TAG_NAME);
|
||||
overlayManager.remove(clueScrollOverlay);
|
||||
overlayManager.remove(clueScrollEmoteOverlay);
|
||||
overlayManager.remove(clueScrollWorldOverlay);
|
||||
@@ -484,6 +495,10 @@ public class ClueScrollPlugin extends Plugin
|
||||
{
|
||||
resetClue(true);
|
||||
}
|
||||
else if (state == GameState.HOPPING)
|
||||
{
|
||||
namedObjectCheckThisTick = true;
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
// or upon reaching a logged in state after hopping worlds
|
||||
if (namedObjectCheckThisTick)
|
||||
{
|
||||
namedObjectCheckThisTick = false;
|
||||
@@ -569,7 +585,7 @@ public class ClueScrollPlugin extends Plugin
|
||||
if (chatDialogClueItem != null
|
||||
&& (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);
|
||||
@@ -1109,4 +1125,38 @@ public class ClueScrollPlugin extends Plugin
|
||||
}
|
||||
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(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(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
|
||||
.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))
|
||||
@@ -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(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(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(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))
|
||||
|
||||
@@ -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_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"),
|
||||
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_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),
|
||||
@@ -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_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_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_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),
|
||||
|
||||
@@ -43,8 +43,6 @@ import net.runelite.api.Constants;
|
||||
import net.runelite.api.DecorativeObject;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.GraphicsObject;
|
||||
import net.runelite.api.TileItem;
|
||||
import net.runelite.api.GroundObject;
|
||||
import net.runelite.api.ItemLayer;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.NPCComposition;
|
||||
@@ -55,7 +53,8 @@ import net.runelite.api.Point;
|
||||
import net.runelite.api.Projectile;
|
||||
import net.runelite.api.Scene;
|
||||
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.widgets.Widget;
|
||||
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() + ")";
|
||||
OverlayUtil.renderActorOverlay(graphics, local, text, CYAN);
|
||||
renderPlayerWireframe(graphics, local, CYAN);
|
||||
}
|
||||
|
||||
private void renderNpcs(Graphics2D graphics)
|
||||
@@ -214,7 +212,7 @@ class DevToolsOverlay extends Overlay
|
||||
|
||||
if (plugin.getGroundObjects().isActive())
|
||||
{
|
||||
renderGroundObject(graphics, tile, player);
|
||||
renderTileObject(graphics, tile.getGroundObject(), player, PURPLE);
|
||||
}
|
||||
|
||||
if (plugin.getGameObjects().isActive())
|
||||
@@ -224,7 +222,7 @@ class DevToolsOverlay extends Overlay
|
||||
|
||||
if (plugin.getWalls().isActive())
|
||||
{
|
||||
renderWallObject(graphics, tile, player);
|
||||
renderTileObject(graphics, tile.getWallObject(), player, GRAY);
|
||||
}
|
||||
|
||||
if (plugin.getDecorations().isActive())
|
||||
@@ -309,45 +307,21 @@ class DevToolsOverlay extends Overlay
|
||||
{
|
||||
for (GameObject gameObject : gameObjects)
|
||||
{
|
||||
if (gameObject != null)
|
||||
if (gameObject != null && gameObject.getSceneMinLocation().equals(tile.getSceneLocation()))
|
||||
{
|
||||
if (player.getLocalLocation().distanceTo(gameObject.getLocalLocation()) <= MAX_DISTANCE)
|
||||
{
|
||||
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);
|
||||
}
|
||||
renderTileObject(graphics, gameObject, player, GREEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (groundObject != null)
|
||||
if (tileObject != 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
OverlayUtil.renderTileOverlay(graphics, tileObject, "ID: " + tileObject.getId(), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.api.Varbits;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@@ -187,6 +183,7 @@ enum DiscordGameEventType
|
||||
DUNGEON_CRABCLAW_CAVES("Crabclaw Caves", DiscordAreaType.DUNGEONS, 6553, 6809),
|
||||
DUNGEON_CRANDOR("Crandor Dungeon", DiscordAreaType.DUNGEONS, 11414),
|
||||
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_DIGSITE("Digsite Dungeon", DiscordAreaType.DUNGEONS, 13464, 13465),
|
||||
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_HEROES_GUILD("Heroes' Guild Mine", DiscordAreaType.DUNGEONS, 11674),
|
||||
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_JIGGIG_BURIAL_TOMB("Jiggig Burial Tomb", DiscordAreaType.DUNGEONS, 9875, 9874),
|
||||
DUNGEON_JOGRE("Jogre Dungeon", DiscordAreaType.DUNGEONS, 11412),
|
||||
@@ -307,8 +305,8 @@ enum DiscordGameEventType
|
||||
MG_VOLCANIC_MINE("Volcanic Mine", DiscordAreaType.MINIGAMES, 15263, 15262),
|
||||
|
||||
// Raids
|
||||
RAIDS_CHAMBERS_OF_XERIC("Chambers of Xeric", DiscordAreaType.RAIDS, Varbits.IN_RAID),
|
||||
RAIDS_THEATRE_OF_BLOOD("Theatre of Blood", DiscordAreaType.RAIDS, Varbits.THEATRE_OF_BLOOD),
|
||||
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, 12611, 12612, 12613, 12867, 12869, 13122, 13123, 13125, 13379),
|
||||
|
||||
// Other
|
||||
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_ISAFDAR("Isafdar", DiscordAreaType.REGIONS, 8497, 8753, 8754, 9009, 9010),
|
||||
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_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),
|
||||
@@ -430,20 +429,12 @@ enum DiscordGameEventType
|
||||
REGION_WRATH_ALTAR("Wrath Altar", DiscordAreaType.REGIONS, 9291);
|
||||
|
||||
private static final Map<Integer, DiscordGameEventType> FROM_REGION;
|
||||
private static final List<DiscordGameEventType> FROM_VARBITS;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<Integer, DiscordGameEventType> regionMapBuilder = new ImmutableMap.Builder<>();
|
||||
ImmutableList.Builder<DiscordGameEventType> fromVarbitsBuilder = ImmutableList.builder();
|
||||
for (DiscordGameEventType discordGameEventType : DiscordGameEventType.values())
|
||||
{
|
||||
if (discordGameEventType.getVarbits() != null)
|
||||
{
|
||||
fromVarbitsBuilder.add(discordGameEventType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (discordGameEventType.getRegionIds() == null)
|
||||
{
|
||||
continue;
|
||||
@@ -455,7 +446,6 @@ enum DiscordGameEventType
|
||||
}
|
||||
}
|
||||
FROM_REGION = regionMapBuilder.build();
|
||||
FROM_VARBITS = fromVarbitsBuilder.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -497,9 +487,6 @@ enum DiscordGameEventType
|
||||
@Nullable
|
||||
private DiscordAreaType discordAreaType;
|
||||
|
||||
@Nullable
|
||||
private Varbits varbits;
|
||||
|
||||
@Nullable
|
||||
private int[] regionIds;
|
||||
|
||||
@@ -541,15 +528,6 @@ enum DiscordGameEventType
|
||||
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)
|
||||
{
|
||||
return training(skill.getName());
|
||||
@@ -609,17 +587,4 @@ enum DiscordGameEventType
|
||||
{
|
||||
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.events.GameStateChanged;
|
||||
import net.runelite.api.events.StatChanged;
|
||||
import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.discord.DiscordService;
|
||||
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
|
||||
public void onDiscordReady(DiscordReady event)
|
||||
{
|
||||
@@ -447,6 +430,7 @@ public class DiscordPlugin extends Plugin
|
||||
case DUNGEONS: return config.showDungeonActivity();
|
||||
case MINIGAMES: return config.showMinigameActivity();
|
||||
case REGIONS: return config.showRegionsActivity();
|
||||
case RAIDS: return config.showRaidingActivity();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -91,6 +91,8 @@ enum Emoji
|
||||
GORILLA(":G"),
|
||||
PLEADING("(n_n)"),
|
||||
XD("Xd"),
|
||||
SPOON("--o"),
|
||||
WEARY_FACE("Dx"),
|
||||
;
|
||||
|
||||
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.OverheadTextChanged;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
@@ -63,9 +62,6 @@ public class EmojiPlugin extends Plugin
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private ChatMessageManager chatMessageManager;
|
||||
|
||||
private int modIconsStart = -1;
|
||||
|
||||
@Override
|
||||
@@ -145,9 +141,7 @@ public class EmojiPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
messageNode.setRuneLiteFormatMessage(updatedMessage);
|
||||
chatMessageManager.update(messageNode);
|
||||
client.refreshChat();
|
||||
messageNode.setValue(updatedMessage);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
||||
@@ -29,16 +29,18 @@ import net.runelite.client.config.Config;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
|
||||
@ConfigGroup("entityhider")
|
||||
@ConfigGroup(EntityHiderConfig.GROUP)
|
||||
public interface EntityHiderConfig extends Config
|
||||
{
|
||||
String GROUP = "entityhider";
|
||||
|
||||
@ConfigItem(
|
||||
position = 1,
|
||||
keyName = "hidePlayers",
|
||||
name = "Hide Players",
|
||||
description = "Configures whether or not players are hidden"
|
||||
name = "Hide Others",
|
||||
description = "Configures whether or not other players are hidden"
|
||||
)
|
||||
default boolean hidePlayers()
|
||||
default boolean hideOthers()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -46,10 +48,10 @@ public interface EntityHiderConfig extends Config
|
||||
@ConfigItem(
|
||||
position = 2,
|
||||
keyName = "hidePlayers2D",
|
||||
name = "Hide Players 2D",
|
||||
description = "Configures whether or not players 2D elements are hidden"
|
||||
name = "Hide Others 2D",
|
||||
description = "Configures whether or not other players 2D elements are hidden"
|
||||
)
|
||||
default boolean hidePlayers2D()
|
||||
default boolean hideOthers2D()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -78,6 +80,17 @@ public interface EntityHiderConfig extends Config
|
||||
|
||||
@ConfigItem(
|
||||
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",
|
||||
name = "Hide Local Player",
|
||||
description = "Configures whether or not the local player is hidden"
|
||||
@@ -88,7 +101,7 @@ public interface EntityHiderConfig extends Config
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 6,
|
||||
position = 7,
|
||||
keyName = "hideLocalPlayer2D",
|
||||
name = "Hide Local Player 2D",
|
||||
description = "Configures whether or not the local player's 2D elements are hidden"
|
||||
@@ -99,7 +112,7 @@ public interface EntityHiderConfig extends Config
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 7,
|
||||
position = 8,
|
||||
keyName = "hideNPCs",
|
||||
name = "Hide NPCs",
|
||||
description = "Configures whether or not NPCs are hidden"
|
||||
@@ -110,7 +123,7 @@ public interface EntityHiderConfig extends Config
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 8,
|
||||
position = 9,
|
||||
keyName = "hideNPCs2D",
|
||||
name = "Hide NPCs 2D",
|
||||
description = "Configures whether or not NPCs 2D elements are hidden"
|
||||
@@ -121,7 +134,7 @@ public interface EntityHiderConfig extends Config
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 9,
|
||||
position = 10,
|
||||
keyName = "hidePets",
|
||||
name = "Hide Pets",
|
||||
description = "Configures whether or not other player pets are hidden"
|
||||
@@ -132,7 +145,7 @@ public interface EntityHiderConfig extends Config
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 10,
|
||||
position = 11,
|
||||
keyName = "hideAttackers",
|
||||
name = "Hide Attackers",
|
||||
description = "Configures whether or not NPCs/players attacking you are hidden"
|
||||
@@ -143,7 +156,7 @@ public interface EntityHiderConfig extends Config
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 11,
|
||||
position = 12,
|
||||
keyName = "hideProjectiles",
|
||||
name = "Hide Projectiles",
|
||||
description = "Configures whether or not projectiles are hidden"
|
||||
|
||||
@@ -28,13 +28,9 @@ package net.runelite.client.plugins.entityhider;
|
||||
import com.google.inject.Provides;
|
||||
import javax.inject.Inject;
|
||||
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.eventbus.Subscribe;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
|
||||
@@ -67,27 +63,22 @@ public class EntityHiderPlugin extends Plugin
|
||||
@Subscribe
|
||||
public void onConfigChanged(ConfigChanged e)
|
||||
{
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged event)
|
||||
{
|
||||
if (event.getGameState() == GameState.LOGGED_IN)
|
||||
if (e.getGroup().equals(EntityHiderConfig.GROUP))
|
||||
{
|
||||
client.setIsHidingEntities(isPlayerRegionAllowed());
|
||||
updateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateConfig()
|
||||
{
|
||||
client.setIsHidingEntities(isPlayerRegionAllowed());
|
||||
client.setIsHidingEntities(true);
|
||||
|
||||
client.setPlayersHidden(config.hidePlayers());
|
||||
client.setPlayersHidden2D(config.hidePlayers2D());
|
||||
client.setOthersHidden(config.hideOthers());
|
||||
client.setOthersHidden2D(config.hideOthers2D());
|
||||
|
||||
client.setFriendsHidden(config.hideFriends());
|
||||
client.setFriendsChatMembersHidden(config.hideFriendsChatMembers());
|
||||
client.setIgnoresHidden(config.hideIgnores());
|
||||
|
||||
client.setLocalPlayerHidden(config.hideLocalPlayer());
|
||||
client.setLocalPlayerHidden2D(config.hideLocalPlayer2D());
|
||||
@@ -107,11 +98,12 @@ public class EntityHiderPlugin extends Plugin
|
||||
{
|
||||
client.setIsHidingEntities(false);
|
||||
|
||||
client.setPlayersHidden(false);
|
||||
client.setPlayersHidden2D(false);
|
||||
client.setOthersHidden(false);
|
||||
client.setOthersHidden2D(false);
|
||||
|
||||
client.setFriendsHidden(false);
|
||||
client.setFriendsChatMembersHidden(false);
|
||||
client.setIgnoresHidden(false);
|
||||
|
||||
client.setLocalPlayerHidden(false);
|
||||
client.setLocalPlayerHidden2D(false);
|
||||
@@ -125,19 +117,4 @@ public class EntityHiderPlugin extends Plugin
|
||||
|
||||
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(
|
||||
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",
|
||||
name = "Trawler activity notification",
|
||||
description = "Send a notification when fishing trawler activity drops below 15%."
|
||||
@@ -160,7 +171,7 @@ public interface FishingConfig extends Config
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 11,
|
||||
position = 12,
|
||||
keyName = "trawlerTimer",
|
||||
name = "Trawler timer in MM:SS",
|
||||
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);
|
||||
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
|
||||
@@ -372,7 +377,7 @@ public class FishingPlugin extends Plugin
|
||||
{
|
||||
if (!trawlerNotificationSent)
|
||||
{
|
||||
notifier.notify("[" + client.getLocalPlayer().getName() + "] has low Fishing Trawler activity!");
|
||||
notifier.notify("You have low Fishing Trawler activity!");
|
||||
trawlerNotificationSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,11 +411,7 @@ public class FriendsChatPlugin extends Plugin
|
||||
.append(textColor, member.getName() + activityMessage);
|
||||
|
||||
final String messageString = message.build();
|
||||
client.addChatMessage(ChatMessageType.FRIENDSCHATNOTIFICATION, "", messageString, "");
|
||||
|
||||
final ChatLineBuffer chatLineBuffer = client.getChatLineMap().get(ChatMessageType.FRIENDSCHATNOTIFICATION.getType());
|
||||
final MessageNode[] lines = chatLineBuffer.getLines();
|
||||
final MessageNode line = lines[0];
|
||||
final MessageNode line = client.addChatMessage(ChatMessageType.FRIENDSCHATNOTIFICATION, "", messageString, "");
|
||||
|
||||
MemberJoinMessage joinMessage = new MemberJoinMessage(line, line.getId(), client.getTickCount());
|
||||
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.JAWTWindow;
|
||||
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.GLCapabilities;
|
||||
import com.jogamp.opengl.GLContext;
|
||||
@@ -45,6 +50,7 @@ import java.awt.Image;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
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.ui.DrawManager;
|
||||
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(
|
||||
name = "GPU",
|
||||
@@ -105,8 +115,8 @@ import net.runelite.client.util.OSType;
|
||||
public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
{
|
||||
// This is the maximum number of triangles the compute shaders support
|
||||
private static final int MAX_TRIANGLE = 4096;
|
||||
private static final int SMALL_TRIANGLE_COUNT = 512;
|
||||
static final int MAX_TRIANGLE = 4096;
|
||||
static final int SMALL_TRIANGLE_COUNT = 512;
|
||||
private static final int FLAG_SCENE_BUFFER = Integer.MIN_VALUE;
|
||||
private static final int DEFAULT_DISTANCE = 25;
|
||||
static final int MAX_DISTANCE = 90;
|
||||
@@ -115,6 +125,9 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private OpenCLManager openCLManager;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@@ -133,7 +146,14 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
@Inject
|
||||
private PluginManager pluginManager;
|
||||
|
||||
private boolean useComputeShaders;
|
||||
enum ComputeMode
|
||||
{
|
||||
NONE,
|
||||
OPENGL,
|
||||
OPENCL
|
||||
}
|
||||
|
||||
private ComputeMode computeMode = ComputeMode.NONE;
|
||||
|
||||
private Canvas canvas;
|
||||
private JAWTWindow jawtWindow;
|
||||
@@ -182,23 +202,22 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
private int texSceneHandle;
|
||||
private int rboSceneHandle;
|
||||
|
||||
// scene vertex buffer id
|
||||
private int bufferId;
|
||||
// scene uv buffer id
|
||||
private int uvBufferId;
|
||||
// scene vertex buffer
|
||||
private final GLBuffer sceneVertexBuffer = new GLBuffer();
|
||||
// scene uv buffer
|
||||
private final GLBuffer sceneUvBuffer = new GLBuffer();
|
||||
|
||||
private int tmpBufferId; // temporary scene vertex buffer
|
||||
private int tmpUvBufferId; // temporary scene uv buffer
|
||||
private int tmpModelBufferId; // scene model buffer, large
|
||||
private int tmpModelBufferSmallId; // scene model buffer, small
|
||||
private int tmpModelBufferUnorderedId;
|
||||
private int tmpOutBufferId; // target vertex buffer for compute shaders
|
||||
private int tmpOutUvBufferId; // target uv buffer for compute shaders
|
||||
private final GLBuffer tmpVertexBuffer = new GLBuffer(); // temporary scene vertex buffer
|
||||
private final GLBuffer tmpUvBuffer = new GLBuffer(); // temporary scene uv buffer
|
||||
private final GLBuffer tmpModelBufferLarge = new GLBuffer(); // scene model buffer, large
|
||||
private final GLBuffer tmpModelBufferSmall = new GLBuffer(); // scene model buffer, small
|
||||
private final GLBuffer tmpModelBufferUnordered = new GLBuffer(); // scene model buffer, unordered
|
||||
private final GLBuffer tmpOutBuffer = new GLBuffer(); // target vertex buffer for compute shaders
|
||||
private final GLBuffer tmpOutUvBuffer = new GLBuffer(); // target uv buffer for compute shaders
|
||||
|
||||
private int textureArrayId;
|
||||
|
||||
private int uniformBufferId;
|
||||
private final IntBuffer uniformBuffer = GpuIntBuffer.allocateDirect(5 + 3 + 2048 * 4);
|
||||
private final GLBuffer uniformBuffer = new GLBuffer();
|
||||
private final float[] textureOffsets = new float[128];
|
||||
|
||||
private GpuIntBuffer vertexBuffer;
|
||||
@@ -278,7 +297,6 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
{
|
||||
try
|
||||
{
|
||||
bufferId = uvBufferId = uniformBufferId = tmpBufferId = tmpUvBufferId = tmpModelBufferId = tmpModelBufferSmallId = tmpModelBufferUnorderedId = tmpOutBufferId = tmpOutUvBufferId = -1;
|
||||
texSceneHandle = fboSceneHandle = rboSceneHandle = -1; // AA FBO
|
||||
unorderedModels = smallModels = largeModels = 0;
|
||||
drawingModel = false;
|
||||
@@ -290,8 +308,9 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
return false;
|
||||
}
|
||||
|
||||
// OSX supports up to OpenGL 4.1, however 4.3 is required for compute shaders
|
||||
useComputeShaders = config.useComputeShaders() && OSType.getOSType() != OSType.MacOS;
|
||||
computeMode = config.useComputeShaders()
|
||||
? (OSType.getOSType() == OSType.MacOS ? ComputeMode.OPENCL : ComputeMode.OPENGL)
|
||||
: ComputeMode.NONE;
|
||||
|
||||
canvas.setIgnoreRepaint(true);
|
||||
|
||||
@@ -397,7 +416,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
|
||||
if (client.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
uploadScene();
|
||||
invokeOnMainThread(this::uploadScene);
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
@@ -433,6 +452,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
|
||||
invokeOnMainThread(() ->
|
||||
{
|
||||
openCLManager.cleanup();
|
||||
|
||||
if (gl != null)
|
||||
{
|
||||
if (textureArrayId != -1)
|
||||
@@ -441,11 +462,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
textureArrayId = -1;
|
||||
}
|
||||
|
||||
if (uniformBufferId != -1)
|
||||
{
|
||||
glDeleteBuffer(gl, uniformBufferId);
|
||||
uniformBufferId = -1;
|
||||
}
|
||||
destroyGlBuffer(uniformBuffer);
|
||||
|
||||
shutdownBuffers();
|
||||
shutdownInterfaceTexture();
|
||||
@@ -519,12 +536,16 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
glProgram = PROGRAM.compile(gl, template);
|
||||
glUiProgram = UI_PROGRAM.compile(gl, template);
|
||||
|
||||
if (useComputeShaders)
|
||||
if (computeMode == ComputeMode.OPENGL)
|
||||
{
|
||||
glComputeProgram = COMPUTE_PROGRAM.compile(gl, template);
|
||||
glSmallComputeProgram = SMALL_COMPUTE_PROGRAM.compile(gl, template);
|
||||
glUnorderedComputeProgram = UNORDERED_COMPUTE_PROGRAM.compile(gl, template);
|
||||
}
|
||||
else if (computeMode == ComputeMode.OPENCL)
|
||||
{
|
||||
openCLManager.init(gl);
|
||||
}
|
||||
|
||||
initUniforms();
|
||||
}
|
||||
@@ -593,8 +614,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
-1f, 1f, 0.0f, 0.0f, 0f // top left
|
||||
});
|
||||
vboUiBuf.rewind();
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vboUiHandle);
|
||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, vboUiBuf.capacity() * Float.BYTES, vboUiBuf, gl.GL_STATIC_DRAW);
|
||||
gl.glBindBuffer(GL_ARRAY_BUFFER, vboUiHandle);
|
||||
gl.glBufferData(GL_ARRAY_BUFFER, vboUiBuf.capacity() * Float.BYTES, vboUiBuf, gl.GL_STATIC_DRAW);
|
||||
|
||||
// position attribute
|
||||
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);
|
||||
|
||||
// unbind VBO
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0);
|
||||
gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
private void shutdownVao()
|
||||
@@ -622,71 +643,49 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
|
||||
private void initBuffers()
|
||||
{
|
||||
bufferId = glGenBuffers(gl);
|
||||
uvBufferId = glGenBuffers(gl);
|
||||
tmpBufferId = glGenBuffers(gl);
|
||||
tmpUvBufferId = glGenBuffers(gl);
|
||||
tmpModelBufferId = glGenBuffers(gl);
|
||||
tmpModelBufferSmallId = glGenBuffers(gl);
|
||||
tmpModelBufferUnorderedId = glGenBuffers(gl);
|
||||
tmpOutBufferId = glGenBuffers(gl);
|
||||
tmpOutUvBufferId = glGenBuffers(gl);
|
||||
initGlBuffer(sceneVertexBuffer);
|
||||
initGlBuffer(sceneUvBuffer);
|
||||
initGlBuffer(tmpVertexBuffer);
|
||||
initGlBuffer(tmpUvBuffer);
|
||||
initGlBuffer(tmpModelBufferLarge);
|
||||
initGlBuffer(tmpModelBufferSmall);
|
||||
initGlBuffer(tmpModelBufferUnordered);
|
||||
initGlBuffer(tmpOutBuffer);
|
||||
initGlBuffer(tmpOutUvBuffer);
|
||||
}
|
||||
|
||||
private void initGlBuffer(GLBuffer glBuffer)
|
||||
{
|
||||
glBuffer.glBufferId = glGenBuffers(gl);
|
||||
}
|
||||
|
||||
private void shutdownBuffers()
|
||||
{
|
||||
if (bufferId != -1)
|
||||
{
|
||||
glDeleteBuffer(gl, bufferId);
|
||||
bufferId = -1;
|
||||
}
|
||||
destroyGlBuffer(sceneVertexBuffer);
|
||||
destroyGlBuffer(sceneUvBuffer);
|
||||
|
||||
if (uvBufferId != -1)
|
||||
{
|
||||
glDeleteBuffer(gl, uvBufferId);
|
||||
uvBufferId = -1;
|
||||
}
|
||||
destroyGlBuffer(tmpVertexBuffer);
|
||||
destroyGlBuffer(tmpUvBuffer);
|
||||
destroyGlBuffer(tmpModelBufferLarge);
|
||||
destroyGlBuffer(tmpModelBufferSmall);
|
||||
destroyGlBuffer(tmpModelBufferUnordered);
|
||||
destroyGlBuffer(tmpOutBuffer);
|
||||
destroyGlBuffer(tmpOutUvBuffer);
|
||||
}
|
||||
|
||||
if (tmpBufferId != -1)
|
||||
private void destroyGlBuffer(GLBuffer glBuffer)
|
||||
{
|
||||
if (glBuffer.glBufferId != -1)
|
||||
{
|
||||
glDeleteBuffer(gl, tmpBufferId);
|
||||
tmpBufferId = -1;
|
||||
glDeleteBuffer(gl, glBuffer.glBufferId);
|
||||
glBuffer.glBufferId = -1;
|
||||
}
|
||||
glBuffer.size = -1;
|
||||
|
||||
if (tmpUvBufferId != -1)
|
||||
if (glBuffer.cl_mem != null)
|
||||
{
|
||||
glDeleteBuffer(gl, tmpUvBufferId);
|
||||
tmpUvBufferId = -1;
|
||||
}
|
||||
|
||||
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;
|
||||
CL.clReleaseMemObject(glBuffer.cl_mem);
|
||||
glBuffer.cl_mem = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,21 +708,21 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
|
||||
private void initUniformBuffer()
|
||||
{
|
||||
uniformBufferId = glGenBuffers(gl);
|
||||
gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, uniformBufferId);
|
||||
uniformBuffer.clear();
|
||||
uniformBuffer.put(new int[8]);
|
||||
initGlBuffer(uniformBuffer);
|
||||
|
||||
IntBuffer uniformBuf = GpuIntBuffer.allocateDirect(8 + 2048 * 4);
|
||||
uniformBuf.put(new int[8]); // uniform block
|
||||
final int[] pad = new int[2];
|
||||
for (int i = 0; i < 2048; i++)
|
||||
{
|
||||
uniformBuffer.put(Perspective.SINE[i]);
|
||||
uniformBuffer.put(Perspective.COSINE[i]);
|
||||
uniformBuffer.put(pad);
|
||||
uniformBuf.put(Perspective.SINE[i]);
|
||||
uniformBuf.put(Perspective.COSINE[i]);
|
||||
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);
|
||||
gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, 0);
|
||||
updateBuffer(uniformBuffer, GL_UNIFORM_BUFFER, uniformBuf.limit() * Integer.BYTES, uniformBuf, GL_DYNAMIC_DRAW, CL_MEM_READ_ONLY);
|
||||
gl.glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
|
||||
private void initAAFbo(int width, int height, int aaSamples)
|
||||
@@ -785,9 +784,11 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
invokeOnMainThread(() ->
|
||||
{
|
||||
// UBO. Only the first 32 bytes get modified here, the rest is the constant sin/cos table.
|
||||
gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, uniformBufferId);
|
||||
uniformBuffer.clear();
|
||||
uniformBuffer
|
||||
// We can reuse the vertex buffer since it isn't used yet.
|
||||
vertexBuffer.clear();
|
||||
vertexBuffer.ensureCapacity(32);
|
||||
IntBuffer uniformBuf = vertexBuffer.getBuffer();
|
||||
uniformBuf
|
||||
.put(yaw)
|
||||
.put(pitch)
|
||||
.put(client.getCenterX())
|
||||
@@ -796,12 +797,14 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
.put(cameraX)
|
||||
.put(cameraY)
|
||||
.put(cameraZ);
|
||||
uniformBuffer.flip();
|
||||
uniformBuf.flip();
|
||||
|
||||
gl.glBufferSubData(gl.GL_UNIFORM_BUFFER, 0, uniformBuffer.limit() * Integer.BYTES, uniformBuffer);
|
||||
gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, 0);
|
||||
gl.glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer.glBufferId);
|
||||
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()
|
||||
{
|
||||
if (!useComputeShaders)
|
||||
if (computeMode == ComputeMode.NONE)
|
||||
{
|
||||
// Upload buffers
|
||||
vertexBuffer.flip();
|
||||
@@ -822,12 +825,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
IntBuffer vertexBuffer = this.vertexBuffer.getBuffer();
|
||||
FloatBuffer uvBuffer = this.uvBuffer.getBuffer();
|
||||
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpBufferId);
|
||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, gl.GL_DYNAMIC_DRAW);
|
||||
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpUvBufferId);
|
||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, gl.GL_DYNAMIC_DRAW);
|
||||
|
||||
updateBuffer(tmpVertexBuffer, GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, GL_DYNAMIC_DRAW, 0L);
|
||||
updateBuffer(tmpUvBuffer, GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, GL_DYNAMIC_DRAW, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -844,79 +843,91 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
IntBuffer modelBufferSmall = this.modelBufferSmall.getBuffer();
|
||||
IntBuffer modelBufferUnordered = this.modelBufferUnordered.getBuffer();
|
||||
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpBufferId);
|
||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, gl.GL_DYNAMIC_DRAW);
|
||||
// temp buffers
|
||||
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);
|
||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, gl.GL_DYNAMIC_DRAW);
|
||||
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpModelBufferId);
|
||||
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);
|
||||
// model buffers
|
||||
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);
|
||||
updateBuffer(tmpModelBufferUnordered, GL_ARRAY_BUFFER, modelBufferUnordered.limit() * Integer.BYTES, modelBufferUnordered, GL_DYNAMIC_DRAW, CL_MEM_READ_ONLY);
|
||||
|
||||
// Output buffers
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpOutBufferId);
|
||||
gl.glBufferData(gl.GL_ARRAY_BUFFER,
|
||||
updateBuffer(tmpOutBuffer,
|
||||
GL_ARRAY_BUFFER,
|
||||
targetBufferOffset * 16, // each vertex is an ivec4, which is 16 bytes
|
||||
null,
|
||||
gl.GL_STREAM_DRAW);
|
||||
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpOutUvBufferId);
|
||||
gl.glBufferData(gl.GL_ARRAY_BUFFER,
|
||||
targetBufferOffset * 16,
|
||||
GL_STREAM_DRAW,
|
||||
CL_MEM_WRITE_ONLY);
|
||||
updateBuffer(tmpOutUvBuffer,
|
||||
GL_ARRAY_BUFFER,
|
||||
targetBufferOffset * 16, // each vertex is an ivec4, which is 16 bytes
|
||||
null,
|
||||
gl.GL_STREAM_DRAW);
|
||||
GL_STREAM_DRAW,
|
||||
CL_MEM_WRITE_ONLY);
|
||||
|
||||
// Bind UBO to compute programs
|
||||
gl.glUniformBlockBinding(glSmallComputeProgram, uniBlockSmall, 0);
|
||||
gl.glUniformBlockBinding(glComputeProgram, uniBlockLarge, 0);
|
||||
if (computeMode == ComputeMode.OPENCL)
|
||||
{
|
||||
// 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'
|
||||
* 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
|
||||
gl.glUseProgram(glUnorderedComputeProgram);
|
||||
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferUnorderedId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferUnordered.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, sceneVertexBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpVertexBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, sceneUvBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBuffer.glBufferId);
|
||||
|
||||
gl.glDispatchCompute(unorderedModels, 1, 1);
|
||||
|
||||
// small
|
||||
gl.glUseProgram(glSmallComputeProgram);
|
||||
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferSmallId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferSmall.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, sceneVertexBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpVertexBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, sceneUvBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBuffer.glBufferId);
|
||||
|
||||
gl.glDispatchCompute(smallModels, 1, 1);
|
||||
|
||||
// large
|
||||
gl.glUseProgram(glComputeProgram);
|
||||
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferLarge.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, sceneVertexBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpVertexBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, sceneUvBuffer.glBufferId);
|
||||
gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBuffer.glBufferId);
|
||||
|
||||
gl.glDispatchCompute(largeModels, 1, 1);
|
||||
}
|
||||
@@ -926,7 +937,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
SceneTilePaint paint, int tileZ, int tileX, int tileY,
|
||||
int zoom, int centerX, int centerY)
|
||||
{
|
||||
if (!useComputeShaders)
|
||||
if (computeMode == ComputeMode.NONE)
|
||||
{
|
||||
targetBufferOffset += sceneUploader.upload(paint,
|
||||
tileZ, tileX, tileY,
|
||||
@@ -963,7 +974,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
SceneTileModel model, int tileZ, int tileX, int tileY,
|
||||
int zoom, int centerX, int centerY)
|
||||
{
|
||||
if (!useComputeShaders)
|
||||
if (computeMode == ComputeMode.NONE)
|
||||
{
|
||||
targetBufferOffset += sceneUploader.upload(model,
|
||||
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).
|
||||
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.
|
||||
renderHeightOff = (int) Math.floor(scaleFactorY * (renderHeightOff)) - padding;
|
||||
@@ -1195,27 +1206,36 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
gl.glBindVertexArray(vaoHandle);
|
||||
|
||||
int vertexBuffer, uvBuffer;
|
||||
if (useComputeShaders)
|
||||
if (computeMode != ComputeMode.NONE)
|
||||
{
|
||||
// Before reading the SSBOs written to from postDrawScene() we must insert a barrier
|
||||
gl.glMemoryBarrier(gl.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
if (computeMode == ComputeMode.OPENGL)
|
||||
{
|
||||
// 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
|
||||
vertexBuffer = tmpOutBufferId;
|
||||
uvBuffer = tmpOutUvBufferId;
|
||||
vertexBuffer = tmpOutBuffer.glBufferId;
|
||||
uvBuffer = tmpOutUvBuffer.glBufferId;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only use the temporary buffers, which will contain the full scene
|
||||
vertexBuffer = tmpBufferId;
|
||||
uvBuffer = tmpUvBufferId;
|
||||
vertexBuffer = tmpVertexBuffer.glBufferId;
|
||||
uvBuffer = tmpUvBuffer.glBufferId;
|
||||
}
|
||||
|
||||
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.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.glDrawArrays(gl.GL_TRIANGLES, 0, targetBufferOffset);
|
||||
@@ -1400,12 +1420,12 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||
{
|
||||
if (!useComputeShaders || gameStateChanged.getGameState() != GameState.LOGGED_IN)
|
||||
if (computeMode == ComputeMode.NONE || gameStateChanged.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uploadScene();
|
||||
invokeOnMainThread(this::uploadScene);
|
||||
}
|
||||
|
||||
private void uploadScene()
|
||||
@@ -1421,13 +1441,10 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
IntBuffer vertexBuffer = this.vertexBuffer.getBuffer();
|
||||
FloatBuffer uvBuffer = this.uvBuffer.getBuffer();
|
||||
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, bufferId);
|
||||
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, gl.GL_STATIC_COPY);
|
||||
updateBuffer(sceneVertexBuffer, GL_ARRAY_BUFFER, vertexBuffer.limit() * Integer.BYTES, vertexBuffer, GL_STATIC_COPY, CL_MEM_READ_ONLY);
|
||||
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.glBufferData(gl.GL_ARRAY_BUFFER, uvBuffer.limit() * Float.BYTES, uvBuffer, gl.GL_STATIC_COPY);
|
||||
|
||||
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0);
|
||||
gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
vertexBuffer.clear();
|
||||
uvBuffer.clear();
|
||||
@@ -1492,7 +1509,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
@Override
|
||||
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();
|
||||
if (model != null)
|
||||
@@ -1673,7 +1690,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1688,4 +1705,36 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
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_LOOT = Duration.ofMinutes(2);
|
||||
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 KBD_NMZ_REGION = 9033;
|
||||
private static final int ZILYANA_REGION = 11602;
|
||||
private static final int GRAARDOR_REGION = 11347;
|
||||
private static final int KRIL_TSUTSAROTH_REGION = 11603;
|
||||
private static final int KREEARRA_REGION = 11346;
|
||||
private static final int NIGHTMARE_REGION = 15515;
|
||||
|
||||
private final Client client;
|
||||
private final GroundItemsPlugin plugin;
|
||||
@@ -397,8 +399,11 @@ public class GroundItemsOverlay extends Overlay
|
||||
|
||||
private Instant calculateDespawnTime(GroundItem groundItem)
|
||||
{
|
||||
// We can only accurately guess despawn times for our own pvm loot and dropped items
|
||||
if (groundItem.getLootType() != LootType.PVM && groundItem.getLootType() != LootType.DROPPED)
|
||||
// We can only accurately guess despawn times for our own pvm loot, dropped items,
|
||||
// and items we placed on tables
|
||||
if (groundItem.getLootType() != LootType.PVM
|
||||
&& groundItem.getLootType() != LootType.DROPPED
|
||||
&& groundItem.getLootType() != LootType.TABLE)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -447,9 +452,9 @@ public class GroundItemsOverlay extends Overlay
|
||||
}
|
||||
}
|
||||
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
|
||||
? DESPAWN_TIME_DROP
|
||||
: DESPAWN_TIME_LOOT);
|
||||
@@ -461,9 +466,18 @@ public class GroundItemsOverlay extends Overlay
|
||||
}
|
||||
else
|
||||
{
|
||||
despawnTime = spawnTime.plus(groundItem.getLootType() == LootType.DROPPED
|
||||
? DESPAWN_TIME_DROP
|
||||
: DESPAWN_TIME_LOOT);
|
||||
switch (groundItem.getLootType())
|
||||
{
|
||||
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))
|
||||
@@ -477,8 +491,11 @@ public class GroundItemsOverlay extends Overlay
|
||||
|
||||
private Color getItemTimerColor(GroundItem groundItem)
|
||||
{
|
||||
// We can only accurately guess despawn times for our own pvm loot and dropped items
|
||||
if (groundItem.getLootType() != LootType.PVM && groundItem.getLootType() != LootType.DROPPED)
|
||||
// We can only accurately guess despawn times for our own pvm loot, dropped items,
|
||||
// and items we placed on tables
|
||||
if (groundItem.getLootType() != LootType.PVM
|
||||
&& groundItem.getLootType() != LootType.DROPPED
|
||||
&& groundItem.getLootType() != LootType.TABLE)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -52,11 +52,13 @@ import lombok.Setter;
|
||||
import lombok.Value;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.api.ItemContainer;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.MenuAction;
|
||||
import net.runelite.api.MenuEntry;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Tile;
|
||||
import net.runelite.api.TileItem;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
@@ -180,6 +182,7 @@ public class GroundItemsPlugin extends Plugin
|
||||
private LoadingCache<NamedQuantity, Boolean> highlightedItems;
|
||||
private LoadingCache<NamedQuantity, Boolean> hiddenItems;
|
||||
private final Queue<Integer> droppedItemQueue = EvictingQueue.create(16); // recently dropped items
|
||||
private int lastUsedItem;
|
||||
|
||||
@Provides
|
||||
GroundItemsConfig provideConfig(ConfigManager configManager)
|
||||
@@ -194,6 +197,7 @@ public class GroundItemsPlugin extends Plugin
|
||||
mouseManager.registerMouseListener(inputListener);
|
||||
keyManager.registerKeyListener(inputListener);
|
||||
executor.execute(this::reset);
|
||||
lastUsedItem = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -384,6 +388,7 @@ public class GroundItemsPlugin extends Plugin
|
||||
final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemId;
|
||||
final int alchPrice = itemComposition.getHaPrice();
|
||||
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()
|
||||
.id(itemId)
|
||||
@@ -394,12 +399,11 @@ public class GroundItemsPlugin extends Plugin
|
||||
.haPrice(alchPrice)
|
||||
.height(tile.getItemLayer().getHeight())
|
||||
.tradeable(itemComposition.isTradeable())
|
||||
.lootType(dropped ? LootType.DROPPED : LootType.UNKNOWN)
|
||||
.lootType(dropped ? LootType.DROPPED : (table ? LootType.TABLE : LootType.UNKNOWN))
|
||||
.spawnTime(Instant.now())
|
||||
.stackable(itemComposition.isStackable())
|
||||
.build();
|
||||
|
||||
|
||||
// Update item price in case it is coins
|
||||
if (realItemId == COINS)
|
||||
{
|
||||
@@ -638,11 +642,8 @@ public class GroundItemsPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
final Player local = client.getLocalPlayer();
|
||||
final StringBuilder notificationStringBuilder = new StringBuilder()
|
||||
.append('[')
|
||||
.append(local.getName())
|
||||
.append("] received a ")
|
||||
.append("You received a ")
|
||||
.append(dropType)
|
||||
.append(" drop: ")
|
||||
.append(item.getName());
|
||||
@@ -687,5 +688,21 @@ public class GroundItemsPlugin extends Plugin
|
||||
// item spawns that are drops
|
||||
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
|
||||
{
|
||||
UNKNOWN,
|
||||
TABLE,
|
||||
DROPPED,
|
||||
PVP,
|
||||
PVM;
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import lombok.AccessLevel;
|
||||
@@ -313,21 +314,22 @@ public class GroundMarkerPlugin extends Plugin
|
||||
WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, localPoint);
|
||||
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")
|
||||
.value(Optional.ofNullable(existing.getLabel()).orElse(""))
|
||||
.onDone((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);
|
||||
points.remove(searchPoint);
|
||||
points.add(newPoint);
|
||||
|
||||
@@ -147,7 +147,7 @@ public class IdleNotifierPlugin extends Plugin
|
||||
case COOKING_FIRE:
|
||||
case COOKING_RANGE:
|
||||
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_JADE:
|
||||
case GEM_CUTTING_REDTOPAZ:
|
||||
@@ -158,6 +158,7 @@ public class IdleNotifierPlugin extends Plugin
|
||||
case GEM_CUTTING_AMETHYST:
|
||||
case CRAFTING_GLASSBLOWING:
|
||||
case CRAFTING_SPINNING:
|
||||
case CRAFTING_LOOM:
|
||||
case CRAFTING_BATTLESTAVES:
|
||||
case CRAFTING_LEATHER:
|
||||
case CRAFTING_POTTERS_WHEEL:
|
||||
@@ -268,6 +269,10 @@ public class IdleNotifierPlugin extends Plugin
|
||||
case MAGIC_ENCHANTING_BOLTS:
|
||||
/* Prayer */
|
||||
case USING_GILDED_ALTAR:
|
||||
case ECTOFUNTUS_FILL_SLIME_BUCKET:
|
||||
case ECTOFUNTUS_INSERT_BONES:
|
||||
case ECTOFUNTUS_GRIND_BONES:
|
||||
case ECTOFUNTUS_EMPTY_BIN:
|
||||
/* Farming */
|
||||
case FARMING_MIX_ULTRACOMPOST:
|
||||
case FARMING_HARVEST_BUSH:
|
||||
@@ -433,64 +438,64 @@ public class IdleNotifierPlugin extends Plugin
|
||||
|
||||
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())
|
||||
{
|
||||
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))
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] is now idle!");
|
||||
notifier.notify("You are now idle!");
|
||||
}
|
||||
|
||||
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 (lastInteractWasCombat)
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] is now out of combat!");
|
||||
notifier.notify("You are now out of combat!");
|
||||
}
|
||||
else
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] is now idle!");
|
||||
notifier.notify("You are now idle!");
|
||||
}
|
||||
}
|
||||
|
||||
if (checkLowHitpoints())
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] has low hitpoints!");
|
||||
notifier.notify("You have low hitpoints!");
|
||||
}
|
||||
|
||||
if (checkLowPrayer())
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] has low prayer!");
|
||||
notifier.notify("You have low prayer!");
|
||||
}
|
||||
|
||||
if (checkLowEnergy())
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] has low run energy!");
|
||||
notifier.notify("You have low run energy!");
|
||||
}
|
||||
|
||||
if (checkHighEnergy())
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] has restored run energy!");
|
||||
notifier.notify("You have restored run energy!");
|
||||
}
|
||||
|
||||
if (checkLowOxygen())
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] has low oxygen!");
|
||||
notifier.notify("You have low oxygen!");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "swapBattlestaves",
|
||||
name = "Battlestaff",
|
||||
description = "Swap Wield with Use on Battlestaves without orbs",
|
||||
section = itemSection
|
||||
)
|
||||
default boolean swapBattlestaves()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "swapPrayerBook",
|
||||
name = "Recite-Prayer",
|
||||
|
||||
@@ -334,6 +334,8 @@ public class MenuEntrySwapperPlugin extends Plugin
|
||||
|
||||
swap("bury", "use", config::swapBones);
|
||||
|
||||
swap("wield", "battlestaff", "use", config::swapBattlestaves);
|
||||
|
||||
swap("clean", "use", config::swapHerbs);
|
||||
|
||||
swap("read", "recite-prayer", config::swapPrayerBook);
|
||||
|
||||
@@ -166,7 +166,7 @@ public class RegenMeterPlugin extends Plugin
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@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(
|
||||
keyName = "untradeableDrop",
|
||||
name = "Screenshot Untradeable drops",
|
||||
description = "Configures whether or not screenshots are automatically taken when you receive an untradeable drop.",
|
||||
position = 14,
|
||||
position = 15,
|
||||
section = whatSection
|
||||
)
|
||||
default boolean screenshotUntradeableDrop()
|
||||
@@ -221,7 +233,7 @@ public interface ScreenshotConfig extends Config
|
||||
keyName = "ccKick",
|
||||
name = "Screenshot Kicks from FC",
|
||||
description = "Take a screenshot when you kick a user from a friends chat.",
|
||||
position = 15,
|
||||
position = 16,
|
||||
section = whatSection
|
||||
)
|
||||
default boolean screenshotKick()
|
||||
@@ -233,7 +245,7 @@ public interface ScreenshotConfig extends Config
|
||||
keyName = "baHighGamble",
|
||||
name = "Screenshot BA high gambles",
|
||||
description = "Take a screenshot of your reward from a high gamble at Barbarian Assault.",
|
||||
position = 16,
|
||||
position = 17,
|
||||
section = whatSection
|
||||
)
|
||||
default boolean screenshotHighGamble()
|
||||
@@ -245,7 +257,7 @@ public interface ScreenshotConfig extends Config
|
||||
keyName = "hotkey",
|
||||
name = "Screenshot hotkey",
|
||||
description = "When you press this key a screenshot will be taken",
|
||||
position = 17
|
||||
position = 18
|
||||
)
|
||||
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 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 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 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)?[!.]?$");
|
||||
@@ -417,9 +417,13 @@ public class ScreenshotPlugin extends Plugin
|
||||
Matcher m = VALUABLE_DROP_PATTERN.matcher(chatMessage);
|
||||
if (m.matches())
|
||||
{
|
||||
String valuableDropName = m.group(1);
|
||||
String fileName = "Valuable drop " + valuableDropName;
|
||||
takeScreenshot(fileName, "Valuable Drops");
|
||||
int valuableDropValue = Integer.parseInt(m.group(2).replaceAll(",", ""));
|
||||
if (valuableDropValue >= config.valuableDropThreshold())
|
||||
{
|
||||
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.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.text.DecimalFormat;
|
||||
@@ -95,7 +97,14 @@ class SkillCalculator extends JPanel
|
||||
searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
|
||||
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));
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@ enum Task
|
||||
"Fremennik Slayer Dungeon",
|
||||
"God Wars Dungeon",
|
||||
"Iorwerth Dungeon",
|
||||
"Isle of Souls",
|
||||
"Jormungand's Prison",
|
||||
"Kalphite Lair",
|
||||
"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_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_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_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.";
|
||||
@@ -517,7 +518,7 @@ public class TimersPlugin extends Plugin
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public abstract class TabContentPanel extends JPanel
|
||||
LocalDateTime currentTime = LocalDateTime.now();
|
||||
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(formatter.format(endTime));
|
||||
|
||||
@@ -41,6 +41,7 @@ public interface TimeTrackingConfig extends Config
|
||||
String TIMERS = "timers";
|
||||
String STOPWATCHES = "stopwatches";
|
||||
String PREFER_SOONEST = "preferSoonest";
|
||||
String NOTIFY = "notify";
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "timeFormatMode",
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.google.inject.Inject;
|
||||
import com.google.inject.Provides;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
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.FarmingTracker;
|
||||
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.NavigationButton;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
@@ -102,6 +100,8 @@ public class TimeTrackingPlugin extends Plugin
|
||||
|
||||
private ScheduledFuture panelUpdateFuture;
|
||||
|
||||
private ScheduledFuture notifierFuture;
|
||||
|
||||
private TimeTrackingPanel panel;
|
||||
|
||||
private NavigationButton navButton;
|
||||
@@ -139,6 +139,7 @@ public class TimeTrackingPlugin extends Plugin
|
||||
clientToolbar.addNavigation(navButton);
|
||||
|
||||
panelUpdateFuture = executorService.scheduleAtFixedRate(this::updatePanel, 200, 200, TimeUnit.MILLISECONDS);
|
||||
notifierFuture = executorService.scheduleAtFixedRate(this::checkCompletion, 10, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,6 +154,7 @@ public class TimeTrackingPlugin extends Plugin
|
||||
panelUpdateFuture = null;
|
||||
}
|
||||
|
||||
notifierFuture.cancel(true);
|
||||
clientToolbar.removeNavigation(navButton);
|
||||
infoBoxManager.removeInfoBox(farmingContractManager.getInfoBox());
|
||||
farmingContractManager.setInfoBox(null);
|
||||
@@ -260,8 +262,7 @@ public class TimeTrackingPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
@Schedule(period = 10, unit = ChronoUnit.SECONDS)
|
||||
public void checkCompletion()
|
||||
private void checkCompletion()
|
||||
{
|
||||
boolean birdHouseDataChanged = birdHouseTracker.checkCompletion();
|
||||
|
||||
@@ -269,6 +270,8 @@ public class TimeTrackingPlugin extends Plugin
|
||||
{
|
||||
panel.update();
|
||||
}
|
||||
|
||||
farmingTracker.checkCompletion();
|
||||
}
|
||||
|
||||
private void updatePanel()
|
||||
|
||||
@@ -29,22 +29,29 @@ import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.components.ThinProgressBar;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
public class TimeablePanel<T> extends JPanel
|
||||
{
|
||||
private final T timeable;
|
||||
private final JLabel icon = new JLabel();
|
||||
private final JLabel farmingContractIcon = new JLabel();
|
||||
private final JToggleButton notifyButton = new JToggleButton();
|
||||
private final JLabel estimate = new JLabel();
|
||||
private final ThinProgressBar progress = new ThinProgressBar();
|
||||
private final JLabel text;
|
||||
@@ -79,8 +86,29 @@ public class TimeablePanel<T> extends JPanel
|
||||
infoPanel.add(text);
|
||||
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(farmingContractIcon, BorderLayout.EAST);
|
||||
topContainer.add(infoPanel, BorderLayout.CENTER);
|
||||
|
||||
progress.setValue(0);
|
||||
|
||||
@@ -29,6 +29,7 @@ import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||
|
||||
@RequiredArgsConstructor(
|
||||
access = AccessLevel.PACKAGE
|
||||
@@ -41,4 +42,14 @@ class FarmingPatch
|
||||
private final String name;
|
||||
private final Varbits varbit;
|
||||
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 int regionID;
|
||||
private final boolean definite;
|
||||
private final FarmingPatch[] patches;
|
||||
private final Varbits[] varbits;
|
||||
|
||||
FarmingRegion(String name, int regionID, FarmingPatch... patches)
|
||||
FarmingRegion(String name, int regionID, boolean definite, FarmingPatch... patches)
|
||||
{
|
||||
this.name = name;
|
||||
this.regionID = regionID;
|
||||
this.definite = definite;
|
||||
this.patches = patches;
|
||||
this.varbits = new Varbits[patches.length];
|
||||
for (int i = 0; i < patches.length; i++)
|
||||
|
||||
@@ -33,8 +33,11 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.timetracking.TabContentPanel;
|
||||
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.FontManager;
|
||||
|
||||
@Slf4j
|
||||
public class FarmingTabPanel extends TabContentPanel
|
||||
{
|
||||
private final FarmingTracker farmingTracker;
|
||||
private final ItemManager itemManager;
|
||||
private final ConfigManager configManager;
|
||||
private final TimeTrackingConfig config;
|
||||
private final List<TimeablePanel<FarmingPatch>> patchPanels;
|
||||
private final FarmingContractManager farmingContractManager;
|
||||
@@ -53,6 +58,7 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
FarmingTabPanel(
|
||||
FarmingTracker farmingTracker,
|
||||
ItemManager itemManager,
|
||||
ConfigManager configManager,
|
||||
TimeTrackingConfig config,
|
||||
Set<FarmingPatch> patches,
|
||||
FarmingContractManager farmingContractManager
|
||||
@@ -60,6 +66,7 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
{
|
||||
this.farmingTracker = farmingTracker;
|
||||
this.itemManager = itemManager;
|
||||
this.configManager = configManager;
|
||||
this.config = config;
|
||||
this.patchPanels = new ArrayList<>();
|
||||
this.farmingContractManager = farmingContractManager;
|
||||
@@ -103,6 +110,18 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
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);
|
||||
add(p, c);
|
||||
c.gridy++;
|
||||
@@ -197,18 +216,26 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
{
|
||||
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;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.vars.Autoweed;
|
||||
import net.runelite.api.widgets.WidgetModalMode;
|
||||
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.SummaryState;
|
||||
import net.runelite.client.plugins.timetracking.Tab;
|
||||
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
@@ -53,6 +62,7 @@ public class FarmingTracker
|
||||
private final ConfigManager configManager;
|
||||
private final TimeTrackingConfig config;
|
||||
private final FarmingWorld farmingWorld;
|
||||
private final Notifier notifier;
|
||||
|
||||
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.
|
||||
*/
|
||||
private final Map<Tab, Long> completionTimes = new EnumMap<>(Tab.class);
|
||||
Map<ProfilePatch, Boolean> wasNotified = new HashMap<>();
|
||||
|
||||
private boolean newRegionLoaded;
|
||||
private Collection<FarmingRegion> lastRegions;
|
||||
private boolean firstNotifyCheck = true;
|
||||
|
||||
@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.itemManager = itemManager;
|
||||
this.configManager = configManager;
|
||||
this.config = config;
|
||||
this.farmingWorld = farmingWorld;
|
||||
this.notifier = notifier;
|
||||
}
|
||||
|
||||
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
|
||||
Varbits varbit = patch.getVarbit();
|
||||
String key = region.getRegionID() + "." + varbit.getId();
|
||||
String key = patch.configKey();
|
||||
String strVarbit = Integer.toString(client.getVar(varbit));
|
||||
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);
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
@@ -258,17 +277,23 @@ public class FarmingTracker
|
||||
|
||||
@Nullable
|
||||
public PatchPrediction predictPatch(FarmingPatch patch)
|
||||
{
|
||||
return predictPatch(patch, configManager.getRSProfileKey());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PatchPrediction predictPatch(FarmingPatch patch, String profile)
|
||||
{
|
||||
long unixNow = Instant.now().getEpochSecond();
|
||||
|
||||
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
|
||||
.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 storedValue = configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, key);
|
||||
String key = patch.configKey();
|
||||
String storedValue = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile, key);
|
||||
|
||||
if (storedValue == null)
|
||||
{
|
||||
@@ -323,11 +348,11 @@ public class FarmingTracker
|
||||
long doneEstimate = 0;
|
||||
if (tickrate > 0)
|
||||
{
|
||||
long tickNow = getTickTime(tickrate, 0, unixNow);
|
||||
long tickTime = getTickTime(tickrate, 0, unixTime);
|
||||
long tickNow = getTickTime(tickrate, 0, unixNow, profile);
|
||||
long tickTime = getTickTime(tickrate, 0, unixTime, profile);
|
||||
int delta = (int) (tickNow - tickTime) / (tickrate * 60);
|
||||
|
||||
doneEstimate = getTickTime(tickrate, stages - 1 - stage, tickTime);
|
||||
doneEstimate = getTickTime(tickrate, stages - 1 - stage, tickTime, profile);
|
||||
|
||||
stage += delta;
|
||||
if (stage >= stages)
|
||||
@@ -347,13 +372,13 @@ public class FarmingTracker
|
||||
|
||||
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 offsetTimeMins = configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.FARM_TICK_OFFSET, int.class);
|
||||
Integer offsetPrecisionMins = configManager.getConfiguration(TimeTrackingConfig.CONFIG_GROUP, profile, TimeTrackingConfig.FARM_TICK_OFFSET_PRECISION, 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
|
||||
long calculatedOffsetTime = 0L;
|
||||
@@ -465,4 +490,133 @@ public class FarmingTracker
|
||||
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.
|
||||
// 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)
|
||||
), 13362, 13105);
|
||||
|
||||
add(new FarmingRegion("Ardougne", 10290,
|
||||
add(new FarmingRegion("Ardougne", 10290, false,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||
), 10546);
|
||||
add(new FarmingRegion("Ardougne", 10548,
|
||||
add(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),
|
||||
@@ -79,12 +79,12 @@ class FarmingWorld
|
||||
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_4772, PatchImplementation.SPIRIT_TREE)
|
||||
), 11057);
|
||||
|
||||
add(new FarmingRegion("Catherby", 11062,
|
||||
add(new FarmingRegion("Catherby", 11062, false,
|
||||
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
@@ -103,7 +103,7 @@ class FarmingWorld
|
||||
return true;
|
||||
}
|
||||
}, 11061, 11318, 11317);
|
||||
add(new FarmingRegion("Catherby", 11317,
|
||||
add(new FarmingRegion("Catherby", 11317, false,
|
||||
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)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Draynor Manor", 12340,
|
||||
add(new FarmingRegion("Draynor Manor", 12340, false,
|
||||
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)
|
||||
), 11316);
|
||||
|
||||
add(new FarmingRegion("Etceteria", 10300,
|
||||
add(new FarmingRegion("Etceteria", 10300, false,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH),
|
||||
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)
|
||||
), 12084);
|
||||
add(new FarmingRegion("Falador", 12083,
|
||||
add(new FarmingRegion("Falador", 12083, false,
|
||||
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
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("Middle", Varbits.FARMING_4772, PatchImplementation.HARDWOOD_TREE),
|
||||
new FarmingPatch("West", Varbits.FARMING_4773, PatchImplementation.HARDWOOD_TREE)
|
||||
@@ -179,22 +179,22 @@ class FarmingWorld
|
||||
return loc.getPlane() == 0;
|
||||
}
|
||||
}, 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("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_4772, PatchImplementation.FRUIT_TREE)
|
||||
), 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_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("South West", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
@@ -202,7 +202,7 @@ class FarmingWorld
|
||||
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST),
|
||||
new FarmingPatch("", Varbits.FARMING_7904, PatchImplementation.SPIRIT_TREE)
|
||||
), 6711);
|
||||
add(new FarmingRegion("Kourend", 7223,
|
||||
add(new FarmingRegion("Kourend", 7223, false,
|
||||
new FarmingPatch("East 1", Varbits.GRAPES_4953, PatchImplementation.GRAPES),
|
||||
new FarmingPatch("East 2", Varbits.GRAPES_4954, 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)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Lletya", 9265,
|
||||
add(new FarmingRegion("Lletya", 9265, false,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
|
||||
), 11103);
|
||||
|
||||
add(new FarmingRegion("Lumbridge", 12851,
|
||||
add(new FarmingRegion("Lumbridge", 12851, false,
|
||||
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)
|
||||
), 12850);
|
||||
|
||||
add(new FarmingRegion("Morytania", 13622,
|
||||
add(new FarmingRegion("Morytania", 13622, false,
|
||||
new FarmingPatch("Mushroom", Varbits.FARMING_4771, PatchImplementation.MUSHROOM)
|
||||
), 13878);
|
||||
add(new FarmingRegion("Morytania", 14391,
|
||||
add(new FarmingRegion("Morytania", 14391, false,
|
||||
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
@@ -239,7 +239,7 @@ class FarmingWorld
|
||||
new FarmingPatch("", Varbits.FARMING_4775, PatchImplementation.COMPOST)
|
||||
), 14390);
|
||||
|
||||
add(new FarmingRegion("Port Sarim", 12082,
|
||||
add(new FarmingRegion("Port Sarim", 12082, false,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
|
||||
)
|
||||
{
|
||||
@@ -250,48 +250,48 @@ class FarmingWorld
|
||||
}
|
||||
}, 12083);
|
||||
|
||||
add(new FarmingRegion("Rimmington", 11570,
|
||||
add(new FarmingRegion("Rimmington", 11570, false,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||
), 11826);
|
||||
|
||||
add(new FarmingRegion("Seers' Village", 10551,
|
||||
add(new FarmingRegion("Seers' Village", 10551, false,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||
), 10550);
|
||||
|
||||
add(new FarmingRegion("Tai Bwo Wannai", 11056,
|
||||
add(new FarmingRegion("Tai Bwo Wannai", 11056, false,
|
||||
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)
|
||||
), 11829);
|
||||
|
||||
add(new FarmingRegion("Tree Gnome Village", 9777,
|
||||
add(new FarmingRegion("Tree Gnome Village", 9777, true,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE)
|
||||
), 10033);
|
||||
|
||||
add(new FarmingRegion("Troll Stronghold", 11321,
|
||||
add(new FarmingRegion("Troll Stronghold", 11321, true,
|
||||
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)
|
||||
), 12853);
|
||||
|
||||
add(new FarmingRegion("Yanille", 10288,
|
||||
add(new FarmingRegion("Yanille", 10288, false,
|
||||
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)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Farming Guild", 5021,
|
||||
add(new FarmingRegion("Farming Guild", 5021, true,
|
||||
new FarmingPatch("Hespori", Varbits.FARMING_7908, PatchImplementation.HESPORI)
|
||||
));
|
||||
|
||||
//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_4775, PatchImplementation.HERB),
|
||||
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.BUSH),
|
||||
@@ -308,7 +308,7 @@ class FarmingWorld
|
||||
), 5177, 5178, 5179, 4921, 4923, 4665, 4666, 4667);
|
||||
|
||||
//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("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
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)),
|
||||
CRANDOR("Crandor Dungeon", new WorldPoint(2833, 3256, 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)),
|
||||
DRAYNOR_MANOR_E("Draynor Manor basement", new WorldPoint(3114, 3357, 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_TROLL_E("Ice Troll Caves", new WorldPoint(2400, 3889, 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_CAMP_CAVE("Iorwerth Camp cave", new WorldPoint(2200, 3262, 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)),
|
||||
ISAFDAR_NORTH_EAST_INSIDE(FishingSpot.SALMON, new WorldPoint(3293, 6005, 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},
|
||||
new WorldPoint(2400, 3780, 0), new WorldPoint(2412, 3780, 0),
|
||||
new WorldPoint(2419, 3789, 0)),
|
||||
|
||||
@@ -49,6 +49,9 @@ enum HunterAreaLocation
|
||||
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_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),
|
||||
KEBOS_SWAMP(new WorldPoint(1184, 3595, 0), HunterCreature.CRIMSON_SWIFT),
|
||||
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(2, Ore.SILVER)),
|
||||
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),
|
||||
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)),
|
||||
|
||||
@@ -83,6 +83,9 @@ enum RareTreeLocation
|
||||
new WorldPoint(2748, 3466, 0),
|
||||
new WorldPoint(2710, 3570, 0),
|
||||
|
||||
// Isle of Souls
|
||||
new WorldPoint(2254, 2808, 0),
|
||||
|
||||
// Prifddinas
|
||||
new WorldPoint(2209, 3427, 0),
|
||||
new WorldPoint(3233, 6179, 0)),
|
||||
@@ -111,6 +114,9 @@ enum RareTreeLocation
|
||||
// Mos Le'Harmless
|
||||
new WorldPoint(3810, 3058, 0),
|
||||
|
||||
// Isle of Souls
|
||||
new WorldPoint(2194, 2991, 0),
|
||||
|
||||
// Karamja
|
||||
new WorldPoint(2821, 3084, 0)),
|
||||
|
||||
@@ -180,6 +186,10 @@ enum RareTreeLocation
|
||||
new WorldPoint(3674, 3447, 0),
|
||||
new WorldPoint(3684, 3385, 0),
|
||||
|
||||
// Isle of Souls
|
||||
new WorldPoint(2147, 2972, 0),
|
||||
new WorldPoint(2165, 2863, 0),
|
||||
|
||||
// Zanaris
|
||||
new WorldPoint(2412, 4464, 0),
|
||||
new WorldPoint(2465, 4427, 0),
|
||||
|
||||
@@ -33,14 +33,12 @@ import java.awt.Font;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
@@ -335,30 +333,6 @@ public class IconTextField extends JPanel
|
||||
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
|
||||
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 |
Reference in New Issue
Block a user