Runelite Plugins Development: PvP Helper – Part 2

Introduction to runelite plugins Development Part 2:

Welcome back to the electrifying world of runelite plugins PvP development! In Part 1, we delved into the intricate workings of the RuneLite API and began crafting the foundation for our ultimate PvP revolution. Now, brace yourselves as we venture further into the realm of player versus player combat enhancement with Part 2 of our journey.

Github Source: https://github.com/slyautomation/osrs_pvp_tutorial

In this installment, we’ll dive deeper into the coding process, exploring essential classes and functionalities that will elevate your PvP encounters to new heights. From configuring plugin functionalities to implementing event listeners and displaying crucial PvP information, we’ll cover it all.

But that’s not all! We’ll also introduce you to utility classes designed to streamline PvP activities, making your gameplay experience smoother and more immersive than ever before.

So, gear up, sharpen your skills, and get ready to unleash the full potential of your PvP adventures with the runelite PvP plugins. Let’s embark on this exhilarating journey of development and innovation together!

Text Component

This code defines a Java class named TextComponent that implements the RenderableEntity interface. The purpose of this class is to render text with optional color and border information. Let’s break down the key components of the code:

  1. Class Structure:
    • TextComponent is a class that implements the RenderableEntity interface.
  2. Fields:
    • text: Represents the text content that will be rendered.
    • position: Represents the position (x, y) where the text will be rendered.
    • color: Represents the color of the text.
    • borderColor: Represents the color of the text border.
  3. Constants:
    • COL_TAG_REGEX: A regular expression for identifying color tags in the text. It matches patterns like <col=RRGGBB> where RRGGBB represents a hexadecimal color code.
    • COL_TAG_PATTERN_W_LOOKAHEAD: A pattern with a positive lookahead for identifying color tags.
    • COL_TAG_PATTERN: A pattern for identifying color tags in the text.
  4. Static Method:
    • textWithoutColTags: A static method that removes color tags from a given text using the COL_TAG_PATTERN.
  5. Render Method:
    • render: The method responsible for rendering the text. It calculates the dimensions of the rendered text and applies color and border effects if color tags are present in the text.
  6. Helper Method:
    • renderText: A helper method that performs the actual rendering of text. It takes care of drawing the text, its border, and applying alpha compositing.
  7. Rendering Logic:
    • The code checks if the text contains color tags using COL_TAG_PATTERN.matcher(text).find().
    • If color tags are present, it splits the text based on color tags and renders each segment separately, applying the corresponding colors.
    • If no color tags are present, it renders the entire text with the specified color and border color.
  8. Rendering Technique:
    • The rendering technique involves creating a glyph vector from the text, computing the text shape, and then drawing the text and its border separately.
  9. Alpha Compositing:
    • The code uses alpha compositing to draw the text border. It sets the composite to AlphaComposite.Src to replace the pixels instead of overlaying them.

In summary, the TextComponent class provides a flexible way to render text with color and border options. It can handle color tags within the text and apply visual effects such as borders during rendering.

TextComponent Java Class Code

package net.runelite.client.plugins.pvptools;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Shape;
import java.awt.font.GlyphVector;
import java.util.regex.Pattern;
import lombok.Setter;
import net.runelite.client.ui.overlay.RenderableEntity;

@Setter
public class TextComponent implements RenderableEntity
{
	private static final String COL_TAG_REGEX = "(<col=([0-9a-fA-F]){2,6}>)";
	private static final Pattern COL_TAG_PATTERN_W_LOOKAHEAD = Pattern.compile("(?=" + COL_TAG_REGEX + ")");
	private static final Pattern COL_TAG_PATTERN = Pattern.compile(COL_TAG_REGEX);

	private String text;
	private Point position = new Point();
	private Color color = Color.WHITE;
	private Color borderColor = Color.BLACK;

	public static String textWithoutColTags(String text)
	{
		return COL_TAG_PATTERN.matcher(text).replaceAll("");
	}

	@Override
	public Dimension render(Graphics2D graphics)
	{
		final FontMetrics fontMetrics = graphics.getFontMetrics();

		if (COL_TAG_PATTERN.matcher(text).find())
		{
			final String[] parts = COL_TAG_PATTERN_W_LOOKAHEAD.split(text);
			int x = position.x;

			for (String textSplitOnCol : parts)
			{
				final String textWithoutCol = textWithoutColTags(textSplitOnCol);
				final String colColor = textSplitOnCol.substring(textSplitOnCol.indexOf('=') + 1, textSplitOnCol.indexOf('>'));

				renderText(graphics, x, position.y, textWithoutCol, Color.decode("#" + colColor), borderColor);

				x += fontMetrics.stringWidth(textWithoutCol);
			}
		}
		else
		{
			renderText(graphics, position.x, position.y, text, color, borderColor);
		}
		return new Dimension(fontMetrics.stringWidth(text), fontMetrics.getHeight());
	}

	private void renderText(Graphics2D graphics, int x, int y, String text, Color color, Color border)
	{
		// remember previous composite
		Composite originalComposite = graphics.getComposite();

		// create a vector of the text
		GlyphVector vector = graphics.getFont().createGlyphVector(graphics.getFontRenderContext(), text);

		// compute the text shape
		Shape stroke = vector.getOutline(x + 1, y + 1);
		Shape shape = vector.getOutline(x, y);

		// draw text border
		graphics.setColor(border);
		graphics.fill(stroke);

		// replace the pixels instead of overlaying
		graphics.setComposite(AlphaComposite.Src);

		// draw actual text
		graphics.setColor(color);
		graphics.fill(shape);

		// reset composite to original
		graphics.setComposite(originalComposite);
	}

}

Table Element

This code defines a Java class named TableElement using Lombok annotations (@Data and @Builder). The purpose of this class is to represent an element within a table, such as a cell, with various properties.

Let’s break down the key components of the code:

  1. Class Structure:
    • TableElement is a class representing an element within a table.
  2. Fields:
    • alignment: Represents the alignment of the table element. It is of type TableAlignment, which is an enum with possible values (LEFT, CENTER, RIGHT).
    • color: Represents the color of the table element. It is of type Color from the java.awt package.
    • content: Represents the content or text of the table element.
  3. Lombok Annotations:
    • @Data: Generates boilerplate code for getter and setter methods, toString, hashCode, and equals.
    • @Builder: Generates a builder pattern for creating instances of the class. It simplifies the process of constructing objects with many optional parameters.
  4. Builder Pattern:
    • The @Builder annotation allows for easy and readable instantiation of TableElement objects using a builder pattern. This pattern enables the creation of instances with optional parameters in a fluent and expressive way.
  5. Default Values:
    • The generated builder includes default values for each field, allowing the creation of instances without specifying every parameter.

In summary, the TableElement class is a simple data class with fields for alignment, color, and content. The use of Lombok annotations simplifies the creation of instances and reduces the amount of boilerplate code needed for such a class. Instances of this class would typically be used as elements within a larger table structure, such as the rows and columns of a table.

TableElement Java Class Code

package net.runelite.client.plugins.pvptools;

import java.awt.Color;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class TableElement
{
	TableAlignment alignment;
	Color color;
	String content;
}

Table Component

This code defines a TableComponent class in Java, which is used for rendering tables with various configurations. The class implements the LayoutableRenderableEntity interface, suggesting that it can be rendered within a graphical user interface. Let’s break down the key components:

  1. Fields:
    • columns: A list of TableElement representing the columns of the table.
    • rows: A list of TableRow representing the rows of the table.
    • bounds: A Rectangle representing the bounds (position and size) of the table.
    • Various configuration fields such as defaultAlignment, defaultColor, gutter, preferredLocation, and preferredSize.
  2. Rendering:
    • The render method is responsible for rendering the table. It iterates through the columns and rows, rendering each cell based on the specified alignment and color.
    • The displayRow method is a helper method for rendering a single row.
    • The getColumnWidths method calculates the width that each column should take up based on the content.
  3. Text Wrapping:
    • The lineBreakText method handles line breaking for text within a cell, considering the width of the column.
  4. Column Width Calculation:
    • The getColumnWidths method calculates the optimal width for each column, considering the content and flexible/non-flexible column behavior.
    • It uses a weighted approach, allowing for flexible columns to adjust their width based on content.
  5. Alignment and Color Handling:
    • The getCellAlignment and getCellColor methods determine the alignment and color for a specific cell, considering cell, row, column, and default values.
  6. Adding Rows and Columns:
    • Various methods (addRow, addRows, addColumn, addColumns, etc.) are provided for adding rows and columns to the table.
  7. Utility Methods:
    • Utility methods such as firstNonNull, getTextWidth, getAlignedPosition, and ensureColumnSize are used to perform various tasks, including handling null values, calculating text width, aligning text, and ensuring the correct size of columns.
  8. Lombok Annotations:
    • Lombok annotations such as @Setter are used to automatically generate setter methods for fields, reducing boilerplate code.

Overall, this class is designed to represent and render tables with configurable alignments, colors, and other properties. It provides methods for adding and setting rows and columns, making it a versatile component for displaying tabular data in a graphical interface.

TableComponent Java Class Code

package net.runelite.client.plugins.pvptools;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import net.runelite.client.ui.overlay.components.ComponentConstants;
import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity;

@Setter
public class TableComponent implements LayoutableRenderableEntity
{
	private static final TableElement EMPTY_ELEMENT = TableElement.builder().build();

	@Getter
	private final List<TableElement> columns = new ArrayList<>();
	@Getter
	private final List<TableRow> rows = new ArrayList<>();

	@Getter
	private final Rectangle bounds = new Rectangle();

	private TableAlignment defaultAlignment = TableAlignment.LEFT;
	private Color defaultColor = Color.WHITE;
	private Dimension gutter = new Dimension(3, 0);
	private Point preferredLocation = new Point();
	private Dimension preferredSize = new Dimension(ComponentConstants.STANDARD_WIDTH, 0);

	@Override
	public Dimension render(final Graphics2D graphics)
	{
		final FontMetrics metrics = graphics.getFontMetrics();
		final TableRow colRow = TableRow.builder().elements(this.columns).build();
		final int[] columnWidths = getColumnWidths(metrics, colRow);

		graphics.translate(preferredLocation.x, preferredLocation.y);

		// Display the columns first
		int height = displayRow(graphics, colRow, 0, columnWidths, metrics);

		for (TableRow row : this.rows)
		{
			height = displayRow(graphics, row, height, columnWidths, metrics);
		}

		graphics.translate(-preferredLocation.x, -preferredLocation.y);

		final Dimension dimension = new Dimension(preferredSize.width, height);
		bounds.setLocation(preferredLocation);
		bounds.setSize(dimension);

		return dimension;
	}

	private int displayRow(Graphics2D graphics, TableRow row, int height, int[] columnWidths, FontMetrics metrics)
	{
		int x = 0;
		int startingRowHeight = height;

		final List<TableElement> elements = row.getElements();
		for (int i = 0; i < elements.size(); i++)
		{
			int y = startingRowHeight;
			final TableElement cell = elements.get(i);

			final String content = cell.getContent();
			if (content == null)
			{
				continue;
			}

			final String[] lines = lineBreakText(content, columnWidths[i], metrics);
			final TableAlignment alignment = getCellAlignment(row, i);
			final Color color = getCellColor(row, i);

			for (String line : lines)
			{
				final int alignmentOffset = getAlignedPosition(line, alignment, columnWidths[i], metrics);
				final TextComponent leftLineComponent = new TextComponent();
				y += metrics.getHeight();

				leftLineComponent.setPosition(new Point(x + alignmentOffset, y));
				leftLineComponent.setText(line);
				leftLineComponent.setColor(color);
				leftLineComponent.render(graphics);
			}
			height = Math.max(height, y);
			x += columnWidths[i] + gutter.width;
		}

		return height + gutter.height;
	}

	/**
	 * Returns the width that each column should take up
	 * Based on https://stackoverflow.com/questions/22206825/algorithm-for-calculating-variable-column-widths-for-set-table-width
	 *
	 * @param metrics
	 * @return int[] of column width
	 */
	private int[] getColumnWidths(final FontMetrics metrics, final TableRow columnRow)
	{
		int numCols = columns.size();
		for (final TableRow r : rows)
		{
			numCols = Math.max(r.getElements().size(), numCols);
		}

		int[] maxtextw = new int[numCols];      // max text width over all rows
		int[] maxwordw = new int[numCols];      // max width of longest word
		boolean[] flex = new boolean[numCols];  // is column flexible?
		boolean[] wrap = new boolean[numCols];  // can column be wrapped?
		int[] finalcolw = new int[numCols];     // final width of columns

		final List<TableRow> rows = new ArrayList<>(this.rows);
		rows.add(columnRow);

		for (final TableRow r : rows)
		{
			final List<TableElement> elements = r.getElements();
			for (int col = 0; col < elements.size(); col++)
			{
				final TableElement ele = elements.get(col);
				final String cell = ele.getContent();
				if (cell == null)
				{
					continue;
				}

				final int cellWidth = getTextWidth(metrics, cell);

				maxtextw[col] = Math.max(maxtextw[col], cellWidth);
				for (String word : cell.split(" "))
				{
					maxwordw[col] = Math.max(maxwordw[col], getTextWidth(metrics, word));
				}

				if (maxtextw[col] == cellWidth)
				{
					wrap[col] = cell.contains(" ");
				}
			}
		}

		int left = preferredSize.width - (numCols - 1) * gutter.width;
		final double avg = left / numCols;
		int nflex = 0;

		// Determine whether columns should be flexible and assign width of non-flexible cells
		for (int col = 0; col < numCols; col++)
		{
			// This limit can be adjusted as needed
			final double maxNonFlexLimit = 1.5 * avg;

			flex[col] = maxtextw[col] > maxNonFlexLimit;
			if (flex[col])
			{
				nflex++;
			}
			else
			{
				finalcolw[col] = maxtextw[col];
				left -= finalcolw[col];
			}
		}

		// If there is not enough space, make columns that could be word-wrapped flexible too
		if (left < nflex * avg)
		{
			for (int col = 0; col < numCols; col++)
			{
				if (!flex[col] && wrap[col])
				{
					left += finalcolw[col];
					finalcolw[col] = 0;
					flex[col] = true;
					nflex++;
				}
			}
		}

		// Calculate weights for flexible columns. The max width is capped at the table width to
		// treat columns that have to be wrapped more or less equal
		int tot = 0;
		for (int col = 0; col < numCols; col++)
		{
			if (flex[col])
			{
				maxtextw[col] = Math.min(maxtextw[col], preferredSize.width);
				tot += maxtextw[col];
			}
		}

		// Now assign the actual width for flexible columns. Make sure that it is at least as long
		// as the longest word length
		for (int col = 0; col < numCols; col++)
		{
			if (flex[col])
			{
				finalcolw[col] = left * maxtextw[col] / tot;
				finalcolw[col] = Math.max(finalcolw[col], maxwordw[col]);
				left -= finalcolw[col];
			}
		}

		// When the sum of column widths is less than the total space available, distribute the
		// extra space equally across all columns
		final int extraPerCol = left / numCols;
		for (int col = 0; col < numCols; col++)
		{
			finalcolw[col] += extraPerCol;
			left -= extraPerCol;
		}
		// Add any remainder to the right-most column
		finalcolw[finalcolw.length - 1] += left;

		return finalcolw;
	}
	private static int getTextWidth(final FontMetrics metrics, final String cell)
	{
		return metrics.stringWidth(TextComponent.textWithoutColTags(cell));
	}

	private static String[] lineBreakText(final String text, final int maxWidth, final FontMetrics metrics)
	{
		final String[] words = text.split(" ");

		if (words.length == 0)
		{
			return new String[0];
		}

		final StringBuilder wrapped = new StringBuilder(words[0]);
		int spaceLeft = maxWidth - getTextWidth(metrics, wrapped.toString());

		for (int i = 1; i < words.length; i++)
		{
			final String word = words[i];
			final int wordLen = getTextWidth(metrics, word);
			final int spaceWidth = metrics.stringWidth(" ");

			if (wordLen + spaceWidth > spaceLeft)
			{
				wrapped.append("\n").append(word);
				spaceLeft = maxWidth - wordLen;
			}
			else
			{
				wrapped.append(" ").append(word);
				spaceLeft -= spaceWidth + wordLen;
			}
		}

		return wrapped.toString().split("\n");
	}

	public boolean isEmpty()
	{
		return columns.size() == 0 || rows.size() == 0;
	}

	private void ensureColumnSize(final int size)
	{
		while (size > columns.size())
		{
			columns.add(TableElement.builder().build());
		}
	}

	private static int getAlignedPosition(final String str, final TableAlignment alignment, final int columnWidth, final FontMetrics metrics)
	{
		final int stringWidth = getTextWidth(metrics, str);
		int offset = 0;

		switch (alignment)
		{
			case LEFT:
				break;
			case CENTER:
				offset = (columnWidth / 2) - (stringWidth / 2);
				break;
			case RIGHT:
				offset = columnWidth - stringWidth;
				break;
		}
		return offset;
	}

	/**
	 * Returns the color for the specified table element.
	 * Priority order: cell->row->column->default
	 *
	 * @param row      TableRow element
	 * @param colIndex column index
	 */
	private Color getCellColor(final TableRow row, final int colIndex)
	{
		final List<TableElement> rowElements = row.getElements();
		final TableElement cell = colIndex < rowElements.size() ? rowElements.get(colIndex) : EMPTY_ELEMENT;
		final TableElement column = colIndex < columns.size() ? columns.get(colIndex) : EMPTY_ELEMENT;

		return firstNonNull(
				cell.getColor(),
				row.getRowColor(),
				column.getColor(),
				defaultColor);
	}

	private void setColumnAlignment(final int col, final TableAlignment alignment)
	{
		assert columns.size() > col;
		columns.get(col).setAlignment(alignment);
	}

	public void setColumnAlignments(@Nonnull final TableAlignment... alignments)
	{
		ensureColumnSize(alignments.length);
		for (int i = 0; i < alignments.length; i++)
		{
			setColumnAlignment(i, alignments[i]);
		}
	}

	/**
	 * Returns the alignment for the specified table element.
	 * Priority order: cell->row->column->default
	 *
	 * @param row      TableRow element
	 * @param colIndex column index
	 */
	private TableAlignment getCellAlignment(final TableRow row, final int colIndex)
	{
		final List<TableElement> rowElements = row.getElements();
		final TableElement cell = colIndex < rowElements.size() ? rowElements.get(colIndex) : EMPTY_ELEMENT;
		final TableElement column = colIndex < columns.size() ? columns.get(colIndex) : EMPTY_ELEMENT;

		return firstNonNull(
				cell.getAlignment(),
				row.getRowAlignment(),
				column.getAlignment(),
				defaultAlignment);
	}

	@SafeVarargs
	private static <T> T firstNonNull(@Nullable T... elements)
	{
		if (elements == null || elements.length == 0)
		{
			return null;
		}

		int i = 0;
		T cur = elements[0];
		while (cur == null && i < elements.length)
		{
			cur = elements[i];
			i++;
		}

		return cur;
	}

	// Helper functions for cleaner overlay code
	public void addRow(@Nonnull final String... cells)
	{
		final List<TableElement> elements = new ArrayList<>();
		for (final String cell : cells)
		{
			elements.add(TableElement.builder().content(cell).build());
		}

		final TableRow row = TableRow.builder().build();
		row.setElements(elements);

		this.rows.add(row);
	}

	private void addRows(@Nonnull final String[]... rows)
	{
		for (String[] row : rows)
		{
			addRow(row);
		}
	}

	public void addRows(@NonNull final TableRow... rows)
	{
		this.rows.addAll(Arrays.asList(rows));
	}

	public void setRows(@Nonnull final String[]... elements)
	{
		this.rows.clear();
		addRows(elements);
	}

	public void setRows(@Nonnull final TableRow... elements)
	{
		this.rows.clear();
		this.rows.addAll(Arrays.asList(elements));
	}

	private void addColumn(@Nonnull final String col)
	{
		this.columns.add(TableElement.builder().content(col).build());
	}

	public void addColumns(@NonNull final TableElement... columns)
	{
		this.columns.addAll(Arrays.asList(columns));
	}

	public void setColumns(@Nonnull final TableElement... elements)
	{
		this.columns.clear();
		this.columns.addAll(Arrays.asList(elements));
	}

	public void setColumns(@Nonnull final String... columns)
	{
		this.columns.clear();
		for (String col : columns)
		{
			addColumn(col);
		}
	}
}

Pvp Tools Panel

This Java code defines a Swing-based GUI panel (PvpToolsPanel) for a PvP Tools plugin in the RuneLite client. This panel is responsible for displaying various information related to player counts, risk calculations, and other game-related details.

Let’s break down the code:

  1. Import Statements:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import javax.inject.Singleton;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.plugins.info.JRichTextPane;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.PluginPanel;

Import statements for various Java and runelite plugins classes mostly used to format and add information into tabled sections.

  1. Annotations:
   @Slf4j
   @Singleton

The @Slf4j annotation generates a logger for the class, and @Singleton indicates that only one instance of this class should exist.

  1. Class Definition:
   class PvpToolsPanel extends PluginPanel

The class extends PluginPanel, which is runelite plugins class for creating plugin panels.

  1. Instance Variables:
   private final JLabel loggedLabel = new JLabel();
   private final JRichTextPane emailLabel = new JRichTextPane();
   final JLabel numCC = new JLabel();
	 final JLabel numOther = new JLabel();
	 final JLabel numMageJLabel = new JLabel(" ");
	 final JLabel numRangeJLabel = new JLabel(" ");
	 final JLabel numMeleeJLabel = new JLabel(" ");
	 final JLabel totalRiskLabel = new JLabel(" ");
	 final JLabel riskProtectingItem = new JLabel(" ");
	 final JLabel biggestItemLabel = new JLabel("Protected Item: ");
	 private final JLabel numBrews = new JLabel();

Instance variables representing various Swing components such as labels, buttons, and a RichTextPane.

  1. htmlLabel Method:
   public static String htmlLabel(String key, String value)
   	{
		return "<html><body style = 'color:#a5a5a5'>" + key + "<span style = 'color:white'>" + value + "</span></body></html>";
	}

A static method that formats HTML content for labels, providing a consistent styling for the text.

  1. init Method:
   void init()

This method initializes the panel by setting its layout, background color, border, and creating various Swing components. It configures the appearance of labels, buttons, and panels, adding them to the layout.

  1. disablePlayerCount, disablePrayerCount, disableRiskCalculator Methods:
	void disablePlayerCount()
	{
		this.numOther.setText("Disabled");
		this.numCC.setText("Disabled");
		this.numCC.repaint();
		this.numOther.repaint();
	}

	void disablePrayerCount()
	{
		this.numMageJLabel.setText("disabled");
		this.numRangeJLabel.setText("disabled");
		this.numMeleeJLabel.setText("disabled");
		this.numMageJLabel.repaint();
		this.numRangeJLabel.repaint();
		this.numMeleeJLabel.repaint();
	}

	void disableRiskCalculator()
	{
		this.totalRiskLabel.setText("disabled");
		this.riskProtectingItem.setText("disabled");
		this.biggestItemLabel.setText("disabled");
		this.totalRiskLabel.repaint();
		this.riskProtectingItem.repaint();
		this.biggestItemLabel.repaint();
	}

These methods are used to disable specific sections of the panel by updating the text and repainting the affected components.

  1. Panel Configuration:
   setLayout(new BorderLayout());
   setBackground(ColorScheme.DARK_GRAY_COLOR);
   setBorder(new EmptyBorder(10, 10, 10, 10));

The panel’s layout, background color, and border are configured.

  1. Label and Font Configuration:
		JPanel versionPanel = new JPanel();
		versionPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
		versionPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
		versionPanel.setLayout(new GridLayout(0, 1));

		JPanel riskPanel = new JPanel();
		riskPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
		riskPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
		riskPanel.setLayout(new GridLayout(0, 1));

		final Font smallFont = FontManager.getRunescapeSmallFont();
		
				JLabel revision = new JLabel();
		revision.setFont(smallFont);

		revision.setText("Oldschool revision: ");

		loggedLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
		loggedLabel.setFont(smallFont);

		emailLabel.setForeground(Color.WHITE);
		emailLabel.setFont(smallFont);

Font styles and colors are set and added using a grid snap layout.

  1. Adding Labels to Panels:
		numCC.setText(htmlLabel("Friendly Player Count: ", "0"));
		numOther.setText(htmlLabel("Other Player Count: ", "0"));
		numBrews.setText(htmlLabel("Player brew count: ", "0"));
		numMageJLabel.setText(htmlLabel("Enemies Praying Mage: ", "0"));
		numMageJLabel.setFont(FontManager.getRunescapeFont());
		numRangeJLabel.setText(htmlLabel("Enemies Praying Range: ", "0"));
		numRangeJLabel.setFont(FontManager.getRunescapeFont());
		numMeleeJLabel.setText(htmlLabel("Enemies Praying Melee: ", "0"));
		numMeleeJLabel.setFont(FontManager.getRunescapeFont());

		totalRiskLabel.setText(htmlLabel("Total risk: ", "0"));
		totalRiskLabel.setFont(FontManager.getRunescapeFont());
		riskProtectingItem.setText(htmlLabel("Risk Protecting Item: ", "0"));
		riskProtectingItem.setFont(FontManager.getRunescapeFont());
		biggestItemLabel.setText("Most Valuable Item: ");

Labels for displaying information related to player counts, risk calculations, and other game details are set.

  1. Adding Components to Panels:
   versionPanel.add(numCC);
   versionPanel.add(numOther);
   versionPanel.add(numBrews);
   versionPanel.add(numMageJLabel);
   versionPanel.add(numRangeJLabel);
   versionPanel.add(numMeleeJLabel);

Components are added to panels (versionPanel and riskPanel) using layouts.

In summary, the PvpToolsPanel class defines a graphical user interface panel for a PvP Tools plugin. It uses Swing components to display player counts, risk calculations, and other game-related details. The appearance of the panel is configured, and methods are provided to disable specific sections when needed.

PvP Tools

This Java code defines runelite plugins named “PvP Tools.” The plugin provides various tools and overlays related to player versus player (PvP) interactions in the Old School RuneScape game. Let’s break down the key components and functionalities:

  1. Plugin Annotation and Descriptor:
   @Extension
   @PluginDescriptor(
      name = "PvP Tools",
      enabledByDefault = false,
      description = "Enable the PvP Tools panel",
      tags = {"panel", "pvp", "pk", "pklite", "renderself"}
   )

The @Extension annotation marks this class as runelite plugins extension. The @PluginDescriptor annotation provides metadata about the plugin, including its name, default enabled state, description, and tags.

Dependency Injection and Field Initialization:

  1. Dependency Injection:
@Inject
private Hooks hooks;

@Inject
private OverlayManager overlayManager;

@Inject
private Client client;

@Inject
private ClientThread clientThread;

@Inject
private ItemManager itemManager;

@Inject
private ClientToolbar clientToolbar;

@Inject
private KeyManager keyManager;

@Inject
private PvpToolsConfig config;

@Inject
PlayerCountOverlay playerCountOverlay;

These variables include references to overlays, frames, buttons, and other necessary components for the plugin’s functionality.

  1. Instance Variables:
	public boolean hideNPCs2D;
	public boolean hideNPCs;
	public boolean hideOthers;
	public boolean hideOthers2D;
	public boolean hideFriends;
	public boolean hideFriendsChatMembers;
	public boolean hideClanMembers;
	public boolean hideIgnoredPlayers;
	public boolean hideLocalPlayer;
	public boolean hideLocalPlayer2D;
	public boolean hideAttackers;
	public boolean hideProjectiles;
	public boolean hideEnemy;
	private PvpToolsPanel panel;
	private NavigationButton navButton;
	@Getter(AccessLevel.PACKAGE)
	@Setter(AccessLevel.PACKAGE)
	public boolean hideAll;
	public boolean loaded;

  1. Event Listeners:
   @Subscribe
   private void onConfigChanged(ConfigChanged configChanged)

   @Subscribe
   private void onItemContainerChanged(ItemContainerChanged event)

   @Subscribe
   private void onGameStateChanged(GameStateChanged event)

   @Subscribe
   private void onPlayerSpawned(PlayerSpawned event)

   @Subscribe
   private void onPlayerDespawned(PlayerDespawned event)

These methods are annotated with @Subscribe to indicate that they subscribe to specific events, such as changes in configuration, item container updates, game state changes, player spawns, and player despawns.

  1. DrawListeners:
private final Hooks.RenderableDrawListener drawListener = this::shouldDraw;

These are DrawListener implementations that handle actions when objects are rendered into the game (npc, players, creatures etc).

  1. Configuration Methods:
   @Provides
   PvpToolsConfig config(ConfigManager configManager)

   @Override
   protected void startUp()

   @Override
   protected void shutDown()

   @Subscribe
   private void onConfigChanged(ConfigChanged configChanged)

These methods handle plugin startup, shutdown, and changes in configuration. They also use dependency injection to provide access to the plugin’s configuration.

  1. Player Count and Overhead Calculation:
   private int[] overheadCount = new int[]{0, 0, 0};

   @Getter
   private int enemyPlayerCount = 0;
   @Getter
   private int friendlyPlayerCount = 0;

   private void updatePrayerNumbers()

   private void updatePlayers()

   private void countOverHeads()

These methods calculate and update the player count, overhead prayers, and other related information.

  1. Risk Calculator:
   private void getCarriedWealth()

This method calculates the player’s risk based on the item price of items in their inventory and equipment.

  1. Initialization and GUI Components:
   @Override
   protected void startUp()

   private void init()

The startUp method initializes the plugin by adding overlays, registering key listeners, and creating the main GUI components. The init method configures the appearance and behavior of the GUI.

In summary, this runelite plugins, “PvP Tools,” offers various tools and overlays for players engaging in PvP activities in Old School RuneScape. It includes features like player counting and risk calculation. In part 3 we will add auto prayer and heal and gear swap.

One thought on “Runelite Plugins Development: PvP Helper – Part 2

Leave a Reply

Your email address will not be published. Required fields are marked *