Created
January 31, 2021 23:24
-
-
Save IntelOrca/5e39d683b038cdd1eb2c02a778205a0a to your computer and use it in GitHub Desktop.
OpenRCT2 plugin for network stats
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <reference path="C:\Users\Ted\Documents\GitHub\openrct2\distribution\openrct2.d.ts" /> | |
var NETWORK_STATS_WINDOW_CLASS = 'network-stats'; | |
var DEBUG = true; | |
var MOCK_STATS = DEBUG; | |
function openNetworkStats() { | |
var StatKind = { | |
receive: 0, | |
send: 1 | |
}; | |
var categoryGroups = [ | |
{ text: "Base protocol", paletteIndex: 102 }, | |
{ text: "Commands", paletteIndex: 138 }, | |
{ text: "Map", paletteIndex: 171 }, | |
]; | |
var historyReceived = []; | |
var historySent = []; | |
var totalSentBytes = 0; | |
var totalReceivedBytes = 0; | |
var accumulatedSentBytes = 0; | |
var accumulatedReceivedBytes = 0; | |
var sentBytesPerSecond = 0; | |
var receivedBytesPerSecond = 0; | |
var lastStatsUpdateTime = 0; | |
var receivedMax = 0; | |
var sentMax = 0; | |
function open() { | |
var width = 450; | |
var height = 210; | |
var padding = 5; | |
var heightTab = 43; | |
var textHeight = 12; | |
var totalHeight = height; | |
var totalHeightText = (textHeight + (padding * 2)) * 3; | |
var graphWidth = width - (padding * 2); | |
var graphHeight = (totalHeight - totalHeightText - heightTab) / 2; | |
graphHeight = ~~graphHeight; | |
var x = padding; | |
var y = heightTab + padding; | |
var widgets = []; | |
createGraphTextWidgets(widgets, x, y, StatKind.receive); | |
y += textHeight + padding; | |
createGraphWidget(widgets, x, y, graphWidth, graphHeight, StatKind.receive, 'graphReceived'); | |
y += graphHeight + padding; | |
createGraphTextWidgets(widgets, x, y, StatKind.send); | |
y += textHeight + padding; | |
createGraphWidget(widgets, x, y, graphWidth, graphHeight, StatKind.send, 'graphSent'); | |
y += graphHeight + padding; | |
createLegendWidgets(widgets, x, y); | |
var stats = getStats(); | |
var w = ui.openWindow({ | |
x: (ui.width - width) / 2, | |
y: (ui.height - height) / 2, | |
width: width, | |
height: height, | |
minWidth: width, | |
minHeight: height, | |
maxWidth: width * 4, | |
maxHeight: height * 4, | |
title: 'Network Information', | |
classification: NETWORK_STATS_WINDOW_CLASS, | |
colours: [0, 0], | |
tabs: [ | |
{ | |
image: { | |
frameBase: 5367, | |
frameCount: 8, | |
frameDuration: 4 | |
}, | |
widgets: widgets | |
} | |
], | |
onUpdate: function () { | |
var deltaStats = { | |
bytesReceived: [0, 0, 0], | |
bytesSent: [0, 0, 0] | |
}; | |
var receivedSum = 0; | |
var sentSum = 0; | |
var newStats = getStats(); | |
for (var i = 0; i < categoryGroups.length; i++) { | |
deltaStats.bytesReceived[i] = newStats.bytesReceived[i + 1] - stats.bytesReceived[i + 1]; | |
deltaStats.bytesSent[i] = newStats.bytesSent[i + 1] - stats.bytesSent[i + 1]; | |
accumulatedReceivedBytes += deltaStats.bytesReceived[i]; | |
accumulatedSentBytes += deltaStats.bytesSent[i] | |
receivedSum += deltaStats.bytesReceived[i]; | |
sentSum += deltaStats.bytesSent[i]; | |
} | |
stats = newStats; | |
totalReceivedBytes = stats.bytesReceived[0]; | |
totalSentBytes = stats.bytesSent[0]; | |
receivedMax = Math.max(receivedMax, receivedSum); | |
sentMax = Math.max(sentMax, sentSum); | |
while (historyReceived.length >= 256) { | |
historyReceived.shift(); | |
} | |
historyReceived.push(deltaStats.bytesReceived); | |
while (historySent.length >= 256) { | |
historySent.shift(); | |
} | |
historySent.push(deltaStats.bytesSent); | |
var currentTime = performance.now(); | |
if (currentTime > lastStatsUpdateTime + 1000) { | |
var elapsed = (currentTime - lastStatsUpdateTime) / 1000; | |
lastStatsUpdateTime = currentTime; | |
receivedBytesPerSecond = accumulatedReceivedBytes / elapsed; | |
sentBytesPerSecond = accumulatedSentBytes / elapsed; | |
accumulatedReceivedBytes = 0; | |
accumulatedSentBytes = 0; | |
} | |
var setWidgetText = function (name, text) { | |
var label = w.findWidget(name); | |
if (label) { | |
label.text = text; | |
} | |
}; | |
setWidgetText('lblReceivedBytes', formatReadableSpeed(receivedBytesPerSecond)); | |
setWidgetText('lblTotalReceivedBytes', formatReadableSize(totalReceivedBytes)); | |
setWidgetText('lblSentBytes', formatReadableSpeed(sentBytesPerSecond)); | |
setWidgetText('lblTotalSentBytes', formatReadableSize(totalSentBytes)); | |
performLayout(w); | |
} | |
}); | |
} | |
function performLayout(w) { | |
var width = w.width; | |
var height = w.height; | |
var padding = 5; | |
var heightTab = 43; | |
var textHeight = 12; | |
// var graphBarWidth = Math.min(1, width / width); | |
var graphBarWidth = 1; | |
var totalHeight = height; | |
var totalHeightText = (textHeight + (padding * 2)) * 3; | |
var graphWidth = width - (padding * 2); | |
var graphHeight = (totalHeight - totalHeightText - heightTab) / 2; | |
graphHeight = ~~graphHeight; | |
var x = padding; | |
var y = heightTab + padding; | |
var setWidgetY = function (names, y) { | |
for (var i = 0; i < names.length; i++) { | |
var widget = w.findWidget(names[i]); | |
if (widget) { | |
widget.y = y; | |
} | |
} | |
} | |
setWidgetY(['lblReceive', 'lblReceivedBytes', 'lblTotalReceived', 'lblTotalReceivedBytes'], y); | |
y += textHeight + padding; | |
var graph = w.findWidget('graphReceived'); | |
graph.y = y; | |
graph.width = graphWidth; | |
graph.height = graphHeight; | |
y += graphHeight + padding; | |
setWidgetY(['lblSend', 'lblSentBytes', 'lblTotalSent', 'lblTotalSentBytes'], y); | |
y += textHeight + padding; | |
var graph = w.findWidget('graphSent'); | |
graph.y = y; | |
graph.width = graphWidth; | |
graph.height = graphHeight; | |
y += graphHeight + padding; | |
for (var n = 0; n < categoryGroups.length; n++) { | |
setWidgetY(['legendColour' + n], y + 4); | |
setWidgetY(['legendLabel' + n], y); | |
} | |
} | |
function createLabel(name, x, y, text) { | |
return { | |
type: 'label', | |
name: name, | |
x: x, | |
y: y, | |
width: 100, | |
height: 16, | |
text: text | |
}; | |
} | |
function createLegendColourWidget(name, x, y, w, h, colour) { | |
return { | |
type: 'custom', | |
name: name, | |
x: x, | |
y: y, | |
width: w, | |
height: h, | |
onDraw: function (g) { | |
g.fill = colour; | |
g.clear(); | |
} | |
}; | |
} | |
function createGraphTextWidgets(widgets, x, y, kind) { | |
if (kind === StatKind.receive) { | |
widgets.push(createLabel('lblReceive', x, y, "Receive")); | |
widgets.push(createLabel('lblReceivedBytes', x + 70, y, "0.000 B/sec")); | |
widgets.push(createLabel('lblTotalReceived', x + 200, y, "Total received")); | |
widgets.push(createLabel('lblTotalReceivedBytes', x + 300, y, "0.000 B/sec")); | |
} else { | |
widgets.push(createLabel('lblSend', x, y, "Send")); | |
widgets.push(createLabel('lblSentBytes', x + 70, y, "0.000 B/sec")); | |
widgets.push(createLabel('lblTotalSent', x + 200, y, "Total sent")); | |
widgets.push(createLabel('lblTotalSentBytes', x + 300, y, "0.000 B/sec")); | |
} | |
} | |
function createGraphWidget(widgets, x, y, w, h, kind, name) { | |
widgets.push({ | |
type: 'custom', | |
name: name, | |
x: x, | |
y: y, | |
width: w, | |
height: h, | |
onDraw: function (g) { | |
g.stroke = 1; | |
g.line(0, 0, this.width - 1, 0); | |
g.line(this.width - 1, 0, this.width - 1, this.height); | |
g.line(0, this.height - 1, this.width - 1, this.height - 1); | |
g.line(0, 0, 0, this.height); | |
g.clip(1, 1, this.width - 2, this.height - 2); | |
drawGraph(g, this.width - 2, this.height - 2, kind); | |
} | |
}); | |
} | |
function createLegendWidgets(widgets, x, y) { | |
for (var n = 0; n < categoryGroups.length; n++) { | |
var cg = categoryGroups[n]; | |
widgets.push(createLegendColourWidget('legendColour' + n, x, y + 4, 6, 4, cg.paletteIndex)); | |
widgets.push(createLabel('legendLabel' + n, x + 10, y, cg.text)); | |
x += cg.text.length * 10; | |
} | |
} | |
function drawGraph(g, width, height, kind) { | |
var barWidth = 1; | |
var history = kind == StatKind.receive ? historyReceived : historySent; | |
var dataMax = kind == StatKind.receive ? receivedMax : sentMax; | |
var numBars = Math.min(history.length, Math.floor(width / barWidth)); | |
var gap = (width - (numBars * barWidth)) / numBars; | |
var x = 0; | |
for (var i = 0; i < numBars; i++) { | |
var historyItem = history[i]; | |
var totalSum = 0; | |
for (var n = 0; n < categoryGroups.length; n++) { | |
totalSum += historyItem[n]; | |
} | |
var totalHeight = (totalSum / dataMax) * height; | |
var yOffset = height; | |
for (var n = 0; n < categoryGroups.length; n++) { | |
var amount = historyItem[n]; | |
var singleHeight = (amount / totalSum) * totalHeight; | |
var lineHeight = Math.ceil(singleHeight); | |
lineHeight = Math.min(lineHeight, height); | |
yOffset -= lineHeight; | |
if (lineHeight > 0) { | |
g.fill = categoryGroups[n].paletteIndex; | |
g.fillRect(x, yOffset, barWidth, lineHeight); | |
} | |
} | |
x += barWidth + gap; | |
} | |
} | |
var getStats; | |
if (MOCK_STATS) { | |
var mockStats = { | |
bytesReceived: [0, 0, 0, 0], | |
bytesSent: [0, 0, 0, 0] | |
}; | |
var mockSizeInc = 4; | |
getStats = function () { | |
for (var i = 1; i < 4; i++) { | |
mockStats.bytesReceived[i] += ~~(Math.random() * mockSizeInc); | |
mockStats.bytesSent[i] += ~~(Math.random() * mockSizeInc); | |
mockStats.bytesReceived[0] += mockStats.bytesReceived[i]; | |
mockStats.bytesSent[0] += mockStats.bytesSent[i]; | |
} | |
return JSON.parse(JSON.stringify(mockStats)); | |
}; | |
} else { | |
getStats = function () { | |
return network.stats; | |
}; | |
} | |
function formatReadableSpeed(speed) { | |
return formatReadableSize(speed) + "/sec"; | |
} | |
function formatReadableSize(size) { | |
var sizeTable = ['B', 'KiB', 'MiB', 'GiB']; | |
var idx = 0; | |
while (size >= 1024 && idx < sizeTable.length - 1) { | |
size /= 1024; | |
idx++; | |
} | |
return context.formatString('{COMMA1DP16} {STRING}', size * 10, sizeTable[idx]); | |
} | |
return open(); | |
} | |
var main = function () { | |
ui.registerMenuItem('Network Information', function () { | |
var w = ui.getWindow(NETWORK_STATS_WINDOW_CLASS); | |
if (w) { | |
w.bringToFront(); | |
} else { | |
openNetworkStats(); | |
} | |
}); | |
if (DEBUG) { | |
ui.closeAllWindows(); | |
openNetworkStats(); | |
} | |
}; | |
registerPlugin({ | |
name: 'Test', | |
version: '1.0', | |
authors: ['Ted'], | |
type: 'local', | |
licence: 'MIT', | |
main: main | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment