initial
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "debug/ComponentGui.hpp"
|
||||
#include "world/CharacterBody.hpp"
|
||||
|
||||
template<>
|
||||
class tw::dbg::ComponentGui<tw::CharacterBody> {
|
||||
public:
|
||||
void draw(CharacterBody* instance) {
|
||||
ImGui::SeparatorText("Character Body Component");
|
||||
|
||||
auto position = instance->m_character->GetPosition();
|
||||
ImGui::InputFloat3("Position", (float*)&position);
|
||||
|
||||
auto new_velocity = instance->m_character->GetLinearVelocity();
|
||||
ImGui::InputFloat3("New Velocity", (float*)&new_velocity);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "debug/ComponentGui.hpp"
|
||||
#include "world/CharacterController.hpp"
|
||||
|
||||
template<>
|
||||
class tw::dbg::ComponentGui<tw::CharacterController> {
|
||||
public:
|
||||
void draw(tw::CharacterController* instance) {
|
||||
ImGui::SeparatorText("Character Controller Component");
|
||||
|
||||
if(ImGui::BeginTable("history", 3)) {
|
||||
for(auto key : instance->input_history().buffer()) {
|
||||
// ImGui::TableNextRow();
|
||||
|
||||
// ImGui::TableNextColumn();
|
||||
// ImGui::Text("%u", key.first);
|
||||
|
||||
// ImGui::TableNextColumn();
|
||||
// if(instance->input_history().get(key.first).has_value()) {
|
||||
// glm::vec3 input_vec = *instance->input_history().get(key.first).value();
|
||||
// std::string input = std::format("{} {} {}", input_vec.x, input_vec.y, input_vec.z);
|
||||
// ImGui::Text("%s", input.c_str());
|
||||
// } else {
|
||||
// ImGui::Text("None");
|
||||
// }
|
||||
|
||||
// ImGui::TableNextColumn();
|
||||
// if(instance->position_history().get(key).has_value()) {
|
||||
// glm::vec3 position_vec = *instance->position_history().get(key).value();
|
||||
// std::string position = std::format("{} {} {}", position_vec.x, position_vec.y, position_vec.z);
|
||||
// ImGui::Text("%s", position.c_str());
|
||||
// } else {
|
||||
// ImGui::Text("None");
|
||||
// }
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace tw::dbg {
|
||||
|
||||
template<typename T>
|
||||
class ComponentGui {
|
||||
public:
|
||||
void draw(T* instance);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tw::dbg {
|
||||
|
||||
class DebugComponent {
|
||||
private:
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
inline const std::string& name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
DebugComponent(const std::string& name) :
|
||||
m_name{name} {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
#include <ratio>
|
||||
|
||||
#include "debug/ComponentGui.hpp"
|
||||
#include <implot.h>
|
||||
#include <implot_internal.h>
|
||||
#include "network/EntityInterpolation.hpp"
|
||||
|
||||
template<>
|
||||
class tw::dbg::ComponentGui<tw::net::EntityPositionInterpolation> {
|
||||
public:
|
||||
void draw(net::EntityPositionInterpolation* instance) {
|
||||
ImGui::SeparatorText("Entity Interpolation");
|
||||
|
||||
bool m_is_scrolling = true;
|
||||
static float m_metric_history = 10.0f;
|
||||
ImGui::Checkbox("Is Scrolling", &m_is_scrolling);
|
||||
if(m_is_scrolling) {
|
||||
ImGui::SliderFloat("History", &m_metric_history,1,30,"%.1f s");
|
||||
}
|
||||
|
||||
static int32_t time_buffer_len = 1000;
|
||||
ImGui::SliderInt("Buffer length (ms)", &time_buffer_len, 0, 1000);
|
||||
|
||||
auto now = std::chrono::high_resolution_clock::now() - std::chrono::milliseconds(time_buffer_len);
|
||||
auto [from, to, mix] = instance->get_values_around(now);
|
||||
auto mixed_value = glm::mix(from, to, mix);
|
||||
|
||||
ImGui::Text("Mixed value: (%f, %f)", mixed_value.x, mixed_value.y);
|
||||
|
||||
if(ImPlot::BeginPlot("Interpolation")) {
|
||||
auto plot_x_from = instance->times().begin()->time_since_epoch().count();
|
||||
std::vector<float> times(instance->times().max_size());
|
||||
for(auto it = instance->times().begin(); it != instance->times().end(); ++it) {
|
||||
times.push_back(it->time_since_epoch().count() - plot_x_from);
|
||||
}
|
||||
|
||||
float interpolated_time = now.time_since_epoch().count() - plot_x_from;
|
||||
std::vector<float> values(instance->values().max_size());
|
||||
for(auto it = instance->values().begin(); it != instance->values().end(); ++it) {
|
||||
values.push_back(it->x);
|
||||
}
|
||||
values.push_back(mixed_value.x);
|
||||
|
||||
ImPlot::PlotScatter("Server", times.data(), values.data(), times.size() - 1);
|
||||
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
|
||||
ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 6, ImPlot::GetColormapColor(1), IMPLOT_AUTO, ImPlot::GetColormapColor(1));
|
||||
ImPlot::PlotScatter("Client", &interpolated_time, &mixed_value.x, 1);
|
||||
ImPlot::PopStyleVar();
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
|
||||
if(ImGui::BeginTable("entityInterpolation", 2)) {
|
||||
for(int i = 0; i < instance->values().size(); i++) {
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
auto value = instance->values()[i];
|
||||
auto now = std::chrono::high_resolution_clock::now() - std::chrono::milliseconds(time_buffer_len);
|
||||
if(instance->times()[i] > now && (i == instance->values().size() - 1 || instance->times()[i + 1] <= now)) {
|
||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, ImGui::GetColorU32(ImVec4(0.7f, 0.3f, 0.3f, 0.65f)));
|
||||
ImGui::Text("%f %f %f", mixed_value.x, mixed_value.y, mixed_value.z);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)));
|
||||
}
|
||||
|
||||
ImGui::Text("%f %f %f", value.x, value.y, value.z);
|
||||
|
||||
auto point = instance->times()[i].time_since_epoch();
|
||||
auto hours = std::chrono::duration_cast<std::chrono::hours>(point);
|
||||
point -= hours;
|
||||
hours %= 24;
|
||||
auto minutes = std::chrono::duration_cast<std::chrono::minutes>(point);
|
||||
point -= minutes;
|
||||
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(point);
|
||||
point -= seconds;
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(point);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
auto fmt = std::format("{}:{}:{}.{}", hours, minutes, seconds, milliseconds);
|
||||
ImGui::Text(fmt.c_str());
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "EntityManagerGui.hpp"
|
||||
|
||||
#include "debug/tools/MatrixWidget.hpp"
|
||||
#include "debug/EntityInterpolationDebug.hpp"
|
||||
#include "debug/CharacterBodyDebug.hpp"
|
||||
#include "debug/CharacterControllerDebug.hpp"
|
||||
|
||||
#include "network/EntityInterpolation.hpp"
|
||||
#include "world/CharacterBody.hpp"
|
||||
#include "world/CharacterController.hpp"
|
||||
#include "world/Transform.hpp"
|
||||
#include "world/WorldEntity.hpp"
|
||||
#include "draw/Mesh.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
EntityManagerGui::EntityManagerGui(World* world) :
|
||||
m_world(world) {
|
||||
|
||||
}
|
||||
|
||||
void draw_transform_controls(Transform* transform) {
|
||||
|
||||
}
|
||||
|
||||
void EntityManagerGui::draw_entity_components() {
|
||||
ImGui::Text("Entity ID: %d", (uint32_t)m_selected);
|
||||
|
||||
ImGui::BeginChild("Transform Component", ImVec2(0, 0), ImGuiChildFlags_Border);
|
||||
|
||||
auto transform = m_world->registry().try_get<Transform>(m_selected);
|
||||
|
||||
if(transform != nullptr) {
|
||||
ImGui::SeparatorText("Transform Component");
|
||||
draw_matrix_widget(transform->transform, true);
|
||||
|
||||
draw_transform_controls(transform);
|
||||
}
|
||||
|
||||
|
||||
auto mesh = m_world->registry().try_get<tw::drw::Mesh>(m_selected);
|
||||
if(mesh != nullptr) {
|
||||
ImGui::SeparatorText("Mesh Component");
|
||||
ImGui::Text("Num vertices: %i", mesh->num_vertices());
|
||||
ImGui::Text("Vertex offset: %i", mesh->vertex_offset());
|
||||
}
|
||||
|
||||
draw_debug_components<tw::CharacterBody, tw::CharacterController, tw::net::EntityPositionInterpolation>();
|
||||
|
||||
// auto character = m_world->registry().try_get<tw::CharacterBody>(m_selected);
|
||||
// if(character != nullptr) {
|
||||
// tw::dbg::ComponentGui<tw::CharacterBody>().draw(character);
|
||||
// }
|
||||
//
|
||||
// auto entity_interpolation = m_world->registry().try_get<EntityInterpolation>(m_selected);
|
||||
// if(entity_interpolation != nullptr) {
|
||||
// tw::dbg::ComponentGui<EntityInterpolation>().draw(entity_interpolation);
|
||||
// }
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void EntityManagerGui::draw() {
|
||||
ImGui::Begin("Transforms");
|
||||
|
||||
ImGui::BeginChild("Entities", ImVec2(0, 260), ImGuiChildFlags_Border);
|
||||
|
||||
ImGui::SeparatorText("Entities");
|
||||
|
||||
auto view = m_world->registry().view<const WorldEntity>();
|
||||
|
||||
view.each([&](const auto entity, const WorldEntity& info) {
|
||||
ImGui::PushID((uint32_t)info.entity_id);
|
||||
if(ImGui::Selectable(info.name.c_str(), m_selected_entity == info.entity_id)) {
|
||||
m_selected_entity = info.entity_id;
|
||||
m_selected = entity;
|
||||
}
|
||||
ImGui::PopID();
|
||||
});
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
if(m_selected_entity.has_value()) {
|
||||
draw_entity_components();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "debug/ComponentGui.hpp"
|
||||
#include "entt/entity/fwd.hpp"
|
||||
#include "world/World.hpp"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
class EntityManagerGui {
|
||||
private:
|
||||
World* m_world;
|
||||
|
||||
entt::entity m_selected;
|
||||
std::optional<uint32_t> m_selected_entity;
|
||||
|
||||
void draw_entity_components();
|
||||
|
||||
template<class... Ts>
|
||||
void draw_debug_components() {
|
||||
(
|
||||
[&]() {
|
||||
auto character = m_world->registry().try_get<Ts>(m_selected);
|
||||
if(character != nullptr) {
|
||||
tw::dbg::ComponentGui<Ts>().draw(character);
|
||||
}
|
||||
}(),
|
||||
...);
|
||||
}
|
||||
|
||||
public:
|
||||
entt::entity& selected() {
|
||||
return m_selected;
|
||||
}
|
||||
|
||||
EntityManagerGui(World* world);
|
||||
|
||||
void draw();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "MatrixWidget.hpp"
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
void draw_matrix_widget(const glm::mat4 &mat, bool display_headers) {
|
||||
if(ImGui::BeginTable("transform_component", 4, ImGuiTableFlags_Borders)) {
|
||||
if(display_headers) {
|
||||
ImGui::TableSetupColumn("Right");
|
||||
ImGui::TableSetupColumn("Front");
|
||||
ImGui::TableSetupColumn("Up");
|
||||
ImGui::TableSetupColumn("Translation");
|
||||
ImGui::TableHeadersRow();
|
||||
}
|
||||
|
||||
for(int row = 0; row < 4; row++) {
|
||||
ImGui::TableNextRow();
|
||||
|
||||
for(int col = 0; col < 4; col++) {
|
||||
ImGui::TableSetColumnIndex(col);
|
||||
ImGui::Text("%f", mat[col][row]);
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
void draw_matrix_widget(const glm::mat4& mat, bool display_headers);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
#include <implot.h>
|
||||
#include <implot_internal.h>
|
||||
|
||||
#include "metrics/BucketMetric.hpp"
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
template<typename T, typename Interval, typename Op = net::SumOp<T>>
|
||||
class MetricWidget {
|
||||
std::string m_name;
|
||||
|
||||
net::BucketMetric<T, Interval, Op>& m_metric;
|
||||
|
||||
using Self = MetricWidget<T, Interval, Op>;
|
||||
|
||||
struct {
|
||||
T constraint_from;
|
||||
T constraint_to;
|
||||
|
||||
T from;
|
||||
T to;
|
||||
} y_axis;
|
||||
|
||||
bool m_is_scrolling = true;
|
||||
|
||||
public:
|
||||
MetricWidget(
|
||||
const std::string& name,
|
||||
net::BucketMetric<T, Interval, Op>& metric
|
||||
) :
|
||||
m_name(name),
|
||||
m_metric(metric)
|
||||
{
|
||||
y_axis = {
|
||||
.constraint_from = 0,
|
||||
.constraint_to = 500,
|
||||
.from = 0,
|
||||
.to = 250
|
||||
};
|
||||
}
|
||||
|
||||
Self& set_x_axis_limits_contraints(T from, T to) {
|
||||
ImPlot::SetupAxisLimits(ImAxis_X1, from, to);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self& set_y_axis_limits(double from, double to) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self& enable_scrolling() {
|
||||
m_is_scrolling = true;
|
||||
}
|
||||
|
||||
Self& disable_scrolling() {
|
||||
m_is_scrolling = true;
|
||||
}
|
||||
|
||||
|
||||
void draw() {
|
||||
ImGui::PushID(m_name.c_str());
|
||||
|
||||
auto head = m_metric.get_head();
|
||||
auto head_timeline = m_metric.get_head_timeline();
|
||||
|
||||
auto tail = m_metric.get_tail();
|
||||
auto tail_timeline = m_metric.get_tail_timeline();
|
||||
|
||||
static float m_metric_history = 10.0f;
|
||||
ImGui::Checkbox("Is Scrolling", &m_is_scrolling);
|
||||
if(m_is_scrolling) {
|
||||
ImGui::SliderFloat("History", &m_metric_history,1,30,"%.1f s");
|
||||
}
|
||||
|
||||
ImGui::Text("Min: %i", m_metric.min());
|
||||
ImGui::Text("Max: %i", m_metric.max());
|
||||
|
||||
if(ImPlot::BeginPlot(m_name.c_str())) {
|
||||
auto from = tail_timeline.empty() ? *(head_timeline.end() - 1) : *(tail_timeline.end() - 1);
|
||||
|
||||
ImPlot::SetupAxes("Time", m_name.c_str(), ImPlotAxisFlags_None, ImPlotAxisFlags_None);
|
||||
if(m_is_scrolling) {
|
||||
ImPlot::SetupAxisLimits(ImAxis_X1, from - m_metric_history, from, ImGuiCond_Always);
|
||||
}
|
||||
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, 0, m_metric.max() * 2, ImGuiCond_Always);
|
||||
// ImPlot::SetupAxisLimitsConstraints(ImAxis_Y1, 0, 10000);
|
||||
|
||||
ImPlot::PlotLine(m_name.c_str(), head_timeline.data(), head.data(), head.size());
|
||||
ImPlot::PlotLine(m_name.c_str(), tail_timeline.data(), tail.data(), tail.size());
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "metrics/BucketMetric.hpp"
|
||||
#include "metrics/NetworkStatsLogger.hpp"
|
||||
#include "debug/tools/MetricWidget.hpp"
|
||||
|
||||
#include <implot.h>
|
||||
#include <implot_internal.h>
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
class NetworkStatsGui {
|
||||
private:
|
||||
// MetricWidget<uint32_t, std::chrono::seconds, net::AverageOp<uint32_t>> m_ping_widget;
|
||||
// MetricWidget<uint32_t, std::chrono::seconds> m_outgoing_widget;
|
||||
// MetricWidget<uint32_t, std::chrono::seconds> m_incoming_widget;
|
||||
|
||||
public:
|
||||
// NetworkStatsGui() :
|
||||
// m_ping_widget("Ping", net::NetworkStatsLogger::instance()->ping()),
|
||||
// m_outgoing_widget("Outgoing", net::NetworkStatsLogger::instance()->outgoing()),
|
||||
// m_incoming_widget("Incoming", net::NetworkStatsLogger::instance()->incoming())
|
||||
// {
|
||||
// }
|
||||
|
||||
void draw() {
|
||||
// auto* instance = net::NetworkStatsLogger::instance();
|
||||
// auto& ping = instance->ping();
|
||||
|
||||
ImGui::Begin("Network Stats");
|
||||
|
||||
/* auto head = ping.get_head();
|
||||
auto head_timeline = ping.get_head_timeline();
|
||||
|
||||
auto tail = ping.get_tail();
|
||||
auto tail_timeline = ping.get_tail_timeline();
|
||||
|
||||
static float ping_history = 10.0f;
|
||||
ImGui::SliderFloat("Ping History", &ping_history,1,30,"%.1f s");
|
||||
|
||||
if(ImPlot::BeginPlot("Ping")) {
|
||||
auto from = tail_timeline.empty() ? *(head_timeline.end() - 1) : *(tail_timeline.end() - 1);
|
||||
|
||||
ImPlot::SetupAxes("FrameIdx","FPS", ImPlotAxisFlags_None, ImPlotAxisFlags_None);
|
||||
ImPlot::SetupAxisLimits(ImAxis_X1, from - ping_history, from, ImGuiCond_Always);
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, 0, 120);
|
||||
ImPlot::SetupAxisLimitsConstraints(ImAxis_Y1, 0, 10000);
|
||||
|
||||
ImPlot::PlotLine("Ping", head_timeline.data(), head.data(), head.size());
|
||||
ImPlot::PlotLine("Ping", tail_timeline.data(), tail.data(), tail.size());
|
||||
ImPlot::EndPlot();
|
||||
} */
|
||||
|
||||
// m_ping_widget.draw();
|
||||
// m_outgoing_widget.draw();
|
||||
// m_incoming_widget.draw();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <vector>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include "metrics/NetworkStatsLogger.hpp"
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
class PacketBacklogGui {
|
||||
private:
|
||||
std::vector<uint32_t> m_buckets;
|
||||
uint32_t m_last_backlog_idx;
|
||||
|
||||
public:
|
||||
void draw() {
|
||||
// auto* instance = net::NetworkStatsLogger::instance();
|
||||
// size_t size = instance->get_size();
|
||||
|
||||
// if(ImGui::BeginTable("Network Packets", 5)) {
|
||||
// ImGui::TableSetupColumn("Message Type");
|
||||
// ImGui::TableSetupColumn("Time");
|
||||
// ImGui::TableSetupColumn("Is From Us");
|
||||
// ImGui::TableSetupColumn("Target");
|
||||
// ImGui::TableSetupColumn("Size");
|
||||
|
||||
// for(int32_t i = size-1; i >= 0; i--) {
|
||||
// auto& item = instance->get_item(i);
|
||||
// ImGui::PushID(item.timepoint.time_since_epoch().count());
|
||||
|
||||
// ImGui::TableNextRow();
|
||||
|
||||
// ImGui::TableNextColumn();
|
||||
// ImGui::Text("%i", item.message_type);
|
||||
|
||||
// ImGui::TableNextColumn();
|
||||
// ImGui::Text(std::format("{}", item.timepoint.time_since_epoch()).c_str());
|
||||
|
||||
// ImGui::TableNextColumn();
|
||||
// ImGui::Checkbox("is_sent_from_us", &item.is_sent_by_us);
|
||||
|
||||
// ImGui::TableNextColumn();
|
||||
// ImGui::Text(item.target.to_string().c_str());
|
||||
|
||||
// ImGui::TableNextColumn();
|
||||
// ImGui::Text("%ld", item.buffer.size());
|
||||
|
||||
// ImGui::PopID();
|
||||
// }
|
||||
// ImGui::EndTable();
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "Address.hpp"
|
||||
#include "ByteBuffer.hpp"
|
||||
#include "packets/Packet.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
class SavedPacket {
|
||||
public:
|
||||
PacketType type;
|
||||
bool is_from_client;
|
||||
|
||||
net::Address origin;
|
||||
net::Address target;
|
||||
|
||||
net::ByteBuffer content;
|
||||
|
||||
public:
|
||||
SavedPacket() :
|
||||
origin({}, 0),
|
||||
target({}, 0),
|
||||
content(1024)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class PacketLogger {
|
||||
private:
|
||||
std::vector<SavedPacket> m_packets;
|
||||
uint32_t m_left, m_right;
|
||||
|
||||
public:
|
||||
inline const std::vector<SavedPacket>& packets() const {
|
||||
return m_packets;
|
||||
}
|
||||
|
||||
PacketLogger(uint32_t max_packets) :
|
||||
m_packets(max_packets) {
|
||||
}
|
||||
|
||||
void push(PacketType type, bool is_from_client,
|
||||
net::Address origin, net::Address target,
|
||||
net::ByteBuffer& content) {
|
||||
SavedPacket& packet = m_packets[m_right];
|
||||
packet.type = type;
|
||||
packet.is_from_client = is_from_client;
|
||||
packet.origin = origin;
|
||||
packet.target = target;
|
||||
memcpy(packet.content.data().data(), content.data().data(), content.writing_head());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "PerformanceStatsGui.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <implot.h>
|
||||
#include <implot_internal.h>
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
PerformanceStatsGui::PerformanceStatsGui(LockStep& lock_step) :
|
||||
m_lockstep(lock_step),
|
||||
fps_history(1000),
|
||||
frame_idxs(1000)
|
||||
{
|
||||
}
|
||||
|
||||
void PerformanceStatsGui::draw() {
|
||||
ImGui::Begin("Stats");
|
||||
|
||||
ImGui::Text("FPS: %ld", m_lockstep.fps());
|
||||
fps_history[fps_history_idx] = m_lockstep.fps();
|
||||
frame_idxs[fps_history_idx] = frame_idx++;
|
||||
|
||||
if(fps_history_idx == fps_history.size() - 1) {
|
||||
is_plot_filled = true;
|
||||
}
|
||||
|
||||
fps_history_idx = (fps_history_idx + 1) % fps_history.size();
|
||||
|
||||
if(ImPlot::BeginPlot("FPS Plot")) {
|
||||
ImPlot::SetupAxes("FrameIdx","FPS", ImPlotAxisFlags_None, ImPlotAxisFlags_None);
|
||||
ImPlot::SetupAxisLimits(ImAxis_X1, std::max((double)frame_idx - 1000.0, 0.0), frame_idx, ImGuiCond_Always);
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1,0,120);
|
||||
ImPlot::SetupAxisLimitsConstraints(ImAxis_Y1, 0, 120);
|
||||
ImPlot::PlotLine("FPS", frame_idxs.data(), fps_history.data(), is_plot_filled ? (int)fps_history.size() : (int)fps_history_idx - 1);
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "runtime/LockStep.hpp"
|
||||
|
||||
namespace tw::dbg::tools {
|
||||
|
||||
class PerformanceStatsGui {
|
||||
private:
|
||||
LockStep& m_lockstep;
|
||||
|
||||
std::vector<uint32_t> fps_history;
|
||||
std::vector<uint32_t> frame_idxs;
|
||||
|
||||
uint32_t fps_history_idx = 0;
|
||||
uint32_t frame_idx = 0;
|
||||
bool is_plot_filled = false;
|
||||
|
||||
public:
|
||||
PerformanceStatsGui(LockStep& lock_step);
|
||||
|
||||
void draw();
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user