Дома из бруса: преимущества и нюансы строительства

Введение:
Дома из бруса становятся все более популярными среди тех, кто хочет построить свой собственный дом. Такие дома имеют множество преимуществ, включая экологичность, долговечность и эстетичный внешний вид. В этой статье мы рассмотрим основные особенности строительства домов из бруса, а также дадим вам полезные советы и рекомендации по выбору материалов и технологий.

Преимущества домов из бруса

Дома из бруса имеют ряд преимуществ перед другими видами домов:

  • Экологичность и натуральность материалов
  • Высокая прочность и долговечность
  • Хорошая теплоизоляция
  • Эстетичный внешний вид
  • Быстрое возведение

Как выбрать качественный брус для строительства дома?

Выбор качественного бруса — один из ключевых моментов в строительстве дома из бруса. Вот несколько советов, которые помогут вам сделать правильный выбор:

  1. Обратите внимание на влажность бруса. Она должна быть не более 20%.
  2. Проверьте брус на наличие трещин, сучков и других дефектов.
  3. Убедитесь, что брус был обработан антисептиками и противопожарными средствами.
  4. Выбирайте брус из дерева, выращенного в вашем регионе. Это обеспечит лучшую адаптацию к местным климатическим условиям.
  5. Обратитесь к проверенным и надежным поставщикам бруса.

Ответы на популярные вопросы

Вопрос 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 infix = convertExpressionToInfix(expression);
List rpn = infixToRPN(infix);
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 stack = new 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 convertExpressionToInfix(String expression) throws PluginException {
List infix = new ArrayList<>();
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 infixToRPN(List infix) {
List output = new ArrayList<>();
Stack stack = new 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 rpn) {
Stack stack = new 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 plugins = new LinkedHashMap<>();

@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 = new ArrayList<>();
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 = new ArrayList<>();
itemNames.add(itemName);

sendSalesData(itemNames, quantity, price, currency);
}
}
}

private void sendSalesData(List itemNames, int quantity, int price, String currency) {
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 itemNames;
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 xpGainedMap = new EnumMap<>(Skill.class);
private final Map actionsGainedMap = new EnumMap<>(Skill.class);
private final Map xpToLevelMap = new EnumMap<>(Skill.class);
private final Map actionsToLevelMap = new EnumMap<>(Skill.class);
private final Map isActive = new EnumMap<>(Skill.class);
private final Map wasActive = new EnumMap<>(Skill.class);
private final Map actionGained = new EnumMap<>(Skill.class);
private final Map lastXp = new EnumMap<>(Skill.class);
private final Map lastActions = new EnumMap<>(Skill.class);
private final Map lastBoostedXp = new EnumMap<>(Skill.class);
private final Map totalXpGainedMap = new EnumMap<>(Skill.class);
private final Map totalActionsGainedMap = new EnumMap<>(Skill.class);
private final List menuList = new ArrayList<>();
private final List globesMenuList = new ArrayList<>();
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(«>() {}.getType();
Map configMap = gson.fromJson(reader, type);
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 getXpGainedMap() {
return xpGainedMap;
}

public Map getActionsGainedMap() {
return actionsGainedMap;
}

public Map getXpToLevelMap() {
return xpToLevelMap;
}

public Map getActionsToLevelMap() {
return actionsToLevelMap;
}

public Map getTotalXpGainedMap() {
return totalXpGainedMap;
}

public Map getTotalActionsGainedMap() {
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 getMenuList() {
return menuList;
}

public List getGlobesMenuList() {
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 xpGainedMap = xpGlobesPlugin.getXpGainedMap();
Map actionsGainedMap = xpGlobesPlugin.getActionsGainedMap();
Map xpToLevelMap = xpGlobesPlugin.getXpToLevelMap();
Map actionsToLevelMap = xpGlobesPlugin.getActionsToLevelMap();
Map totalXpGainedMap = xpGlobesPlugin.getTotalXpGainedMap();
Map totalActionsGainedMap = xpGlobesPlugin.getTotalActionsGainedMap();

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 void setting(String key, Skill skill, T value)
{
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

Оцените статью
Строительный Эксперт - inhomes.ru
Добавить комментарий