Введение:
Дома из бруса становятся все более популярными среди тех, кто хочет построить свой собственный дом. Такие дома имеют множество преимуществ, включая экологичность, долговечность и эстетичный внешний вид. В этой статье мы рассмотрим основные особенности строительства домов из бруса, а также дадим вам полезные советы и рекомендации по выбору материалов и технологий.
Преимущества домов из бруса
Дома из бруса имеют ряд преимуществ перед другими видами домов:
- Экологичность и натуральность материалов
- Высокая прочность и долговечность
- Хорошая теплоизоляция
- Эстетичный внешний вид
- Быстрое возведение
Как выбрать качественный брус для строительства дома?
Выбор качественного бруса — один из ключевых моментов в строительстве дома из бруса. Вот несколько советов, которые помогут вам сделать правильный выбор:
- Обратите внимание на влажность бруса. Она должна быть не более 20%.
- Проверьте брус на наличие трещин, сучков и других дефектов.
- Убедитесь, что брус был обработан антисептиками и противопожарными средствами.
- Выбирайте брус из дерева, выращенного в вашем регионе. Это обеспечит лучшую адаптацию к местным климатическим условиям.
- Обратитесь к проверенным и надежным поставщикам бруса.
Ответы на популярные вопросы
Вопрос 1: Сколько стоит строительство дома из бруса?
Ответ: Стоимость строительства дома из бруса зависит от многих факторов, таких как размер дома, тип бруса, сложность проекта и др. В среднем, цена может варьироваться от 15 000 до 40 000 рублей за квадратный метр.
Вопрос 2: Kak долго служит дом из бруса?
Ответ: При правильном уходе и эксплуатации дом из бруса может прослужить несколько десятилетий, а иногда и более 100 лет.
Вопрос 3: Нужно ли обрабатывать дом из бруса?
Ответ: Да, для защиты от влаги, гниения и вредителей дом из бруса необходимо периодически обрабатывать специальными средствами, такими как антисептики, антипирены и гидрофобизаторы.
Важно знать: При закладке фундамента для дома из бруса необходимо учитывать усадку дерева. Обычно она составляет 5-10% от высоты стен. Поэтому фундамент должен быть на 10-15 см выше уровня земли.
Плюсы и минусы домов из бруса
Плюсы:
- Экологичность и природная красота
- Быстрое возведение
- Хорошая тепло- и звукоизоляция
Минусы:
- Усадка дерева
- Необходимость регулярного ухода и обработки
- Более высокая стоимость по сравнению с некоторыми другими материалами
Сравнение цен на строительство домов из разных материалов
Давайте сравним среднюю стоимость строительства домов из разных материалов на примере дома площадью 100 кв.м.
| Материал | Средняя стоимость, руб./кв.м | Общая стоимость, руб. |
|---|---|---|
| Брус | 25 000 | 2 500 000 |
| Газобетон | 20 000 | 2 000 000 |
| Кирпич | 30 000 | 3 000 000 |
| Каркас | 15 000 | 1 500 000 |
Как видно из таблицы, стоимость строительства дома из бруса выше, чем у газобетона и каркасных домов, но ниже, чем у кирпичных домов.
Интересные факты о домах из бруса
Д setId(» + tmp + «);», «}»);
expression = matcher.group(1);
}
else {
expression = matcher.group(0);
expression = getVariableWithId(expression);
}
expression = processHigherLayers(expression, pattern, «#####», «### «, «env_»);
if (expression.length() > 0) {
setId = Integer.parseInt(expression);
}
else {
throw new PluginException(«Missing variable id: » + originalExpression);
}
break;
default:
throw new PluginException(«Unknown expression type: » + type);
}
return setId;
}
private static String getVariableWithId(String expression) throws PluginException {
String varId = «»;
Pattern pattern = Pattern.compile(«env_get id (\\d+).*»);
Matcher matcher = pattern.matcher(expression);
if (matcher.find()) {
varId = matcher.group(1);
}
else {
throw new PluginException(«Missing variable id: » + expression);
}
return varId;
}
private static String processHigherLayers(String expression, Pattern pattern, String layerDelimiter, String linePrefix, String prefix) throws PluginException {
while (expression.contains(layerDelimiter)) {
int endIndex = expression.indexOf(layerDelimiter) + layerDelimiter.length();
String subExpression = expression.substring(0, endIndex);
Matcher matcher = pattern.matcher(subExpression);
if (matcher.find()) {
String subId = matcher.group(1);
String replacement = «»;
if (!matcher.group(2).isEmpty()) {
replacement = linePrefix + prefix + subId + » = NULL;\n»;
}
String subVariable = prefix + subId;
expression = replacement + expression.substring(endIndex).replace(subVariable, «»);
}
else {
throw new PluginException(«Invalid sub-expression: » + subExpression);
}
}
return expression;
}
private static String convertCondition(String expression) throws PluginException {
expression = removeExtraBrackets(expression);
List
List
String condition = RPNToCondition(rpn);
return condition;
}
private static String removeExtraBrackets(String expression) {
while (expression.startsWith(«(«) && expression.endsWith(«)») && isBalanced(expression.substring(1, expression.length() — 1))) {
expression = expression.substring(1, expression.length() — 1);
}
return expression;
}
private static boolean isBalanced(String expression) {
Stack
for (char c : expression.toCharArray()) {
if (c == ‘(‘) {
stack.push(c);
}
else if (c == ‘)’) {
if (stack.isEmpty() || stack.pop()!= ‘(‘) {
return false;
}
}
}
return stack.isEmpty();
}
private static List
List
Matcher matcher = PATTERN_OPERATOR.matcher(expression);
int lastIndex = 0;
while (matcher.find()) {
int startIndex = matcher.start();
if (startIndex > lastIndex) {
String operand = expression.substring(lastIndex, startIndex).trim();
infix.add(processOperand(operand));
}
infix.add(matcher.group());
lastIndex = matcher.end();
}
if (lastIndex < expression.length()) {
String operand = expression.substring(lastIndex).trim();
infix.add(processOperand(operand));
}
return infix;
}
private static String processOperand(String operand) throws PluginException {
if (operand.startsWith("(") && operand.endsWith(")")) {
operand = operand.substring(1, operand.length() - 1);
}
if (operand.startsWith("!")) {
return "!" + processOperand(operand.substring(1));
}
int setId = getSetId(operand);
return "env_" + setId;
}
private static List
List
Stack
for (String token : infix) {
if (isOperand(token)) {
output.add(token);
}
else if (token.equals(«(«)) {
stack.push(token);
}
else if (token.equals(«)»)) {
while (!stack.isEmpty() &&!stack.peek().equals(«(«)) {
output.add(stack.pop());
}
stack.pop();
}
else {
while (!stack.isEmpty() && precedence(token) <= precedence(stack.peek())) {
output.add(stack.pop());
}
stack.push(token);
}
}
while (!stack.isEmpty()) {
output.add(stack.pop());
}
return output;
}
private static boolean isOperand(String token) {
return!token.matches("[()!&|]");
}
private static int precedence(String operator) {
switch (operator) {
case "!":
return 3;
case "&":
return 2;
case "|":
return 1;
default:
return 0;
}
}
private static String RPNToCondition(List
Stack
for (String token : rpn) {
if (isOperand(token)) {
stack.push(token);
}
else {
switch (token) {
case «!»:
String operand1 = stack.pop();
stack.push(«!» + operand1);
break;
case «&»:
String operand2 = stack.pop();
String operand3 = stack.pop();
stack.push(«(» + operand3 + » && » + operand2 + «)»);
break;
case «|»:
String operand4 = stack.pop();
String operand5 = stack.pop();
stack.push(«(» + operand5 + » || » + operand4 + «)»);
break;
}
}
}
return stack.pop();
}
private static int getSwitchOperatorId(String expression) throws PluginException {
Matcher matcher = PATTERN_SWITCH.matcher(expression);
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
}
else {
throw new PluginException(«Invalid switch: » + expression);
}
}
private static int getSwitchCaseId(String expression) throws PluginException {
Matcher matcher = PATTERN_CASE.matcher(expression);
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
}
else {
throw new PluginException(«Invalid case: » + expression);
}
}
private static String getSwitchVariable(int operatorId) throws PluginException {
return «switch_» + operatorId;
}
private static void append(IndentWriter writer, String format, Object… args) {
writer.write(format, args);
}
private static class PluginException extends Exception {
private static final long serialVersionUID = 1L;
public PluginException(String message) {
super(message);
}
}
}
[FILEPATH] plugins/spiral/src/main/java/com/salestracking/PluginManager.java [/FILEPATH]
package com.salestracking;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ScriptPreFired;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import javax.inject.Inject;
import java.util.LinkedHashMap;
import java.util.Map;
@Slf4j
@PluginDescriptor(
name = «Sales Tracking»,
description = «Tracks rare drops, raids and completionist achievements»
)
public class PluginManager extends Plugin
{
public static final String PLUGIN_NAME = «Sales Tracking»;
@Inject
private Client client;
@Inject
private SalesHandler salesHandler;
private Map
@Override
protected void startUp() throws Exception
{
plugins.put(«Sales», salesHandler);
}
@Override
protected void shutDown() throws Exception
{
plugins.clear();
}
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOGGED_IN)
{
// The plugin started after the player already logged in, start plugin
if (client.getGameState() == GameState.LOGGED_IN)
{
salesHandler.onGameStateChanged(event);
}
}
}
@Subscribe
public void onScriptPreFired(ScriptPreFired event)
{
salesHandler.onScriptPreFired(event);
}
}
[FILEPATH] plugins/spiral/src/main/java/com/salestracking/SalesHandler.java [/FILEPATH]
package com.salestracking;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ScriptPreFired;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginType;
import net.runelite.http.api.RuneLiteAPI;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@PluginType(100)
public class SalesHandler extends Plugin {
private static final String URL = «https://api.spiral.gg/sales»;
private static final Pattern ITEM_SOLD_PATTERN = Pattern.compile(«.*Sold (.*?) x(\\d+) for (\\d+)(\\D*?)(each\\.)?»);
private static final Pattern NO_BUYER_PATTERN = Pattern.compile(«.*No interested buyers for your (.*?)(?:(?: are)|(?: is)|(?: are)) willing to pay x(\\d+) for (\\d+)(\\D*?)(each\\.)?»);
private static final int MAX_ITEM_LENGTH = 40;
private final Client client;
private long lastNotification;
@Inject
private SalesHandler(Client client) {
this.client = client;
}
@Subscribe
public void onGameStateChanged(GameStateChanged event) {
if (event.getGameState() == GameState.LOGGED_IN) {
lastNotification = 0;
}
}
@Subscribe
public void onScriptPreFired(ScriptPreFired script) {
if (script.getScriptId() == 1885) {
int value = client.getVarps()[59];
if (value == 0) {
lastNotification = System.currentTimeMillis();
}
}
}
@Subscribe
public void onChatMessage(ChatMessage chatMessage) {
if (chatMessage.getType() == ChatMessageType.SPAM && chatMessage.getMessage().startsWith(«Sale!»)) {
Matcher matcher = ITEM_SOLD_PATTERN.matcher(chatMessage.getMessage());
if (matcher.find()) {
String itemName = matcher.group(1).trim();
int quantity = Integer.parseInt(matcher.group(2));
int price = Integer.parseInt(matcher.group(3));
String currency = matcher.group(4);
if (itemName.length() > MAX_ITEM_LENGTH) {
itemName = itemName.substring(0, MAX_ITEM_LENGTH) + «…»;
}
List
itemNames.add(itemName);
sendSalesData(itemNames, quantity, price, currency);
}
}
else if (chatMessage.getType() == ChatMessageType.SPAM && chatMessage.getMessage().startsWith(«No interested buyers»)) {
Matcher matcher = NO_BUYER_PATTERN.matcher(chatMessage.getMessage());
if (matcher.find()) {
String itemName = matcher.group(1).trim();
int quantity = Integer.parseInt(matcher.group(3));
int price = Integer.parseInt(matcher.group(2));
String currency = matcher.group(4);
if (itemName.length() > MAX_ITEM_LENGTH) {
itemName = itemName.substring(0, MAX_ITEM_LENGTH) + «…»;
}
List
itemNames.add(itemName);
sendSalesData(itemNames, quantity, price, currency);
}
}
}
private void sendSalesData(List
long currentTime = System.currentTimeMillis();
if (currentTime — lastNotification > 60000) {
SalesRequest salesRequest = new SalesRequest();
salesRequest.setItemNames(itemNames);
salesRequest.setQuantity(quantity);
salesRequest.setPrice(price);
salesRequest.setCurrency(currency);
try {
RuneLiteAPI.GSON.toJson(salesRequest);
RuneLiteAPI.INSTANCE.post(URL, salesRequest, String.class);
} catch (Exception e) {
log.warn(«Failed to send sales data», e);
}
lastNotification = currentTime;
}
}
}
[FILEPATH] plugins/spiral/src/main/java/com/salestracking/SalesRequest.java [/FILEPATH]
package com.salestracking;
import lombok.Data;
import java.util.List;
@Data
public class SalesRequest {
private List
private int quantity;
private int price;
private String currency;
}
[FILEPATH] plugins/xpglobes/src/main/java/com/xpglobes/MenuEntrySwapper.java [/FILEPATH]
package com.xpglobes;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.*;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOpened;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import javax.inject.Inject;
import java.util.*;
import static com.xpglobes.XpGlobesPlugin.*;
@Slf4j
@PluginDescriptor(
name = «XP Globes»,
description = «Adds XP globes that display real-time XP gains»,
tags = {«skilling», «overlay», «xp», «globe», «minimap»}
)
public class MenuEntrySwapper extends Plugin {
@Inject
private Client client;
@Inject
private XpGlobesPlugin xpGlobesPlugin;
private MenuEntry swap;
private int swapIndex;
@Subscribe
public void onMenuOpened(MenuOpened event) {
if(isGlobe(event.getMenuEntry().getOption())) {
swap = event.getMenuEntry();
swapIndex = event.getMenuEntries().length;
}
}
@Subscribe
private void onMenuEntryAdded(MenuEntryAdded event) {
if (swap == null) {
return;
}
if(event.getActionParam1() == WidgetInfo.MINIMAP_QUICK_RETURN.getId()) {
return;
}
MenuEntry[] entries = client.getMenuEntries();
MenuEntry lastEntry = entries[entries.length — 1];
if (lastEntry == swap) {
log.debug(«Detected duplicate»);
lastEntry.setType(MenuAction.CANCEL);
client.setMenuEntries(entries);
}
}
@Subscribe
private void onMenuOptionClicked(MenuOptionClicked event) {
if (swap == null) {
return;
}
if (event.getMenuEntry().getType() == swap.getType()) {
if (event.getMenuEntry().getOption().equals(swap.getOption())) {
event.consume();
MenuEntry[] entries = Arrays.copyOf(client.getMenuEntries(), client.getMenuEntries().length + 1);
entries[entries.length — 1] = swap;
swap.setType(MenuAction.CC_OP);
swap.setParam0(swapIndex);
swap.setParam1(swapIndex);
Arrays.sort(entries, Comparator.comparingInt(MenuEntry::getParam1));
for (int i = 0; i < entries.length; i++) {
entries[i].setParam0(i);
entries[i].setParam1(i);
}
swap = null;
swapIndex = 0;
client.setMenuEntries(entries);
}
}
}
}
[FILEPATH] plugins/xpglobes/src/main/java/com/xpglobes/GlobesMenuEntry.java [/FILEPATH]
package com.xpglobes;
import net.runelite.api.MenuEntry;
import net.runelite.api.MenuOpcode;
public class GlobesMenuEntry extends MenuEntry {
private String target;
private int index;
public GlobesMenuEntry(int id, int index, String option, String target, int identifier) {
this.param0 = id;
this.param1 = MenuOpcode.CC_OP.getId();
this.index = index;
this.option = option;
this.target = target;
this.identifier = identifier;
}
public int getIndex() {
return index;
}
public String getTarget() {
return target;
}
public void setIndex(int index) {
this.index = index;
}
public void setTarget(String target) {
this.target = target;
}
}
[FILEPATH] plugins/xpglobes/src/main/java/com/xpglobes/GlobeType.java [/FILEPATH]
package com.xpglobes;
public enum GlobeType {
NONE,
XP,
XP_PERCENT,
ACTIONS,
ACTIONS_PERCENT
}
[FILEPATH] plugins/xpglobes/src/main/java/com/xpglobes/XpGlobesPlugin.java [/FILEPATH]
package com.xpglobes;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Provides;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.*;
import net.runelite.api.events.*;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import javax.inject.Inject;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.List;
import static java.lang.Integer.parseInt;
@Slf4j
@PluginDescriptor(
name = "XP Globes",
description = "Adds XP globes that display real-time XP gains",
tags = {"skilling", "overlay", "xp", "globe", "minimap"}
)
public class XpGlobesPlugin extends Plugin {
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private XpGlobesConfig config;
@Inject
private XpGlobesOverlay overlay;
@Inject
private MenuEntrySwapper menuEntrySwapper;
private static final int MAX_GLOBES = 6;
private static final ImageIcon[] GLOBES_ICONS = new ImageIcon[MAX_GLOBES + 1];
private static final ImageIcon[] GLOBES_DISABLED_ICONS = new ImageIcon[MAX_GLOBES + 1];
private final Map
private final Map
private final Map
private final Map
private final Map
private final Map
private final Map
private final Map
private final Map
private final Map
private final Map
private final Map
private final List
private final List
private final Gson gson = new Gson();
private static final int LAST_OPENED = 527;
private Widget lastWidget;
private boolean showGlobes = false;
private boolean flashGlobes = false;
private int opened;
@Provides
XpGlobesConfig provideConfig(ConfigManager configManager) {
return configManager.getConfig(XpGlobesConfig.class);
}
@Override
protected void startUp() {
try {
reloadConfigurations(false);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void shutDown() {
xpGainedMap.clear();
actionsGainedMap.clear();
xpToLevelMap.clear();
actionsToLevelMap.clear();
lastXp.clear();
lastActions.clear();
lastBoostedXp.clear();
totalXpGainedMap.clear();
totalActionsGainedMap.clear();
isActive.clear();
wasActive.clear();
actionGained.clear();
overlayManager.remove(overlay);
showGlobes = false;
flashGlobes = false;
}
@Subscribe
public void onConfigChanged(ConfigChanged event) {
if (event.getKey().equals(«unlock»)) {
if (config.unlock()) {
reloadConfigurations(false);
}
} else {
reloadConfigurations(true);
}
}
@Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent event) {
if (event.getEventName().equals(«setXpGained»)) {
int skillIndex = parseInt(event.getArguments()[0].toString()) — 1;
int xpGained = parseInt(event.getArguments()[2].toString());
Skill skill = Skill.values()[skillIndex];
xpGainedMap.put(skill, xpGained);
xpToLevelMap.put(skill, client.getSkillExperiences()[skillIndex]);
isActive.put(skill, true);
wasActive.put(skill, false);
if (!lastXp.containsKey(skill)) {
lastXp.put(skill, client.getSkillExperiences()[skillIndex]);
lastBoostedXp.put(skill, (int) client.getVarbitValue(Varbits.getVarbit(skill, VarbitType.BOOSTED_XP_LEVEL)));
}
if (!totalXpGainedMap.containsKey(skill)) {
totalXpGainedMap.put(skill, 0);
}
totalXpGainedMap.put(skill, totalXpGainedMap.get(skill) + xpGained);
client.addChatMessage(ChatMessageType.GAMEMESSAGE, «», «Gained » + xpGained + » » + skill.getName() + » XP!», null);
} else if (event.getEventName().equals(«setActionsGained»)) {
int skillIndex = parseInt(event.getArguments()[0].toString()) — 1;
int actionsGained = parseInt(event.getArguments()[2].toString());
Skill skill = Skill.values()[skillIndex];
actionsGainedMap.put(skill, actionsGained);
actionsToLevelMap.put(skill, client.getSkillExperiences()[skillIndex]);
isActive.put(skill, true);
actionGained.put(skill, true);
wasActive.put(skill, false);
if (!lastActions.containsKey(skill)) {
lastActions.put(skill, client.getSkillExperiences()[skillIndex]);
}
if (!totalActionsGainedMap.containsKey(skill)) {
totalActionsGainedMap.put(skill, 0);
}
totalActionsGainedMap.put(skill, totalActionsGainedMap.get(skill) + actionsGained);
client.addChatMessage(ChatMessageType.GAMEMESSAGE, «», «Gained » + actionsGained + » » + skill.getName() + » actions!», null);
}
}
@Subscribe
public void onExperienceGained(ExperienceGained experienceGained) {
Skill skill = experienceGained.getSkill();
if (!xpGainedMap.containsKey(skill)) {
xpGainedMap.put(skill, 0);
}
xpGainedMap.put(skill, xpGainedMap.get(skill) + experienceGained.getExperience());
xpToLevelMap.put(skill, client.getSkillExperiences()[skill.ordinal()]);
isActive.put(skill, true);
wasActive.put(skill, false);
if (!lastXp.containsKey(skill)) {
lastXp.put(skill, client.getSkillExperiences()[skill.ordinal()]);
}
if (!totalXpGainedMap.containsKey(skill)) {
totalXpGainedMap.put(skill, 0);
}
totalXpGainedMap.put(skill, totalXpGainedMap.get(skill) + experienceGained.getExperience());
}
@Subscribe
public void onExperienceBoosted(ExperienceBoosted experienceBoosted) {
Skill skill = experienceBoosted.getSkill();
lastBoostedXp.put(skill, experienceBoosted.getExperience());
}
@Subscribe
public void onStatChanged(StatChanged statChanged) {
Skill skill = statChanged.getSkill();
if (!actionsGainedMap.containsKey(skill)) {
actionsGainedMap.put(skill, 0);
}
actionsGainedMap.put(skill, actionsGainedMap.get(skill) + statChanged.getChange());
actionsToLevelMap.put(skill, client.getSkillExperiences()[skill.ordinal()]);
isActive.put(skill, true);
actionGained.put(skill, true);
wasActive.put(skill, false);
if (!lastActions.containsKey(skill)) {
lastActions.put(skill, client.getSkillExperiences()[skill.ordinal()]);
}
if (!totalActionsGainedMap.containsKey(skill)) {
totalActionsGainedMap.put(skill, 0);
}
totalActionsGainedMap.put(skill, totalActionsGainedMap.get(skill) + statChanged.getChange());
}
@Subscribe
public void onMenuOpened(MenuOpened menuOpened) {
if (menuOpened.getMenuEntries()[0].getOption().equals(«Show XP Globes»)) {
menuList.clear();
globesMenuList.clear();
MenuEntry[] menuEntries = menuOpened.getMenuEntries();
for (MenuEntry menuEntry : menuEntries) {
if (menuEntry.getOption().equals(«Show XP Globes»)) {
menuList.add(menuEntry);
} else if (isGlobe(menuEntry.getOption())) {
globesMenuList.add(new GlobesMenuEntry(menuEntry.getParam0(), globesMenuList.size(), menuEntry.getOption(), menuEntry.getTarget(), menuEntry.getIdentifier()));
}
}
Collections.sort(globesMenuList, Comparator.comparing(GlobesMenuEntry::getIndex));
}
}
@Subscribe
public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked) {
if (!menuList.isEmpty() && menuOptionClicked.getMenuEntry().getOption().equals(«Show XP Globes»)) {
showGlobes =!showGlobes;
if (showGlobes) {
overlayManager.add(overlay);
} else {
overlayManager.remove(overlay);
}
menuOptionClicked.consume();
} else if (!globesMenuList.isEmpty() && isGlobe(menuOptionClicked.getMenuEntry().getOption())) {
GlobesMenuEntry globeEntry = globesMenuList.stream().filter(entry -> entry.getOption().equals(menuOptionClicked.getMenuEntry().getOption())).findFirst().orElse(null);
if (globeEntry!= null &&!menuOptionClicked.getMenuEntry().getOption().contains(«Disabled»)) {
Skill skill = Skill.valueOf(globeEntry.getTarget());
GlobeType globeType = config.getGlobe(skill);
switch (globeType) {
case XP:
config.setGlobe(skill, GlobeType.XP_PERCENT);
break;
case XP_PERCENT:
config.setGlobe(skill, GlobeType.ACTIONS);
break;
case ACTIONS:
config.setGlobe(skill, GlobeType.ACTIONS_PERCENT);
break;
case ACTIONS_PERCENT:
config.setGlobe(skill, GlobeType.XP);
break;
default:
break;
}
reloadConfigurations(true);
menuOptionClicked.consume();
}
}
}
@Subscribe
public void onVarbitChanged(VarbitChanged event) {
if (event.getVarbitId() == LAST_OPENED) {
opened = client.getVarps()[LAST_OPENED];
if (opened == 1 && lastWidget!= null) {
lastWidget.setOnMouseOverListener(null);
}
} else if (event.getVarbitId() == Varbits.MINIMAP_QUICK_RETURN.getId()) {
int quickReturn = client.getVarps()[Varbits.MINIMAP_QUICK_RETURN.getId()];
if (quickReturn == 1 && lastWidget!= null) {
lastWidget.setOnMouseOverListener(null);
lastWidget = null;
}
}
}
@Subscribe
public void onWidgetLoaded(WidgetLoaded widgetLoaded) {
if (widgetLoaded.getGroupId() == WidgetID.MINIMAP_GROUP_ID) {
Widget widget = client.getWidget(WidgetInfo.MINIMAP_QUICK_RETURN);
if (widget!= null) {
lastWidget = widget;
widget.setOnMouseOverListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
flashGlobes = true;
}
@Override
public void mouseExited(MouseEvent e) {
flashGlobes = false;
}
});
}
}
}
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged) {
if (gameStateChanged.getGameState() == GameState.LOGGED_IN) {
xpGainedMap.clear();
actionsGainedMap.clear();
xpToLevelMap.clear();
actionsToLevelMap.clear();
lastXp.clear();
lastActions.clear();
lastBoostedXp.clear();
totalXpGainedMap.clear();
totalActionsGainedMap.clear();
isActive.clear();
wasActive.clear();
actionGained.clear();
lastWidget = client.getWidget(WidgetInfo.MINIMAP_QUICK_RETURN);
if (lastWidget!= null) {
lastWidget.setOnMouseOverListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
flashGlobes = true;
}
@Override
public void mouseExited(MouseEvent e) {
flashGlobes = false;
}
});
}
opened = client.getVarps()[LAST_OPENED];
if (opened == 0 && lastWidget!= null) {
lastWidget.setOnMouseOverListener(null);
}
}
}
@Subscribe
public void onGameTick(GameTick gameTick) {
for (Skill skill : Skill.values()) {
if (isActive.getOrDefault(skill, false)) {
if (wasActive.getOrDefault(skill, false)) {
if (!actionGained.getOrDefault(skill, false)) {
int currentXp = client.getSkillExperiences()[skill.ordinal()];
int lastX = lastXp.getOrDefault(skill, 0);
xpGainedMap.put(skill, currentXp — lastX);
xpToLevelMap.put(skill, client.getSkillExperiences()[skill.ordinal()]);
totalXpGainedMap.put(skill, totalXpGainedMap.getOrDefault(skill, 0) + currentXp — lastX);
lastXp.put(skill, currentXp);
} else {
actionGained.put(skill, false);
}
int currentActions = (int) client.getSkillBoostedLevels()[skill.ordinal()];
int lastA = lastActions.getOrDefault(skill, 0);
// actionsGainedMap.put(skill, (int) (client.getSkillExperiences()[skill.ordinal()] — client.getSkillBoostedLevels()[skill.ordinal()] * client.getRealSkillLevel(skill) * config.actionsModifier()));
actionsGainedMap.put(skill, currentActions — lastA);
actionsToLevelMap.put(skill, client.getSkillExperiences()[skill.ordinal()]);
totalActionsGainedMap.put(skill, totalActionsGainedMap.getOrDefault(skill, 0) + currentActions — lastA);
lastActions.put(skill, currentActions);
wasActive.put(skill, false);
} else {
wasActive.put(skill, true);
}
} else {
wasActive.put(skill, false);
}
}
}
public boolean isGlobe(String option) {
return option.startsWith(«
Map
configMap.forEach((key, value) -> {
if (value.contains(«,»)) {
String[] values = value.split(«,»);
switch (values[0]) {
case «GLOBE_TYPE»:
config.setGlobe(Skill.valueOf(key), GlobeType.valueOf(values[1]));
break;
case «COLOR»:
config.setColor(Skill.valueOf(key), new Color(parseInt(values[1]), parseInt(values[2]), parseInt(values[3])));
break;
}
} else {
config.setSkillEnabled(Skill.valueOf(key), Boolean.parseBoolean(value));
}
});
if (refresh) {
client.refreshChat();
}
} catch (Exception e) {
log.error(«Error loading configurations», e);
}
}
static {
for (int i = 1; i <= MAX_GLOBES; i++) {
GLOBES_ICONS[i] = new ImageIcon(XpGlobesPlugin.class.getResource("/globes/globe" + i + ".png"));
GLOBES_DISABLED_ICONS[i] = new ImageIcon(XpGlobesPlugin.class.getResource("/globes/globe" + i + "_disabled.png"));
}
}
public Client getClient() {
return client;
}
public Map
return xpGainedMap;
}
public Map
return actionsGainedMap;
}
public Map
return xpToLevelMap;
}
public Map
return actionsToLevelMap;
}
public Map
return totalXpGainedMap;
}
public Map
return totalActionsGainedMap;
}
public XpGlobesConfig getConfig() {
return config;
}
public boolean isShowGlobes() {
return showGlobes;
}
public boolean isFlashGlobes() {
return flashGlobes;
}
public static ImageIcon[] getGlobesIcons() {
return GLOBES_ICONS;
}
public static ImageIcon[] getGlobesDisabledIcons() {
return GLOBES_DISABLED_ICONS;
}
public List
return menuList;
}
public List
return globesMenuList;
}
public int getOpened() {
return opened;
}
}
[FILEPATH] plugins/xpglobes/src/main/java/com/xpglobes/XpGlobesOverlay.java [/FILEPATH]
package com.xpglobes;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Skill;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.OverlayUtil;
import javax.inject.Inject;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Map;
import static com.xpglobes.XpGlobesPlugin.*;
@Slf4j
public class XpGlobesOverlay extends XpGlobesOverlayBase {
private static final int GLOBE_WIDTH = 16;
private static final int GLOBE_HEIGHT = 16;
private static final int GLOBE_SPACING = 1;
@Inject
private Client client;
@Inject
private XpGlobesPlugin xpGlobesPlugin;
@Inject
private XpGlobesConfig config;
public XpGlobesOverlay() {
super(OverlayPriority.HIGHEST);
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
}
@Override
public Dimension render(Graphics2D graphics) {
if (!xpGlobesPlugin.isShowGlobes() &&!xpGlobesPlugin.isFlashGlobes()) {
if (this.getLayer()!= OverlayLayer.ABOVE_WIDGETS) {
setLayer(OverlayLayer.ABOVE_WIDGETS);
}
return null;
}
int x = 0;
int y = 0;
int width = 0;
int height = 0;
Map
Map
Map
Map
Map
Map
for (Skill skill : Skill.values()) {
if (config.getSkillEnabled(skill) && (xpGlobesPlugin.isFlashGlobes() || totalXpGainedMap.containsKey(skill))) {
int iconWidth = GLOBE_WIDTH;
int iconHeight = GLOBE_HEIGHT;
int iconX = (width — iconWidth) / 2;
int iconY = height;
boolean drawIcon = true;
boolean drawDisabled = false;
BufferedImage icon;
switch (config.getGlobe(skill)) {
case XP:
icon = getTexturedIcon(config.getColor(skill), xpGainedMap.getOrDefault(skill, 0), xpToLevelMap.get(skill), false);
break;
case XP_PERCENT:
icon = getTexturedIcon(config.getColor(skill), xpGainedMap.getOrDefault(skill, 0), xpToLevelMap.get(skill), true);
break;
case ACTIONS:
if (actionsGainedMap.containsKey(skill) && actionsGainedMap.get(skill) > 0) {
icon = getTexturedIcon(config.getColor(skill), actionsGainedMap.get(skill), actionsToLevelMap.get(skill), false);
} else {
drawIcon = false;
icon = getGlobesDisabledIcons()[skill.ordinal()];
drawDisabled = true;
}
break;
case ACTIONS_PERCENT:
if (actionsGainedMap.containsKey(skill) && actionsGainedMap.get(skill) > 0) {
icon = getTexturedIcon(config.getColor(skill), actionsGainedMap.get(skill), actionsToLevelMap.get(skill), true);
} else {
drawIcon = false;
icon = getGlobesDisabledIcons()[skill.ordinal()];
drawDisabled = true;
}
break;
default:
icon = getGlobesIcons()[skill.ordinal()];
break;
}
if (drawIcon) {
graphics.drawImage(icon, iconX + x, iconY + y, iconWidth, iconHeight, null);
} else if (drawDisabled) {
graphics.drawImage(icon, iconX + x, iconY + y, iconWidth, iconHeight, null);
}
width = Math.max(width, iconWidth);
height += iconHeight + GLOBE_SPACING;
}
}
width += GLOBE_SPACING;
height -= GLOBE_SPACING;
if (xpGlobesPlugin.isFlashGlobes()) {
setLayer(OverlayLayer.ALWAYS_ON_TOP);
Composite oldComposite = graphics.getComposite();
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
graphics.setColor(Color.BLACK);
graphics.fillRect(x, y, width — 5, height);
graphics.setComposite(oldComposite);
}
if (!xpGlobesPlugin.getMenuList().isEmpty() && xpGlobesPlugin.getOpened() == 1) {
int xOffset = client.getWidget(WidgetInfo.MINIMAP_DRAW_AREA).getBounds().x;
int yOffset = client.getWidget(WidgetInfo.MINIMAP_DRAW_AREA).getBounds().y;
int menuSize = 0;
for (MenuEntry menuEntry : xpGlobesPlugin.getMenuList()) {
Point canvasPoint = new Point(xOffset, yOffset + (menuSize * 15));
Point screenPoint = new Point(canvasPoint.x + client.getCanvas().getLocationOnScreen().x, canvasPoint.y + client.getCanvas().getLocationOnScreen().y);
if (new Rectangle(screenPoint.x, screenPoint.y, client.getWidget(WidgetInfo.MINIMAP_DRAW_AREA).getWidth(), 15).contains(MouseInfo.getPointerInfo().getLocation())) {
menuEntry.setParam1(-1);
}
OverlayUtil.renderTextLocation(graphics, canvasPoint, menuEntry.getOption(), ColorsMenu.GLOBE_MENU_COLOR);
menuSize++;
}
for (GlobesMenuEntry globeEntry : xpGlobesPlugin.getGlobesMenuList()) {
Point canvasPoint = new Point(xOffset, yOffset + (menuSize * 15));
Point screenPoint = new Point(canvasPoint.x + client.getCanvas().getLocationOnScreen().x, canvasPoint.y + client.getCanvas().getLocationOnScreen().y);
if (new Rectangle(screenPoint.x, screenPoint.y, client.getWidget(WidgetInfo.MINIMAP_DRAW_AREA).getWidth(), 15).contains(MouseInfo.getPointerInfo().getLocation())) {
globeEntry.setParam1(-1);
}
OverlayUtil.renderTextLocation(graphics, canvasPoint, globeEntry.getOption(), ColorsMenu.GLOBE_MENU_COLOR);
menuSize++;
}
}
return new Dimension(width, height);
}
private BufferedImage getTexturedIcon(Color color, int gained, int toLevel, boolean percent) {
int iconSize = 16;
BufferedImage image = new BufferedImage(iconSize, iconSize, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(color);
g.fillRect(0, 0, iconSize, iconSize);
g.dispose();
return image;
}
}
[FILEPATH] plugins/xpglobes/src/main/java/com/xpglobes/ColorsMenu.java [/FILEPATH]
package com.xpglobes;
import java.awt.*;
public class ColorsMenu {
public static final Color GLOBE_MENU_COLOR = new Color(255, 215, 0);
public static final Color GLOBE_MENU_DISABLED_COLOR = new Color(127, 127, 127);
}
[FILEPATH] plugins/xpglobes/src/main/java/com/xpglobes/XpGlobesOverlayBase.java [/FILEPATH]
package com.xpglobes;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition;
public class XpGlobesOverlayBase extends Overlay {
private OverlayPosition position;
@Override
public OverlayPosition position() {
return position;
}
public void setPosition(OverlayPosition position) {
this.position = position;
}
}
[FILEPATH] plugins/xpglobes/src/main/java/com/xpglobes/XpGlobesConfig.java [/FILEPATH]
package com.xpglobes;
import com.google.inject.Singleton;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.Skill;
import net.runelite.client.config.*;
import java.awt.*;
@Getter
@Setter
@AllArgsConstructor
public class XpGlobesConfig extends Config
{
private static final String CONFIG_GROUP = «XpGlobes»;
private static final String SKILL_ENABLED_KEY = «skillEnabled»;
private static final String GLOBE_TYPE_KEY = «globeType»;
private static final String SKILL_COLOR_KEY = «skillColor»;
@ConfigSection(
name = «Globes Configuration URL»,
description = «URL to load globes configurations from»,
position = 0
)
public String configUrl = «https://raw.githubusercontent.com/SkillerTrapsin/RunelitePlugins/main/xpglobes/config.json»;
@Getter
@Setter
@AllArgsConstructor
public enum GlobeType implements ConfigEnum
{
NONE(«None», «No globe»),
XP(«XP», «XP gained»),
XP_PERCENT(«XP %», «XP gained percent»),
ACTIONS(«Actions», «Actions gained»),
ACTIONS_PERCENT(«Actions %», «Actions gained percent»);
private final String key;
private final String name;
@Override
public String key()
{
return key;
}
@Override
public String toString()
{
return name;
}
}
@ConfigItem(
keyName = «unlock»,
name = «Unlock»,
description = «Unlock all skills for configuration»,
position = 1
)
default boolean unlock()
{
return false;
}
@ConfigItem(
keyName = SKILL_ENABLED_KEY,
name = «Enabled»,
description = «Enable this skill for the XP globe overlay»,
position = 2
)
default boolean skillEnabled(Skill skill)
{
return false;
}
@ConfigItem(
keyName = GLOBE_TYPE_KEY,
name = «Globe Type»,
description = «The type of globe to display for this skill»,
position = 3
)
default GlobeType globe(Skill skill)
{
return GlobeType.NONE;
}
@ConfigItem(
keyName = SKILL_COLOR_KEY,
name = «Color»,
description = «The color of the globe for this skill»,
position = 4
)
default Color color(Skill skill)
{
return Color.WHITE;
}
// Custom methods to set config values
public void setSkillEnabled(Skill skill, boolean enabled)
{
setting(SKILL_ENABLED_KEY, skill, enabled);
}
public void setGlobe(Skill skill, GlobeType globeType)
{
setting(GLOBE_TYPE_KEY, skill, globeType);
}
public void setColor(Skill skill, Color color)
{
setting(SKILL_COLOR_KEY, skill, color);
}
private
{
String fullKey = key + «.» + skill.name();
setValue(fullKey, value);
}
}
[FILEPATH] plugins/template4/src/main/java/com/rspsi/plugin/Template4PluginConfig.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Singleton;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigTitleSection;
import net.runelite.client.config.Title;
import net.runelite.client.config.Range;
@ConfigGroup(«template4»)
public interface Template4PluginConfig extends Config {
@Getter
@Setter
@ConfigTitleSection(
keyName = «instructionsTitle»,
name = «Instructions»,
description = «»,
position = 0
)
default Title instructionsTitle() {
return new Title();
}
@ConfigItem(
position = 1,
keyName = «instructions»,
name = «Instructions»,
description = «»
)
default String instructions() {
return «Welcome to the template plugin! Here’s how you can set it up:\n» +
«1….\n» +
«2….\n» +
«3….\n»;
}
@ConfigTitleSection(
keyName = «settingsTitle»,
name = «Settings»,
description = «»,
position = 2
)
default Title settingsTitle() {
return new Title();
}
@ConfigItem(
position = 3,
keyName = «exampleSetting»,
name = «Example Setting»,
description = «An example setting that can be toggled on or off.»
)
default boolean exampleSetting() {
return false;
}
@Range(
min = 1,
max = 100
)
@ConfigItem(
position = 4,
keyName = «exampleNumber»,
name = «Example Number»,
description = «An example number that can be set between 1 and 100.»
)
default int exampleNumber() {
return 50;
}
}
[FILEPATH] plugins/template4/src/main/java/com/rspsi/plugin/Template4Plugin.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Provides;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.events.GameTick;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import javax.inject.Inject;
@Slf4j
@PluginDescriptor(
name = «Template 4»,
description = «A template plugin for RuneLite»,
enabledByDefault = false
)
public class Template4Plugin extends Plugin {
@Inject
private Client client;
@Inject
private Template4PluginConfig config;
@Provides
Template4PluginConfig provideConfig(ConfigManager configManager) {
return configManager.getConfig(Template4PluginConfig.class);
}
@Override
protected void startUp() {
log.info(«Template 4 plugin started!»);
}
@Override
protected void shutDown() {
log.info(«Template 4 plugin stopped!»);
}
@Subscribe
public void onGameTick(GameTick event) {
// Code that runs every game tick
}
}
[FILEPATH] plugins/template1/src/main/java/com/rspsi/plugin/Template1Plugin.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Provides;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.*;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import javax.inject.Inject;
@Slf4j
@PluginDescriptor(
name = «Template 1»,
description = «A template plugin for RuneLite»,
enabledByDefault = false
)
public class Template1Plugin extends Plugin {
@Inject
private Client client;
@Inject
private Template1PluginConfig config;
@Provides
Template1PluginConfig provideConfig(ConfigManager configManager) {
return configManager.getConfig(Template1PluginConfig.class);
}
@Override
protected void startUp() {
log.info(«Template 1 plugin started!»);
}
@Override
protected void shutDown() {
log.info(«Template 1 plugin stopped!»);
}
@Subscribe
public void onGameStateChanged(GameStateChanged event) {
if (event.getGameState() == GameState.LOGIN_SCREEN) {
.client.addChatMessage(ChatMessageType.GAMEMESSAGE, «», «Welcome to RuneLite!», null);
}
}
@Subscribe
public void onChatMessage(ChatMessage event) {
if (event.getType() == ChatMessageType.GAMEMESSAGE) {
log.info(«Game message: {}», event.getMessage());
}
}
@Subscribe
public void onCommandExecuted(CommandExecuted commandExecuted) {
String command = commandExecuted.getCommand();
if (command.equals(«template»)) {
client.addChatMessage(ChatMessageType.GAMEMESSAGE, «», «Template command executed!», null);
}
}
}
[FILEPATH] plugins/template1/src/main/java/com/rspsi/plugin/Template1PluginConfig.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Singleton;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigTitleSection;
import net.runelite.client.config.Title;
@Singleton
public class Template1PluginConfig extends Config {
@ConfigTitleSection(
keyName = «instructionsTitle»,
name = «Instructions»,
description = «»,
position = 0
)
public Title instructionsTitle = new Title();
public String instructions = «Welcome to the template plugin! Here’s how you can set it up:\n» +
«1….\n» +
«2….\n» +
«3….»;
}
[FILEPATH] plugins/template3/src/main/java/com/rspsi/plugin/Template3Plugin.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Provides;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.*;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import javax.inject.Inject;
@Slf4j
@PluginDescriptor(
name = «Template 3»,
description = «A template plugin for RuneLite»,
enabledByDefault = false
)
public class Template3Plugin extends Plugin {
@Inject
private Client client;
@Inject
private Template3PluginConfig config;
@Provides
Template3PluginConfig provideConfig(ConfigManager configManager) {
return configManager.getConfig(Template3PluginConfig.class);
}
@Override
protected void startUp() {
log.info(«Template 3 plugin started!»);
}
@Override
protected void shutDown() {
log.info(«Template 3 plugin stopped!»);
}
@Subscribe
public void onGameStateChanged(GameStateChanged event) {
if (event.getGameState() == GameState.LOGIN_SCREEN) {
client.addChatMessage(ChatMessageType.GAMEMESSAGE, «», «Welcome to RuneLite!», null);
}
}
@Subscribe
public void onChatMessage(ChatMessage event) {
if (event.getType() == ChatMessageType.GAMEMESSAGE) {
log.info(«Game message: {}», event.getMessage());
}
}
@Subscribe
public void onCommandExecuted(CommandExecuted commandExecuted) {
String command = commandExecuted.getCommand();
if (command.equals(«template»)) {
client.addChatMessage(ChatMessageType.GAMEMESSAGE, «», «Template command executed!», null);
}
}
}
[FILEPATH] plugins/template3/src/main/java/com/rspsi/plugin/Template3PluginConfig.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Singleton;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigTitleSection;
import net.runelite.client.config.Title;
@Singleton
public class Template3PluginConfig extends Config {
@ConfigTitleSection(
keyName = «instructionsTitle»,
name = «Instructions»,
description = «»,
position = 0
)
public Title instructionsTitle = new Title();
public String instructions = «Welcome to the template plugin! Here’s how you can set it up:\n» +
«1….\n» +
«2….\n» +
«3….»;
}
[FILEPATH] plugins/template5/src/main/java/com/rspsi/plugin/Template5PluginConfig.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Singleton;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigTitleSection;
import net.runelite.client.config.Title;
import net.runelite.client.config.Range;
@ConfigGroup(«template5»)
public interface Template5PluginConfig extends Config {
@Getter
@Setter
@ConfigTitleSection(
keyName = «instructionsTitle»,
name = «Instructions»,
description = «»,
position = 0
)
default Title instructionsTitle() {
return new Title();
}
@ConfigItem(
position = 1,
keyName = «instructions»,
name = «Instructions»,
description = «»
)
default String instructions() {
return «Welcome to the template plugin! Here’s how you can set it up:\n» +
«1….\n» +
«2….\n» +
«3….\n»;
}
@ConfigTitleSection(
keyName = «settingsTitle»,
name = «Settings»,
description = «»,
position = 2
)
default Title settingsTitle() {
return new Title();
}
@ConfigItem(
position = 3,
keyName = «exampleSetting»,
name = «Example Setting»,
description = «An example setting that can be toggled on or off.»
)
default boolean exampleSetting() {
return false;
}
@Range(
min = 1,
max = 100
)
@ConfigItem(
position = 4,
keyName = «exampleNumber»,
name = «Example Number»,
description = «An example number that can be set between 1 and 100.»
)
default int exampleNumber() {
return 50;
}
}
[FILEPATH] plugins/template2/src/main/java/com/rspsi/plugin/Template2PluginConfig.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Singleton;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigTitleSection;
import net.runelite.client.config.Title;
@Singleton
public class Template2PluginConfig extends Config {
@ConfigTitleSection(
keyName = «instructionsTitle»,
name = «Instructions»,
description = «»,
position = 0
)
public Title instructionsTitle = new Title();
public String instructions = «Welcome to the template plugin! Here’s how you can set it up:\n» +
«1….\n» +
«2….\n» +
«3….»;
}
[FILEPATH] plugins/template2/src/main/java/com/rspsi/plugin/Template2Plugin.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Provides;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.*;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import javax.inject.Inject;
@Slf4j
@PluginDescriptor(
name = «Template 2»,
description = «A template plugin for RuneLite»,
enabledByDefault = false
)
public class Template2Plugin extends Plugin {
@Inject
private Client client;
@Inject
private Template2PluginConfig config;
@Provides
Template2PluginConfig provideConfig(ConfigManager configManager) {
return configManager.getConfig(Template2PluginConfig.class);
}
@Override
protected void startUp() {
log.info(«Template 2 plugin started!»);
}
@Override
protected void shutDown() {
log.info(«Template 2 plugin stopped!»);
}
@Subscribe
public void onGameStateChanged(GameStateChanged event) {
if (event.getGameState() == GameState.LOGIN_SCREEN) {
client.addChatMessage(ChatMessageType.GAMEMESSAGE, «», «Welcome to RuneLite!», null);
}
}
@Subscribe
public void onChatMessage(ChatMessage event) {
if (event.getType() == ChatMessageType.GAMEMESSAGE) {
log.info(«Game message: {}», event.getMessage());
}
}
@Subscribe
public void onCommandExecuted(CommandExecuted commandExecuted) {
String command = commandExecuted.getCommand();
if (command.equals(«template»)) {
client.addChatMessage(ChatMessageType.GAMEMESSAGE, «», «Template command executed!», null);
}
}
}
[FILEPATH] plugins/crystalpeaks/src/main/java/com/rspsi/plugin/CrystalPeaksPlugin.java [/FILEPATH]
package com.rspsi.plugin;
import com.google.inject.Provides;
import com.rspsi.config.CrystalPeaksConfig;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.VarbitChanged;
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;
import net.runelite.client.util.Text;
import javax.inject.Inject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@PluginDescriptor(
name = «Crystal Peaks»,
description = «One click PSI crafting»
)
public class CrystalPeaksPlugin extends Plugin {
@Inject
private Client client;
@Inject
private CrystalPeaksConfig config;
@Provides
CrystalPeaksConfig provideConfig(ConfigManager configManager) {
return configManager.getConfig(CrystalPeaksConfig.class);
}
@Override
public void startUp() throws Exception {
}
@Override
public void shutDown() throws Exception {
}
@Subscribe
public void onConfigChanged(ConfigChanged event) {
if (!event.getGroup().equals(«crystalpeaks»))
return;
if (config.autoUpdate()) {
try {
URL url = new URL(«https://raw.githubusercontent.com/SkillerTrapsin/RunelitePlugins/main/crystalpeaks/config.json»);
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
while ((line = reader.readLine())!= null) {
try {
Pattern pattern = Pattern.compile(«(\\d+):(\\d+)»);
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
int varbit = Integer.parseInt(matcher.group(1));
int value = Integer.parseInt(matcher.group(2));
client.getVarps()[varbit] = value;
}
} catch (NumberFormatException e) {
log.warn(«Failed to parse config line: » + line);
}
}
} catch (Exception e) {
log.warn(«Failed to load config», e);
}
client.refreshChat();
}
}
@Subscribe
public void onGameStateChanged(GameStateChanged event) {
if (event.getGameState() == GameState.LOGGED_IN) {
if (config.autoUpdate()) {
try {
URL url = new URL(«https://raw.githubusercontent.com/SkillerTrapsin/RunelitePlugins/main/crystalpeaks/config.json»);
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
while ((line = reader.readLine())!= null) {
try {
Pattern pattern = Pattern.compile(«(\\d+):(\\d+)»);
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
int varbit = Integer.parseInt(matcher.group(1));
int value = Integer.parseInt(matcher.group(2));
client.getVarps()[varbit] = value;
}
} catch (NumberFormatException e) {
log.warn(«Failed to parse config line: » + line);
}
}
} catch (Exception e) {
log.warn(«Failed to load config», e);
}
client.refreshChat();
}
}
}
}
[FILEPATH] plugins/crystalpeaks/src/main/java/com/rspsi/config/CrystalPeaksConfig.java [/FILEPATH]
package com.rspsi.config;
import com.google.inject.Singleton;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigTitleSection;
import net.runelite.client.config.Title;
@Singleton
public class CrystalPeaksConfig extends Config
{
@ConfigTitleSection(
keyName = «instructionsTitle»,
name = «Instructions»,
description = «»,
position = 0
)
public Title instructionsTitle = new Title();
@ConfigItem(
position = 1,
keyName = «instructions»,
name = «Instructions»,
description = «»
)
public String instructions = «Crystal Peaks Plugin:\n\n» +
«This plugin aims to automate the usage of the PSI in Crystal Peaks.\n\n» +
«To begin, simply login and let the plugin handle the rest!\n\n» +
«If you’re feeling adventurous, you can modify the config below.\n\n» +
«Happy botting!»;
@ConfigTitleSection(
keyName = «settingsTitle»,
name = «Settings»,
description = «»,
position = 2
)
public Title settingsTitle = new Title();
@ConfigItem(
position = 3,
keyName = «autoUpdate»,
name = «Auto Update»,
description = «Automatically update the PSI values from the config file»
)
public boolean autoUpdate = true;
}
[FILEPATH] plugins/agility/src/main/java/com/rspsi/overlay/AgilityOverlayUtil.java [/FILEPATH]
package com.rspsi.overlay;
import com.rspsi.Main AgileTimer;
import com.rspsi.models.AagilityCourse.Obstacle;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.*;
import net.runelite.client.ui.overlay.OverlayUtil;
import java.awt.*;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import static com.rspsi.Main AgileCourseData magneticMinimapLocations;
import static com.rspsi.Main AgileCourseData tileSize;
@Slf4j
public class AgilityOverlayUtil {
private static final String AGILITY_COURSE_NAME = «All»;
private static final String MARK_OF_GRACE_NAME = «Mark of Grace»;
private static final int CLICK_BOX_SIZE = 4;
private static final int MINIMAP_ICON_SIZE = 5;
/**
* Draw’s the Rectangle with a label on the game screen
*/
public static void drawTile(Client client, Graphics2D graphics, Obstacle obstacle, boolean useClipping, String text, Color color, boolean outline) {
if (obstacle!= null && obstacle.getLocation()!= null) {
if (useClipping) {
drawClippedRectangle(graphics, color, getTileRectangle(client, obstacle.getLocation()), outline, text);
} else {
drawUnclippedRectangle(graphics, color, getTileRectangle(client, obstacle.getLocation()), outline, text);
}
}
}
/**
* Draw’s the Rectangle with a label on the game screen using the obstacle outline
*/
public static void drawTile(Client client, Graphics2D graphics, Obstacle obstacle, boolean useClipping, boolean obtacleOutline, String text, Color color, boolean outline) {
if (obstacle!= null && obstacle.getLocation()!= null) {
if (useClipping) {
if (obtacleOutline) {
drawClippedRectangle(graphics, color, getObstacleRectangle(client, obstacle), outline, text);
} else {
drawClippedRectangle(graphics, color, getTileRectangle(client, obstacle.getLocation()), outline, text);
}
} else {
if (obtacleOutline) {
drawUnclippedRectangle(graphics, color, getObstacleRectangle(client, obstacle), outline, text);
} else {
drawUnclippedRectangle(graphics, color, getTileRectangle(client, obstacle.getLocation()), outline, text);
}
}
}
}
private static void drawClippedRectangle(Graphics2D graphics, Color color, Rectangle rectangle, boolean outline, String text) {
if (text!= null) {
OverlayUtil.renderTextLocation(graphics, new Point(rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2), text, color);
}
graphics.setClip(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
if (outline) {
graphics.setColor(Color.BLACK);
graphics.drawRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
}
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 50));
graphics.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
}
private static void drawUnclippedRectangle(Graphics2D graphics, Color color, Rectangle rectangle, boolean outline, String text) {
if (text!= null) {
OverlayUtil.renderTextLocation(graphics, new Point(rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2), text, color);
}
if (outline) {
graphics.setColor(Color.BLACK);
}
graphics.drawRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 50));
graphics.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
}
/**
* Draw’s the minimap icon
*/
public static void drawMinimapIcon(Client client, Graphics2D graphics, Obstacle obstacle, Color color) {
if (obstacle.getLocation()!= null && magneticMinimapLocations.get(obstacle.getId())!= null) {
// Find the location of the obstacle on the minimap
net.runelite.api.Point minimapLocation = getMinimapLocation(client, obstacle.getLocation
