mirror of https://github.com/OpenRCT2/OpenRCT2.git
commit
f5e24bd973
|
@ -24,6 +24,7 @@
|
|||
2AA050322209A8E300D3A922 /* StaffSetCostumeAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2AA050302209A8E300D3A922 /* StaffSetCostumeAction.hpp */; };
|
||||
2AA050332209A8E300D3A922 /* StaffSetOrdersAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2AA050312209A8E300D3A922 /* StaffSetOrdersAction.hpp */; };
|
||||
2AF7893D220B253E0072754A /* RideSetAppearanceAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2AF7893C220B253E0072754A /* RideSetAppearanceAction.hpp */; };
|
||||
2A5354E922099C4F00A5440F /* Network.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A5354E822099C4F00A5440F /* Network.cpp */; };
|
||||
4C29DEB3218C6AE500E8707F /* RCT12.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C29DEB2218C6AE500E8707F /* RCT12.cpp */; };
|
||||
4C358E5221C445F700ADE6BC /* ReplayManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C358E5021C445F700ADE6BC /* ReplayManager.cpp */; };
|
||||
4C3B4236205914F7000C5BB7 /* InGameConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C3B4234205914F7000C5BB7 /* InGameConsole.cpp */; };
|
||||
|
@ -619,6 +620,8 @@
|
|||
2AA050302209A8E300D3A922 /* StaffSetCostumeAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetCostumeAction.hpp; sourceTree = "<group>"; };
|
||||
2AA050312209A8E300D3A922 /* StaffSetOrdersAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaffSetOrdersAction.hpp; sourceTree = "<group>"; };
|
||||
2AF7893C220B253E0072754A /* RideSetAppearanceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetAppearanceAction.hpp; sourceTree = "<group>"; };
|
||||
2A5354E822099C4F00A5440F /* Network.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Network.cpp; sourceTree = "<group>"; };
|
||||
2A5354EA22099C7200A5440F /* CircularBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircularBuffer.h; sourceTree = "<group>"; };
|
||||
4C04D69F2056AA9600F82EBA /* linenoise.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = linenoise.hpp; sourceTree = "<group>"; };
|
||||
4C1A53EC205FD19F000F8EF5 /* SceneryObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneryObject.cpp; sourceTree = "<group>"; };
|
||||
4C29DEB2218C6AE500E8707F /* RCT12.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RCT12.cpp; sourceTree = "<group>"; };
|
||||
|
@ -2454,6 +2457,7 @@
|
|||
F76C83781EC4E7CC00FA49E2 /* core */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A5354EA22099C7200A5440F /* CircularBuffer.h */,
|
||||
F76C83791EC4E7CC00FA49E2 /* Collections.hpp */,
|
||||
F76C837A1EC4E7CC00FA49E2 /* Console.cpp */,
|
||||
9344BEF720C1E6180047D165 /* Crypt.h */,
|
||||
|
@ -3193,6 +3197,7 @@
|
|||
F7CB86401EEDA0E20030C877 /* windows */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A5354E822099C4F00A5440F /* Network.cpp */,
|
||||
C666EE551F37ACB10061AA04 /* About.cpp */,
|
||||
C654DF1C1F69C0430040F43D /* Banner.cpp */,
|
||||
C666EE561F37ACB10061AA04 /* Changelog.cpp */,
|
||||
|
@ -3709,6 +3714,7 @@
|
|||
C654DF311F69C0430040F43D /* GuestList.cpp in Sources */,
|
||||
4C93F1AD1F8CD9F000A9330D /* Input.cpp in Sources */,
|
||||
C666EE761F37ACB10061AA04 /* Options.cpp in Sources */,
|
||||
2A5354E922099C4F00A5440F /* Network.cpp in Sources */,
|
||||
C666EE6E1F37ACB10061AA04 /* CustomCurrency.cpp in Sources */,
|
||||
C654DF2D1F69C0430040F43D /* Banner.cpp in Sources */,
|
||||
C666EE711F37ACB10061AA04 /* MapGen.cpp in Sources */,
|
||||
|
|
|
@ -3731,6 +3731,21 @@ STR_6280 :{SMALLFONT}{BLACK}Chat
|
|||
STR_6281 :{SMALLFONT}{BLACK}Show a separate button for the Chat window in the toolbar
|
||||
STR_6282 :Chat
|
||||
STR_6283 :Chat not available at this time. Are you connected to a server?
|
||||
STR_6284 :Network
|
||||
STR_6285 :Network Information
|
||||
STR_6286 :Receive
|
||||
STR_6287 :Send
|
||||
STR_6288 :Total received
|
||||
STR_6289 :Total sent
|
||||
STR_6290 :Base protocol
|
||||
STR_6291 :Commands
|
||||
STR_6292 :Map
|
||||
STR_6293 :B
|
||||
STR_6294 :KiB
|
||||
STR_6295 :MiB
|
||||
STR_6296 :GiB
|
||||
STR_6297 :TiB
|
||||
STR_6298 :{STRING}/sec
|
||||
|
||||
#############
|
||||
# Scenarios #
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
- Feature: [#8458] Add sprite sorting benchmark.
|
||||
- Feature: [#8583] Add boosters to water coaster.
|
||||
- Feature: [#8648] Add optional chat button to top toolbar in multiplayer games.
|
||||
- Feature: [#8652] Add network window including a graph for data usage visualisation.
|
||||
- Change: [#7961] Add new object types: station, terrain surface, and terrain edge.
|
||||
- Change: [#8222] The climate setting has been moved from objective options to scenario options.
|
||||
- Fix: [#3832] Changing the colour scheme of track pieces does not work in multiplayer.
|
||||
|
|
|
@ -128,6 +128,8 @@ public:
|
|||
return window_viewport_open();
|
||||
case WC_WATER:
|
||||
return window_water_open();
|
||||
case WC_NETWORK:
|
||||
return window_network_open();
|
||||
default:
|
||||
Console::Error::WriteLine("Unhandled window class (%d)", wc);
|
||||
return nullptr;
|
||||
|
|
|
@ -0,0 +1,480 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2019 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <cmath>
|
||||
#include <openrct2-ui/interface/Dropdown.h>
|
||||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/core/CircularBuffer.h>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/network/network.h>
|
||||
#include <openrct2/platform/platform.h>
|
||||
#include <openrct2/sprites.h>
|
||||
#include <openrct2/util/Util.h>
|
||||
|
||||
// clang-format off
|
||||
enum {
|
||||
WINDOW_NETWORK_PAGE_INFORMATION,
|
||||
};
|
||||
|
||||
#define WW 450
|
||||
#define WH 210
|
||||
|
||||
enum WINDOW_NETWORK_WIDGET_IDX {
|
||||
WIDX_BACKGROUND,
|
||||
WIDX_TITLE,
|
||||
WIDX_CLOSE,
|
||||
WIDX_RESIZE,
|
||||
WIDX_TAB1,
|
||||
};
|
||||
|
||||
#define MAIN_NETWORK_WIDGETS \
|
||||
{ WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE }, /* panel / background */ \
|
||||
{ WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_NONE, STR_WINDOW_TITLE_TIP }, /* title bar */ \
|
||||
{ WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, /* close x button */ \
|
||||
{ WWT_RESIZE, 1, 0, WW - 1, 43, WH - 1, 0xFFFFFFFF, STR_NONE }, /* content panel */ \
|
||||
{ WWT_TAB, 1, 3, 33, 17, 43, IMAGE_TYPE_REMAP | SPR_TAB, STR_SHOW_SERVER_INFO_TIP }, /* tab */ \
|
||||
|
||||
static rct_widget window_network_information_widgets[] = {
|
||||
MAIN_NETWORK_WIDGETS
|
||||
{ WIDGETS_END }
|
||||
};
|
||||
|
||||
static rct_widget *window_network_page_widgets[] = {
|
||||
window_network_information_widgets,
|
||||
};
|
||||
|
||||
static constexpr const uint64_t window_network_page_enabled_widgets[] = {
|
||||
(1 << WIDX_CLOSE) | (1 << WIDX_TAB1),
|
||||
};
|
||||
|
||||
static constexpr rct_string_id WindowNetworkPageTitles[] = {
|
||||
STR_NETWORK_INFORMATION_TITLE,
|
||||
};
|
||||
|
||||
static void window_network_information_mouseup(rct_window *w, rct_widgetindex widgetIndex);
|
||||
static void window_network_information_resize(rct_window *w);
|
||||
static void window_network_information_update(rct_window *w);
|
||||
static void window_network_information_invalidate(rct_window *w);
|
||||
static void window_network_information_paint(rct_window *w, rct_drawpixelinfo *dpi);
|
||||
|
||||
struct NetworkHistory_t
|
||||
{
|
||||
std::array<uint16_t, NETWORK_STATISTICS_GROUP_MAX> deltaBytesReceived;
|
||||
std::array<uint16_t, NETWORK_STATISTICS_GROUP_MAX> deltaBytesSent;
|
||||
};
|
||||
|
||||
static NetworkStats_t _networkStats;
|
||||
static NetworkHistory_t _networkLastDeltaStats;
|
||||
static NetworkHistory_t _networkAccumulatedStats;
|
||||
|
||||
static float _graphMaxIn;
|
||||
static float _graphMaxOut;
|
||||
|
||||
static float _bytesInSec;
|
||||
static float _bytesOutSec;
|
||||
static uint32_t _bytesIn;
|
||||
static uint32_t _bytesOut;
|
||||
|
||||
static uint32_t _lastGraphUpdateTime;
|
||||
static uint32_t _lastStatsUpdateTime;
|
||||
|
||||
static CircularBuffer<NetworkHistory_t, 128> _networkHistory;
|
||||
|
||||
static constexpr int32_t NetworkTrafficGroupColors[NETWORK_STATISTICS_GROUP_MAX] = {
|
||||
PALETTE_INDEX_21,
|
||||
PALETTE_INDEX_102,
|
||||
PALETTE_INDEX_138,
|
||||
PALETTE_INDEX_171,
|
||||
};
|
||||
|
||||
static constexpr int32_t NetworkTrafficGroupNames[NETWORK_STATISTICS_GROUP_MAX] = {
|
||||
STR_NETWORK,
|
||||
STR_NETWORK_LEGEND_BASE,
|
||||
STR_NETWORK_LEGEND_COMMANDS,
|
||||
STR_NETWORK_LEGEND_MAPDATA,
|
||||
};
|
||||
|
||||
static rct_window_event_list window_network_information_events = {
|
||||
nullptr,
|
||||
window_network_information_mouseup,
|
||||
window_network_information_resize,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
window_network_information_update,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
window_network_information_invalidate,
|
||||
window_network_information_paint,
|
||||
nullptr
|
||||
};
|
||||
|
||||
static rct_window_event_list *window_network_page_events[] = {
|
||||
&window_network_information_events,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static constexpr const int32_t window_network_animation_divisor[] = { 4, 4, 2, 2 };
|
||||
static constexpr const int32_t window_network_animation_frames[] = { 8, 8, 7, 4 };
|
||||
|
||||
static void window_network_draw_tab_images(rct_window* w, rct_drawpixelinfo* dpi);
|
||||
static void window_network_set_page(rct_window* w, int32_t page);
|
||||
|
||||
rct_window* window_network_open()
|
||||
{
|
||||
// Check if window is already open
|
||||
rct_window* window = window_bring_to_front_by_class(WC_NETWORK);
|
||||
if (window == nullptr)
|
||||
{
|
||||
window = window_create_auto_pos(320, 144, &window_network_information_events, WC_NETWORK, WF_10 | WF_RESIZABLE);
|
||||
window_network_set_page(window, WINDOW_NETWORK_PAGE_INFORMATION);
|
||||
|
||||
// Fill the buffer so it will start scrolling in.
|
||||
_networkHistory.clear();
|
||||
for (size_t i = 0; i < _networkHistory.capacity(); i++)
|
||||
{
|
||||
_networkHistory.push_back(NetworkHistory_t{});
|
||||
}
|
||||
}
|
||||
|
||||
_networkStats = network_get_stats();
|
||||
_networkAccumulatedStats = {};
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
static void window_network_set_page(rct_window* w, int32_t page)
|
||||
{
|
||||
w->page = page;
|
||||
w->frame_no = 0;
|
||||
w->no_list_items = 0;
|
||||
w->selected_list_item = -1;
|
||||
|
||||
w->enabled_widgets = window_network_page_enabled_widgets[page];
|
||||
w->hold_down_widgets = 0;
|
||||
w->event_handlers = window_network_page_events[page];
|
||||
w->pressed_widgets = 0;
|
||||
w->widgets = window_network_page_widgets[page];
|
||||
w->widgets[WIDX_TITLE].text = WindowNetworkPageTitles[page];
|
||||
|
||||
window_event_resize_call(w);
|
||||
window_event_invalidate_call(w);
|
||||
window_init_scroll_widgets(w);
|
||||
window_invalidate(w);
|
||||
}
|
||||
|
||||
static void window_network_anchor_border_widgets(rct_window* w)
|
||||
{
|
||||
w->widgets[WIDX_BACKGROUND].right = w->width - 1;
|
||||
w->widgets[WIDX_BACKGROUND].bottom = w->height - 1;
|
||||
w->widgets[WIDX_TITLE].right = w->width - 2;
|
||||
w->widgets[WIDX_RESIZE].right = w->width - 1;
|
||||
w->widgets[WIDX_RESIZE].bottom = w->height - 1;
|
||||
w->widgets[WIDX_CLOSE].left = w->width - 13;
|
||||
w->widgets[WIDX_CLOSE].right = w->width - 3;
|
||||
}
|
||||
|
||||
static void window_network_set_pressed_tab(rct_window* w)
|
||||
{
|
||||
for (int32_t i = 0; i < 2; i++)
|
||||
{
|
||||
w->pressed_widgets &= ~(1 << (WIDX_TAB1 + i));
|
||||
}
|
||||
w->pressed_widgets |= 1LL << (WIDX_TAB1 + w->page);
|
||||
}
|
||||
|
||||
#pragma region Information page
|
||||
|
||||
static void window_network_information_mouseup(rct_window* w, rct_widgetindex widgetIndex)
|
||||
{
|
||||
switch (widgetIndex)
|
||||
{
|
||||
case WIDX_CLOSE:
|
||||
window_close(w);
|
||||
break;
|
||||
case WIDX_TAB1:
|
||||
if (w->page != widgetIndex - WIDX_TAB1)
|
||||
{
|
||||
window_network_set_page(w, widgetIndex - WIDX_TAB1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void window_network_information_resize(rct_window* w)
|
||||
{
|
||||
window_set_resize(w, WW, WH, WW * 4, WH * 4);
|
||||
window_network_anchor_border_widgets(w);
|
||||
}
|
||||
|
||||
static void window_network_information_update(rct_window* w)
|
||||
{
|
||||
w->frame_no++;
|
||||
widget_invalidate(w, WIDX_TAB1 + w->page);
|
||||
window_invalidate(w);
|
||||
|
||||
NetworkStats_t curStats = network_get_stats();
|
||||
|
||||
uint32_t currentTicks = platform_get_ticks();
|
||||
|
||||
float graphTimeElapsed = (currentTicks - _lastGraphUpdateTime) / 1000.0f;
|
||||
_lastGraphUpdateTime = currentTicks;
|
||||
|
||||
for (int i = 0; i < NETWORK_STATISTICS_GROUP_MAX; i++)
|
||||
{
|
||||
uint32_t deltaBytesReceived = curStats.bytesReceived[i] - _networkStats.bytesReceived[i];
|
||||
uint32_t deltaBytesSent = curStats.bytesSent[i] - _networkStats.bytesSent[i];
|
||||
|
||||
_networkLastDeltaStats.deltaBytesReceived[i] = deltaBytesReceived;
|
||||
_networkLastDeltaStats.deltaBytesSent[i] = deltaBytesSent;
|
||||
|
||||
_networkAccumulatedStats.deltaBytesReceived[i] += deltaBytesReceived;
|
||||
_networkAccumulatedStats.deltaBytesSent[i] += deltaBytesSent;
|
||||
}
|
||||
|
||||
float graphMaxIn = 0.0f;
|
||||
float graphMaxOut = 0.0f;
|
||||
|
||||
for (size_t i = 0; i < _networkHistory.size(); i++)
|
||||
{
|
||||
const NetworkHistory_t& history = _networkHistory[i];
|
||||
for (int n = 1; n < NETWORK_STATISTICS_GROUP_MAX; n++)
|
||||
{
|
||||
graphMaxIn = (float)std::max<uint32_t>(history.deltaBytesReceived[n], graphMaxIn);
|
||||
graphMaxOut = (float)std::max<uint32_t>(history.deltaBytesSent[n], graphMaxOut);
|
||||
}
|
||||
}
|
||||
|
||||
_graphMaxIn = flerp(_graphMaxIn, graphMaxIn, graphTimeElapsed * 4.0f);
|
||||
_graphMaxOut = flerp(_graphMaxOut, graphMaxOut, graphTimeElapsed * 4.0f);
|
||||
|
||||
// Compute readable statistics.
|
||||
if (currentTicks - _lastStatsUpdateTime >= 1000)
|
||||
{
|
||||
float statsTimeElapsed = (currentTicks - _lastStatsUpdateTime) / 1000.0f;
|
||||
_lastStatsUpdateTime = currentTicks;
|
||||
|
||||
_bytesIn = _networkAccumulatedStats.deltaBytesReceived[NETWORK_STATISTICS_GROUP_TOTAL];
|
||||
_bytesOut = _networkAccumulatedStats.deltaBytesSent[NETWORK_STATISTICS_GROUP_TOTAL];
|
||||
_bytesInSec = (double)_bytesIn / statsTimeElapsed;
|
||||
_bytesOutSec = (double)_bytesOut / statsTimeElapsed;
|
||||
|
||||
_networkAccumulatedStats = {};
|
||||
}
|
||||
|
||||
_networkStats = curStats;
|
||||
_networkHistory.push_back(_networkLastDeltaStats);
|
||||
}
|
||||
|
||||
static void window_network_information_invalidate(rct_window* w)
|
||||
{
|
||||
window_network_set_pressed_tab(w);
|
||||
window_network_anchor_border_widgets(w);
|
||||
window_align_tabs(w, WIDX_TAB1, WIDX_TAB1);
|
||||
}
|
||||
|
||||
static void graph_draw_bar(rct_drawpixelinfo* dpi, int32_t x, int32_t y, int32_t height, int32_t width, int32_t colour)
|
||||
{
|
||||
gfx_fill_rect(dpi, x, y, x + width, y + height, colour);
|
||||
}
|
||||
|
||||
static void window_network_draw_graph(
|
||||
rct_window* w, rct_drawpixelinfo* dpi, int32_t x, int32_t y, int32_t height, int32_t width, int32_t barWidth, bool received)
|
||||
{
|
||||
float dataMax = received ? _graphMaxIn : _graphMaxOut;
|
||||
|
||||
// Draw box.
|
||||
gfx_draw_line(dpi, x, y, x, y + height, COLOUR_BLACK);
|
||||
gfx_draw_line(dpi, x, y + height, x + width, y + height, COLOUR_BLACK);
|
||||
|
||||
gfx_draw_line(dpi, x, y, x + width, y, COLOUR_BLACK);
|
||||
gfx_draw_line(dpi, x + width, y, x + width, y + height, COLOUR_BLACK);
|
||||
|
||||
// Draw graph inside box
|
||||
x = x + 1;
|
||||
y = y + 1;
|
||||
width = width - 2;
|
||||
height = height - 2;
|
||||
|
||||
rct_drawpixelinfo clippedDPI;
|
||||
if (!clip_drawpixelinfo(&clippedDPI, dpi, x, y, width, height))
|
||||
return;
|
||||
|
||||
dpi = &clippedDPI;
|
||||
|
||||
for (size_t i = 0; i < _networkHistory.size(); i++)
|
||||
{
|
||||
NetworkHistory_t history = _networkHistory[i];
|
||||
// std::sort(history.deltaBytesReceived.begin(), history.deltaBytesReceived.end(), std::greater<uint16_t>());
|
||||
|
||||
// NOTE: Capacity is not a mistake, we always want the full length.
|
||||
uint32_t curX = std::round(((float)i / (float)_networkHistory.capacity()) * barWidth * width);
|
||||
|
||||
float totalSum = 0.0f;
|
||||
for (int n = 1; n < NETWORK_STATISTICS_GROUP_MAX; n++)
|
||||
{
|
||||
if (received)
|
||||
totalSum += (float)history.deltaBytesReceived[n];
|
||||
else
|
||||
totalSum += (float)history.deltaBytesSent[n];
|
||||
}
|
||||
|
||||
int32_t yOffset = height;
|
||||
for (int n = 1; n < NETWORK_STATISTICS_GROUP_MAX; n++)
|
||||
{
|
||||
float totalHeight;
|
||||
float singleHeight;
|
||||
|
||||
if (received)
|
||||
{
|
||||
totalHeight = ((float)history.deltaBytesReceived[n] / dataMax) * height;
|
||||
singleHeight = ((float)history.deltaBytesReceived[n] / totalSum) * totalHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalHeight = ((float)history.deltaBytesSent[n] / dataMax) * height;
|
||||
singleHeight = ((float)history.deltaBytesSent[n] / totalSum) * totalHeight;
|
||||
}
|
||||
|
||||
uint32_t lineHeight = std::ceil(singleHeight);
|
||||
lineHeight = std::min<uint32_t>(lineHeight, height);
|
||||
|
||||
if (lineHeight > 0)
|
||||
{
|
||||
graph_draw_bar(dpi, curX, yOffset - lineHeight, lineHeight, barWidth, NetworkTrafficGroupColors[n]);
|
||||
}
|
||||
|
||||
yOffset -= lineHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void window_network_information_paint(rct_window* w, rct_drawpixelinfo* dpi)
|
||||
{
|
||||
char textBuffer[200] = {};
|
||||
|
||||
window_draw_widgets(w, dpi);
|
||||
window_network_draw_tab_images(w, dpi);
|
||||
|
||||
constexpr int32_t padding = 5;
|
||||
constexpr int32_t heightTab = 43;
|
||||
constexpr int32_t textHeight = 12;
|
||||
const int32_t graphBarWidth = std::min(1, w->width / WH);
|
||||
const int32_t totalHeight = w->height;
|
||||
const int32_t totalHeightText = (textHeight + (padding * 2)) * 3;
|
||||
const int32_t graphHeight = (totalHeight - totalHeightText - heightTab) / 2;
|
||||
|
||||
rct_drawpixelinfo clippedDPI;
|
||||
if (clip_drawpixelinfo(&clippedDPI, dpi, w->x, w->y, w->width, w->height))
|
||||
{
|
||||
dpi = &clippedDPI;
|
||||
|
||||
int32_t x = padding;
|
||||
int32_t y = heightTab + padding;
|
||||
|
||||
// Received stats.
|
||||
{
|
||||
gfx_draw_string_left(dpi, STR_NETWORK_RECEIVE, nullptr, PALETTE_INDEX_10, x, y);
|
||||
|
||||
format_readable_speed(textBuffer, sizeof(textBuffer), _bytesInSec);
|
||||
gfx_draw_string(dpi, textBuffer, PALETTE_INDEX_10, x + 70, y);
|
||||
|
||||
gfx_draw_string_left(dpi, STR_NETWORK_TOTAL_RECEIVED, nullptr, PALETTE_INDEX_10, x + 200, y);
|
||||
|
||||
format_readable_size(textBuffer, sizeof(textBuffer), _networkStats.bytesReceived[NETWORK_STATISTICS_GROUP_TOTAL]);
|
||||
gfx_draw_string(dpi, textBuffer, PALETTE_INDEX_10, x + 300, y);
|
||||
y += textHeight + padding;
|
||||
|
||||
window_network_draw_graph(w, dpi, x, y, graphHeight, w->width - (padding * 2), graphBarWidth, true);
|
||||
y += graphHeight + padding;
|
||||
}
|
||||
|
||||
// Sent stats.
|
||||
{
|
||||
gfx_draw_string_left(dpi, STR_NETWORK_SEND, nullptr, PALETTE_INDEX_10, x, y);
|
||||
|
||||
format_readable_speed(textBuffer, sizeof(textBuffer), _bytesOutSec);
|
||||
gfx_draw_string(dpi, textBuffer, PALETTE_INDEX_10, x + 70, y);
|
||||
|
||||
gfx_draw_string_left(dpi, STR_NETWORK_TOTAL_SENT, nullptr, PALETTE_INDEX_10, x + 200, y);
|
||||
|
||||
format_readable_size(textBuffer, sizeof(textBuffer), _networkStats.bytesSent[NETWORK_STATISTICS_GROUP_TOTAL]);
|
||||
gfx_draw_string(dpi, textBuffer, PALETTE_INDEX_10, x + 300, y);
|
||||
y += textHeight + padding;
|
||||
|
||||
window_network_draw_graph(w, dpi, x, y, graphHeight, w->width - (padding * 2), graphBarWidth, false);
|
||||
y += graphHeight + padding;
|
||||
}
|
||||
|
||||
// Draw legend
|
||||
{
|
||||
for (int i = 1; i < NETWORK_STATISTICS_GROUP_MAX; i++)
|
||||
{
|
||||
format_string(textBuffer, sizeof(textBuffer), NetworkTrafficGroupNames[i], nullptr);
|
||||
|
||||
// Draw color stripe.
|
||||
gfx_fill_rect(dpi, x, y + 4, x + 4, y + 6, NetworkTrafficGroupColors[i]);
|
||||
|
||||
// Draw text.
|
||||
gfx_draw_string(dpi, textBuffer, PALETTE_INDEX_10, x + 10, y);
|
||||
|
||||
gfx_get_string_width(textBuffer);
|
||||
|
||||
x += gfx_get_string_width(textBuffer) + 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
static void window_network_draw_tab_image(rct_window* w, rct_drawpixelinfo* dpi, int32_t page, int32_t spriteIndex)
|
||||
{
|
||||
rct_widgetindex widgetIndex = WIDX_TAB1 + page;
|
||||
|
||||
if (!widget_is_disabled(w, widgetIndex))
|
||||
{
|
||||
if (w->page == page)
|
||||
{
|
||||
int32_t numFrames = window_network_animation_frames[w->page];
|
||||
if (numFrames > 1)
|
||||
{
|
||||
int32_t frame = w->frame_no / window_network_animation_divisor[w->page];
|
||||
spriteIndex += (frame % numFrames);
|
||||
}
|
||||
}
|
||||
|
||||
gfx_draw_sprite(dpi, spriteIndex, w->x + w->widgets[widgetIndex].left, w->y + w->widgets[widgetIndex].top, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void window_network_draw_tab_images(rct_window* w, rct_drawpixelinfo* dpi)
|
||||
{
|
||||
window_network_draw_tab_image(w, dpi, WINDOW_NETWORK_PAGE_INFORMATION, SPR_TAB_KIOSKS_AND_FACILITIES_0);
|
||||
}
|
|
@ -138,7 +138,8 @@ enum TOP_TOOLBAR_DEBUG_DDIDX {
|
|||
};
|
||||
|
||||
enum TOP_TOOLBAR_NETWORK_DDIDX {
|
||||
DDIDX_MULTIPLAYER = 0
|
||||
DDIDX_MULTIPLAYER = 0,
|
||||
DDIDX_NETWORK = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -3238,8 +3239,11 @@ static void top_toolbar_init_network_menu(rct_window* w, rct_widget* widget)
|
|||
{
|
||||
gDropdownItemsFormat[0] = STR_MULTIPLAYER;
|
||||
|
||||
gDropdownItemsFormat[DDIDX_MULTIPLAYER] = STR_MULTIPLAYER;
|
||||
gDropdownItemsFormat[DDIDX_NETWORK] = STR_NETWORK;
|
||||
|
||||
window_dropdown_show_text(
|
||||
w->x + widget->left, w->y + widget->top, widget->bottom - widget->top + 1, w->colours[0] | 0x80, 0, 1);
|
||||
w->x + widget->left, w->y + widget->top, widget->bottom - widget->top + 1, w->colours[0] | 0x80, 0, 2);
|
||||
|
||||
gDropdownDefaultIndex = DDIDX_MULTIPLAYER;
|
||||
}
|
||||
|
@ -3294,6 +3298,9 @@ static void top_toolbar_network_menu_dropdown(int16_t dropdownIndex)
|
|||
case DDIDX_MULTIPLAYER:
|
||||
context_open_window(WC_MULTIPLAYER);
|
||||
break;
|
||||
case DDIDX_NETWORK:
|
||||
context_open_window(WC_NETWORK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ rct_window* window_land_rights_open();
|
|||
rct_window* window_main_open();
|
||||
rct_window* window_mapgen_open();
|
||||
rct_window* window_multiplayer_open();
|
||||
rct_window* window_network_open();
|
||||
rct_window* window_music_credits_open();
|
||||
rct_window* window_news_open();
|
||||
rct_window* window_news_options_open();
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2019 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
template<typename _TType, size_t _TMax> class CircularBuffer
|
||||
{
|
||||
public:
|
||||
typedef _TType value_type;
|
||||
typedef _TType* pointer;
|
||||
typedef const _TType* const_pointer;
|
||||
typedef _TType& reference;
|
||||
typedef const _TType& const_reference;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
reference front()
|
||||
{
|
||||
return _elements[_head];
|
||||
}
|
||||
|
||||
const_reference front() const
|
||||
{
|
||||
return _elements[_head];
|
||||
}
|
||||
|
||||
reference back()
|
||||
{
|
||||
return _elements[_tail];
|
||||
}
|
||||
|
||||
const_reference back() const
|
||||
{
|
||||
return _elements[_tail];
|
||||
}
|
||||
|
||||
reference operator[](size_type idx)
|
||||
{
|
||||
idx = (_head + idx) % capacity();
|
||||
return _elements[idx];
|
||||
}
|
||||
|
||||
const_reference operator[](size_type idx) const
|
||||
{
|
||||
idx = (_head + idx) % capacity();
|
||||
return _elements[idx];
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_head = 0;
|
||||
_tail = 0;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return _size == 0;
|
||||
}
|
||||
|
||||
constexpr size_type capacity() const
|
||||
{
|
||||
return _elements.size();
|
||||
}
|
||||
|
||||
void push_back(const value_type& val)
|
||||
{
|
||||
if (_size == 0)
|
||||
{
|
||||
_elements[_head] = val;
|
||||
_tail = _head;
|
||||
_size++;
|
||||
}
|
||||
else if (_size != capacity())
|
||||
{
|
||||
_tail++;
|
||||
if (_tail == capacity())
|
||||
_tail = 0;
|
||||
_size++;
|
||||
_elements[_tail] = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
_head++;
|
||||
if (_head == capacity())
|
||||
_head = 0;
|
||||
_tail++;
|
||||
if (_tail == capacity())
|
||||
_tail = 0;
|
||||
_elements[_tail] = val;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _head = 0;
|
||||
size_t _tail = 0;
|
||||
size_t _size = 0;
|
||||
std::array<_TType, _TMax> _elements;
|
||||
};
|
|
@ -420,6 +420,7 @@ enum
|
|||
WC_DEBUG_PAINT = 130,
|
||||
WC_VIEW_CLIPPING = 131,
|
||||
WC_OBJECT_LOAD_ERROR = 132,
|
||||
WC_NETWORK = 133,
|
||||
|
||||
// Only used for colour schemes
|
||||
WC_STAFF = 220,
|
||||
|
|
|
@ -1403,6 +1403,36 @@ void format_string_to_upper(utf8* dest, size_t size, rct_string_id format, const
|
|||
dest[upperString.size()] = '\0';
|
||||
}
|
||||
|
||||
void format_readable_size(char* buf, size_t bufSize, uint64_t sizeBytes)
|
||||
{
|
||||
constexpr uint32_t SizeTable[] = { STR_SIZE_BYTE, STR_SIZE_KILOBYTE, STR_SIZE_MEGABYTE, STR_SIZE_GIGABYTE,
|
||||
STR_SIZE_TERABYTE };
|
||||
|
||||
double size = sizeBytes;
|
||||
size_t idx = 0;
|
||||
while (size >= 1024.0)
|
||||
{
|
||||
size /= 1024.0;
|
||||
idx++;
|
||||
}
|
||||
|
||||
char sizeType[128] = {};
|
||||
format_string(sizeType, sizeof(sizeType), SizeTable[idx], nullptr);
|
||||
|
||||
sprintf(buf, "%.03f %s", size, sizeType);
|
||||
}
|
||||
|
||||
void format_readable_speed(char* buf, size_t bufSize, uint64_t sizeBytes)
|
||||
{
|
||||
char sizeText[128] = {};
|
||||
format_readable_size(sizeText, sizeof(sizeText), sizeBytes);
|
||||
|
||||
const char* args[1] = {
|
||||
sizeText,
|
||||
};
|
||||
format_string(buf, bufSize, STR_NETWORK_SPEED_SEC, args);
|
||||
}
|
||||
|
||||
money32 string_to_money(const char* string_to_monetise)
|
||||
{
|
||||
const char* decimal_char = language_get_string(STR_LOCALE_DECIMAL_POINT);
|
||||
|
|
|
@ -29,6 +29,17 @@ void format_string(char* dest, size_t size, rct_string_id format, const void* ar
|
|||
void format_string_raw(char* dest, size_t size, const char* src, const void* args);
|
||||
void format_string_to_upper(char* dest, size_t size, rct_string_id format, const void* args);
|
||||
void generate_string_file();
|
||||
|
||||
/**
|
||||
* Formats sizeBytes into buf as a human readable text, e.x.: "1024 MB"
|
||||
*/
|
||||
void format_readable_size(char* buf, size_t bufSize, uint64_t sizeBytes);
|
||||
|
||||
/**
|
||||
* Formats sizeBytesPerSec into buf as a human readable text, e.x.: "1024 MB/sec"
|
||||
*/
|
||||
void format_readable_speed(char* buf, size_t bufSize, uint64_t sizeBytesPerSec);
|
||||
|
||||
utf8* get_string_end(const utf8* text);
|
||||
size_t get_string_size(const utf8* text);
|
||||
int32_t get_string_length(const utf8* text);
|
||||
|
|
|
@ -3906,6 +3906,27 @@ enum
|
|||
STR_CHAT_BUTTON_ON_TOOLBAR = 6282,
|
||||
STR_CHAT_UNAVAILABLE = 6283,
|
||||
|
||||
STR_NETWORK = 6284,
|
||||
STR_NETWORK_INFORMATION_TITLE = 6285,
|
||||
|
||||
STR_NETWORK_RECEIVE = 6286,
|
||||
STR_NETWORK_SEND = 6287,
|
||||
|
||||
STR_NETWORK_TOTAL_RECEIVED = 6288,
|
||||
STR_NETWORK_TOTAL_SENT = 6289,
|
||||
|
||||
STR_NETWORK_LEGEND_BASE = 6290,
|
||||
STR_NETWORK_LEGEND_COMMANDS = 6291,
|
||||
STR_NETWORK_LEGEND_MAPDATA = 6292,
|
||||
|
||||
STR_SIZE_BYTE = 6293,
|
||||
STR_SIZE_KILOBYTE = 6294,
|
||||
STR_SIZE_MEGABYTE = 6295,
|
||||
STR_SIZE_GIGABYTE = 6296,
|
||||
STR_SIZE_TERABYTE = 6297,
|
||||
|
||||
STR_NETWORK_SPEED_SEC = 6298,
|
||||
|
||||
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
|
||||
STR_COUNT = 32768
|
||||
};
|
||||
|
|
|
@ -184,6 +184,8 @@ public:
|
|||
void Client_Send_OBJECTS(const std::vector<std::string>& objects);
|
||||
void Server_Send_OBJECTS(NetworkConnection& connection, const std::vector<const ObjectRepositoryItem*>& objects) const;
|
||||
|
||||
NetworkStats_t GetStats() const;
|
||||
|
||||
std::vector<std::unique_ptr<NetworkPlayer>> player_list;
|
||||
std::vector<std::unique_ptr<NetworkGroup>> group_list;
|
||||
NetworkKey _key;
|
||||
|
@ -205,6 +207,7 @@ private:
|
|||
void ProcessPacket(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void AddClient(std::unique_ptr<ITcpSocket>&& socket);
|
||||
void RemoveClient(std::unique_ptr<NetworkConnection>& connection);
|
||||
|
||||
NetworkPlayer* AddPlayer(const utf8* name, const std::string& keyhash);
|
||||
std::string MakePlayerNameUnique(const std::string& name);
|
||||
|
||||
|
@ -1396,6 +1399,27 @@ void Network::Server_Send_OBJECTS(NetworkConnection& connection, const std::vect
|
|||
connection.QueuePacket(std::move(packet));
|
||||
}
|
||||
|
||||
NetworkStats_t Network::GetStats() const
|
||||
{
|
||||
NetworkStats_t stats = {};
|
||||
if (mode == NETWORK_MODE_CLIENT)
|
||||
{
|
||||
stats = _serverConnection->Stats;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& connection : client_connection_list)
|
||||
{
|
||||
for (size_t n = 0; n < NETWORK_STATISTICS_GROUP_MAX; n++)
|
||||
{
|
||||
stats.bytesReceived[n] += connection->Stats.bytesReceived[n];
|
||||
stats.bytesSent[n] += connection->Stats.bytesSent[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
void Network::Server_Send_AUTH(NetworkConnection& connection)
|
||||
{
|
||||
uint8_t new_playerid = 0;
|
||||
|
@ -1412,7 +1436,6 @@ void Network::Server_Send_AUTH(NetworkConnection& connection)
|
|||
connection.QueuePacket(std::move(packet));
|
||||
if (connection.AuthStatus != NETWORK_AUTH_OK && connection.AuthStatus != NETWORK_AUTH_REQUIREPASSWORD)
|
||||
{
|
||||
connection.SendQueuedPackets();
|
||||
connection.Socket->Disconnect();
|
||||
}
|
||||
}
|
||||
|
@ -1538,6 +1561,7 @@ void Network::Client_Send_GAMECMD(
|
|||
std::unique_ptr<NetworkPacket> packet(NetworkPacket::Allocate());
|
||||
*packet << (uint32_t)NETWORK_COMMAND_GAMECMD << gCurrentTicks << eax << (ebx | GAME_COMMAND_FLAG_NETWORKED) << ecx << edx
|
||||
<< esi << edi << ebp << callback;
|
||||
|
||||
_serverConnection->QueuePacket(std::move(packet));
|
||||
}
|
||||
|
||||
|
@ -1569,7 +1593,6 @@ void Network::Client_Send_GAME_ACTION(const GameAction* action)
|
|||
action->Serialise(stream);
|
||||
|
||||
*packet << (uint32_t)NETWORK_COMMAND_GAME_ACTION << gCurrentTicks << action->GetType() << stream;
|
||||
|
||||
_serverConnection->QueuePacket(std::move(packet));
|
||||
}
|
||||
|
||||
|
@ -1616,6 +1639,7 @@ void Network::Server_Send_TICK()
|
|||
rct_sprite_checksum checksum = sprite_checksum();
|
||||
packet->WriteString(checksum.ToString().c_str());
|
||||
}
|
||||
|
||||
SendPacketToClients(*packet);
|
||||
}
|
||||
|
||||
|
@ -1666,7 +1690,6 @@ void Network::Server_Send_SETDISCONNECTMSG(NetworkConnection& connection, const
|
|||
*packet << (uint32_t)NETWORK_COMMAND_SETDISCONNECTMSG;
|
||||
packet->WriteString(msg);
|
||||
connection.QueuePacket(std::move(packet));
|
||||
connection.SendQueuedPackets();
|
||||
}
|
||||
|
||||
void Network::Server_Send_GAMEINFO(NetworkConnection& connection)
|
||||
|
@ -3853,6 +3876,11 @@ std::string network_get_version()
|
|||
return NETWORK_STREAM_ID;
|
||||
}
|
||||
|
||||
NetworkStats_t network_get_stats()
|
||||
{
|
||||
return gNetwork.GetStats();
|
||||
}
|
||||
|
||||
#else
|
||||
int32_t network_get_mode()
|
||||
{
|
||||
|
@ -4085,4 +4113,8 @@ std::string network_get_version()
|
|||
{
|
||||
return "Multiplayer disabled";
|
||||
}
|
||||
NetworkStats_t network_get_stats()
|
||||
{
|
||||
return NetworkStats_t{};
|
||||
}
|
||||
#endif /* DISABLE_NETWORK */
|
||||
|
|
|
@ -73,6 +73,9 @@ int32_t NetworkConnection::ReadPacket()
|
|||
if (InboundPacket.BytesTransferred == sizeof(InboundPacket.Size) + InboundPacket.Size)
|
||||
{
|
||||
_lastPacketTime = platform_get_ticks();
|
||||
|
||||
RecordPacketStats(InboundPacket, false);
|
||||
|
||||
return NETWORK_READPACKET_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +97,13 @@ bool NetworkConnection::SendPacket(NetworkPacket& packet)
|
|||
{
|
||||
packet.BytesTransferred += sent;
|
||||
}
|
||||
return packet.BytesTransferred == tosend.size();
|
||||
|
||||
bool sendComplete = packet.BytesTransferred == tosend.size();
|
||||
if (sendComplete)
|
||||
{
|
||||
RecordPacketStats(packet, true);
|
||||
}
|
||||
return sendComplete;
|
||||
}
|
||||
|
||||
void NetworkConnection::QueuePacket(std::unique_ptr<NetworkPacket> packet, bool front)
|
||||
|
@ -175,4 +184,32 @@ void NetworkConnection::SetLastDisconnectReason(const rct_string_id string_id, v
|
|||
SetLastDisconnectReason(buffer);
|
||||
}
|
||||
|
||||
void NetworkConnection::RecordPacketStats(const NetworkPacket& packet, bool sending)
|
||||
{
|
||||
uint32_t packetSize = (uint32_t)packet.BytesTransferred;
|
||||
uint32_t trafficGroup = NETWORK_STATISTICS_GROUP_BASE;
|
||||
|
||||
switch (packet.GetCommand())
|
||||
{
|
||||
case NETWORK_COMMAND_GAMECMD:
|
||||
case NETWORK_COMMAND_GAME_ACTION:
|
||||
trafficGroup = NETWORK_STATISTICS_GROUP_COMMANDS;
|
||||
break;
|
||||
case NETWORK_COMMAND_MAP:
|
||||
trafficGroup = NETWORK_STATISTICS_GROUP_MAPDATA;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sending)
|
||||
{
|
||||
Stats.bytesSent[trafficGroup] += packetSize;
|
||||
Stats.bytesSent[NETWORK_STATISTICS_GROUP_TOTAL] += packetSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
Stats.bytesReceived[trafficGroup] += packetSize;
|
||||
Stats.bytesReceived[NETWORK_STATISTICS_GROUP_TOTAL] += packetSize;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
std::unique_ptr<ITcpSocket> Socket = nullptr;
|
||||
NetworkPacket InboundPacket;
|
||||
NETWORK_AUTH AuthStatus = NETWORK_AUTH_NONE;
|
||||
NetworkStats_t Stats = {};
|
||||
NetworkPlayer* Player = nullptr;
|
||||
uint32_t PingTime = 0;
|
||||
NetworkKey Key;
|
||||
|
@ -53,6 +54,7 @@ private:
|
|||
uint32_t _lastPacketTime = 0;
|
||||
utf8* _lastDisconnectReason = nullptr;
|
||||
|
||||
void RecordPacketStats(const NetworkPacket& packet, bool sending);
|
||||
bool SendPacket(NetworkPacket& packet);
|
||||
};
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ uint8_t* NetworkPacket::GetData()
|
|||
return &(*Data)[0];
|
||||
}
|
||||
|
||||
int32_t NetworkPacket::GetCommand()
|
||||
int32_t NetworkPacket::GetCommand() const
|
||||
{
|
||||
if (Data->size() >= sizeof(uint32_t))
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
static std::unique_ptr<NetworkPacket> Duplicate(NetworkPacket& packet);
|
||||
|
||||
uint8_t* GetData();
|
||||
int32_t GetCommand();
|
||||
int32_t GetCommand() const;
|
||||
|
||||
void Clear();
|
||||
bool CommandRequiresAuth();
|
||||
|
|
|
@ -95,3 +95,18 @@ template<typename T, size_t _TypeID> struct NetworkObjectId_t
|
|||
// there is no way to specialize templates if they have the exact symbol.
|
||||
using NetworkPlayerId_t = NetworkObjectId_t<int32_t, 0>;
|
||||
using NetworkRideId_t = NetworkObjectId_t<int32_t, 1>;
|
||||
|
||||
enum NetworkStatisticsGroup
|
||||
{
|
||||
NETWORK_STATISTICS_GROUP_TOTAL = 0, // Entire network traffic.
|
||||
NETWORK_STATISTICS_GROUP_BASE, // Messages such as Tick, Ping
|
||||
NETWORK_STATISTICS_GROUP_COMMANDS, // Command / Game actions
|
||||
NETWORK_STATISTICS_GROUP_MAPDATA,
|
||||
NETWORK_STATISTICS_GROUP_MAX,
|
||||
};
|
||||
|
||||
struct NetworkStats_t
|
||||
{
|
||||
uint64_t bytesReceived[NETWORK_STATISTICS_GROUP_MAX];
|
||||
uint64_t bytesSent[NETWORK_STATISTICS_GROUP_MAX];
|
||||
};
|
||||
|
|
|
@ -101,3 +101,5 @@ const utf8* network_get_server_provider_email();
|
|||
const utf8* network_get_server_provider_website();
|
||||
|
||||
std::string network_get_version();
|
||||
|
||||
NetworkStats_t network_get_stats();
|
||||
|
|
|
@ -743,16 +743,9 @@ uint8_t lerp(uint8_t a, uint8_t b, float t)
|
|||
return (uint8_t)(a + amount);
|
||||
}
|
||||
|
||||
float flerp(float a, float b, float t)
|
||||
float flerp(float a, float b, float f)
|
||||
{
|
||||
if (t <= 0)
|
||||
return a;
|
||||
if (t >= 1)
|
||||
return b;
|
||||
|
||||
float range = b - a;
|
||||
float amount = range * t;
|
||||
return a + amount;
|
||||
return (a * (1.0f - f)) + (b * f);
|
||||
}
|
||||
|
||||
uint8_t soft_light(uint8_t a, uint8_t b)
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2019 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
#include <gtest/gtest.h>
|
||||
#include <openrct2/core/CircularBuffer.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
// CircularBuffer capacity.
|
||||
constexpr size_t TEST_BUFFER_SIZE = 128;
|
||||
|
||||
// Amount of elements to push into buffer, will overwrite entire buffer 8 times.
|
||||
constexpr size_t TEST_PUSH_COUNT = 1024;
|
||||
|
||||
TEST(CircularBufferTest, all)
|
||||
{
|
||||
CircularBuffer<size_t, TEST_BUFFER_SIZE> buffer1;
|
||||
ASSERT_EQ(buffer1.capacity(), TEST_BUFFER_SIZE);
|
||||
|
||||
// Mirror the effects of buffer1 into buffer2 to compare.
|
||||
std::vector<size_t> buffer2;
|
||||
|
||||
// Create
|
||||
{
|
||||
for (size_t i = 0; i < TEST_PUSH_COUNT; i++)
|
||||
{
|
||||
buffer1.push_back(i);
|
||||
buffer2.push_back(i);
|
||||
|
||||
// Mimic sliding window, always remove oldest element.
|
||||
if (buffer2.size() > buffer1.capacity())
|
||||
{
|
||||
buffer2.erase(buffer2.begin());
|
||||
}
|
||||
|
||||
ASSERT_EQ(buffer1.size(), buffer2.size());
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_EQ(buffer1.empty(), false);
|
||||
ASSERT_EQ(buffer1.size(), buffer2.size());
|
||||
|
||||
// Compare contents.
|
||||
{
|
||||
ASSERT_EQ(buffer1.front(), buffer1[0]);
|
||||
ASSERT_EQ(buffer1.back(), buffer1[buffer1.size() - 1]);
|
||||
|
||||
for (size_t i = 0; i < buffer1.size(); i++)
|
||||
{
|
||||
ASSERT_EQ(buffer1[i], buffer2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear
|
||||
{
|
||||
buffer1.clear();
|
||||
ASSERT_EQ(buffer1.empty(), true);
|
||||
ASSERT_EQ(buffer1.size(), size_t(0));
|
||||
}
|
||||
|
||||
SUCCEED();
|
||||
}
|
|
@ -56,6 +56,7 @@
|
|||
<ClInclude Include="TestData.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CircularBuffer.cpp" />
|
||||
<ClCompile Include="CryptTests.cpp" />
|
||||
<ClCompile Include="LanguagePackTest.cpp" />
|
||||
<ClCompile Include="ImageImporterTests.cpp" />
|
||||
|
|
Loading…
Reference in New Issue