Skip to content

Commit

Permalink
feat: add memory graph
Browse files Browse the repository at this point in the history
  • Loading branch information
smartcmd committed May 24, 2024
1 parent 9f258b5 commit c4b2a19
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 4 deletions.
34 changes: 33 additions & 1 deletion Allay-Server/src/main/java/org/allaymc/server/gui/Dashboard.form
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,44 @@
<border type="none"/>
<children>
<grid id="a3704" binding="perfTab" layout-manager="FormLayout">
<rowspec value="center:d:grow"/>
<colspec value="fill:d:grow"/>
<constraints>
<tabbedpane title="Performance"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
<children>
<tabbedpane id="6a40b" binding="tabbedPane1" default-binding="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="200" height="200"/>
</grid>
<forms defaultalign-vert="false"/>
</constraints>
<properties>
<alignmentY value="0.5"/>
</properties>
<border type="none"/>
<children>
<grid id="c265f" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<tabbedpane title="Memory"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="409fa" class="org.allaymc.server.gui.GraphPanel" binding="ramGraph" custom-create="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
</component>
</children>
</grid>
</children>
</tabbedpane>
</children>
</grid>
<grid id="64ec5" binding="playerTab" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
Expand Down
53 changes: 50 additions & 3 deletions Allay-Server/src/main/java/org/allaymc/server/gui/Dashboard.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.net.URL;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* java-swing-playground Project 2024/5/19
* Allay Project 2024/5/19
*
* @author daoge_cmd
*/
Expand All @@ -31,6 +36,9 @@ public class Dashboard {
private JPanel pluginTab;
private JTable pluginTable;
private JLabel onlinePlayerCount;
private JTabbedPane tabbedPane1;
private GraphPanel ramGraph;
private List<Integer> ramValues;

public static Dashboard getInstance() {
if (INSTANCE != null) {
Expand All @@ -43,7 +51,7 @@ public static Dashboard getInstance() {
JFrame frame = new JFrame("Dashboard");
frame.setContentPane(INSTANCE.rootPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setSize(700, 700);
frame.setLocationRelativeTo(null);
// Set icon
URL image = Dashboard.class.getClassLoader().getResource("icon.png");
Expand Down Expand Up @@ -158,6 +166,45 @@ protected void updatePluginTable() {
return rootPane;
}

private static final long MEGABYTE = 1024L * 1024L;

private void createUIComponents() {
ramGraph = new GraphPanel();
ramValues = new ArrayList<>();
// Set the ram graph to 0
for (int i = 0; i < 50; i++) {
ramValues.add(0);
}
ramGraph.setValues(ramValues);
ramGraph.setXLabel("Memory Usage");

Runnable periodicTask = () -> {
// Update ram graph
final long freeMemory = Runtime.getRuntime().freeMemory();
final long totalMemory = Runtime.getRuntime().totalMemory();
final int freePercent = (int) (freeMemory * 100.0 / totalMemory + 0.5);
ramValues.add(100 - freePercent);

ramGraph.setXLabel("Usage: " + String.format("%,d", (totalMemory - freeMemory) / MEGABYTE) + "mb (" + freePercent + "% free)");

// Trim the list
int k = ramValues.size();
if (k > 50)
ramValues.subList(0, k - 50).clear();

// Update the graph
ramGraph.setValues(ramValues);
};

// SwingUtilities.invokeLater is called so that we don't run into threading issues with the GUI
Server.getInstance().getScheduler().scheduleRepeating(
Server.getInstance(),
() -> {
SwingUtilities.invokeLater(periodicTask);
return true;},
20);
}

private static class UneditableDefaultTableModel extends DefaultTableModel {
public UneditableDefaultTableModel(String[][] data, String[] title) {super(data, title);}

Expand Down
190 changes: 190 additions & 0 deletions Allay-Server/src/main/java/org/allaymc/server/gui/GraphPanel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/

package org.allaymc.server.gui;

import lombok.Setter;

import javax.swing.*;
import java.awt.*;
import java.io.Serial;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* Allay Project 2024/5/24
*
* @author daoge_cmd
*/
public final class GraphPanel extends JPanel {

@Serial
private static final long serialVersionUID = 1L;

private final static int padding = 10;
private final static int labelPadding = 25;
private final static int pointWidth = 4;
private final static int numberYDivisions = 20;
private final static Color textColor = Color.WHITE;
private final static Color backgroundColor = Color.DARK_GRAY;
private final static Color lineColor = new Color(44, 102, 230, 255);
private final static Color pointColor = new Color(100, 100, 100, 255);
private final static Color gridColor = Color.GRAY;
private static final Stroke graphStroke = new BasicStroke(2f);
private final List<Integer> values = new ArrayList<>(50);

@Setter
private String xLabel = "";

public GraphPanel() {
setPreferredSize(new Dimension(700 - (padding * 2), 700 - (padding * 2)));
}

public void setValues(Collection<Integer> newValues) {
values.clear();
addValues(newValues);
}

public void addValues(Collection<Integer> newValues) {
values.addAll(newValues);
updateUI();
}

@Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
if (!(graphics instanceof final Graphics2D g)) {
graphics.drawString("Graphics is not Graphics2D, unable to render", 0, 0);
return;
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

final int length = values.size();
final int width = getWidth();
final int height = getHeight();
final int maxScore = getMaxScore();
final int minScore = getMinScore();
final int scoreRange = maxScore - minScore;

// draw background
g.setColor(backgroundColor);
g.fillRect(
padding + labelPadding,
padding,
width - (2 * padding) - labelPadding,
height - 2 * padding - labelPadding);
g.setColor(Color.BLACK);

final FontMetrics fontMetrics = g.getFontMetrics();
final int fontHeight = fontMetrics.getHeight();

// create hatch marks and grid lines for y axis.
for (int i = 0; i < numberYDivisions + 1; i++) {
final int x1 = padding + labelPadding;
final int x2 = pointWidth + padding + labelPadding;
final int y = height - ((i * (height - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding);
if (length > 0) {
g.setColor(gridColor);
g.drawLine(padding + labelPadding + 1 + pointWidth, y, width - padding, y);

g.setColor(textColor);
final int tickValue = minScore + ((scoreRange * i) / numberYDivisions);
final String yLabel = tickValue + "";
final int labelWidth = fontMetrics.stringWidth(yLabel);
g.drawString(yLabel, x1 - labelWidth - 5, y + (fontHeight / 2) - 3);
}
g.drawLine(x1, y, x2, y);
}

// and for x axis
if (length > 1) {
for (int i = 0; i < length; i++) {
final int x = i * (width - padding * 2 - labelPadding) / (length - 1) + padding + labelPadding;
final int y1 = height - padding - labelPadding;
final int y2 = y1 - pointWidth;
if ((i % ((int) ((length / 20.0)) + 1)) == 0) {
g.setColor(gridColor);
g.drawLine(x, height - padding - labelPadding - 1 - pointWidth, x, padding);

g.setColor(Color.BLACK);
}
g.drawLine(x, y1, x, y2);
}
}

// create x and y axes
g.drawLine(padding + labelPadding, height - padding - labelPadding, padding + labelPadding, padding);
g.drawLine(padding + labelPadding, height - padding - labelPadding, width - padding, height - padding - labelPadding);

g.setColor(textColor);
final int labelWidth = fontMetrics.stringWidth(xLabel);
final int labelX = ((padding + labelPadding) + (width - padding)) / 2;
final int labelY = height - padding - labelPadding;
g.drawString(xLabel, labelX - labelWidth / 2, labelY + fontHeight + 3);

final Stroke oldStroke = g.getStroke();
g.setColor(lineColor);
g.setStroke(graphStroke);

final double xScale = ((double) width - (2 * padding) - labelPadding) / (length - 1);
final double yScale = ((double) height - 2 * padding - labelPadding) / scoreRange;

final List<Point> graphPoints = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
final int x1 = (int) (i * xScale + padding + labelPadding);
final int y1 = (int) ((maxScore - values.get(i)) * yScale + padding);
graphPoints.add(new Point(x1, y1));
}

for (int i = 0; i < graphPoints.size() - 1; i++) {
final int x1 = graphPoints.get(i).x;
final int y1 = graphPoints.get(i).y;
final int x2 = graphPoints.get(i + 1).x;
final int y2 = graphPoints.get(i + 1).y;
g.drawLine(x1, y1, x2, y2);
}

boolean drawDots = width > (length * pointWidth);
if (drawDots) {
g.setStroke(oldStroke);
g.setColor(pointColor);
for (Point graphPoint : graphPoints) {
final int x = graphPoint.x - pointWidth / 2;
final int y = graphPoint.y - pointWidth / 2;
//noinspection SuspiciousNameCombination
g.fillOval(x, y, pointWidth, pointWidth);
}
}
}

private int getMinScore() {
return 0;
}

private int getMaxScore() {
return 100;
}
}

0 comments on commit c4b2a19

Please sign in to comment.