1 /**
2 Copyright: Copyright (c) 2016 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module voxelman.dbg.plugin;
7 
8 import std.experimental.logger;
9 import std.array;
10 import pluginlib;
11 import derelict.imgui.imgui;
12 import voxelman.core.events;
13 import voxelman.eventdispatcher.plugin;
14 import voxelman.net.plugin;
15 import voxelman.utils.textformatter;
16 
17 
18 final class DebugClient : IPlugin
19 {
20 	mixin IdAndSemverFrom!(voxelman.dbg.plugininfo);
21 
22 	Debugger dbg;
23 	NetClientPlugin connection;
24 
25 	override void registerResourceManagers(void delegate(IResourceManager) registerHandler)
26 	{
27 		registerHandler(dbg = new Debugger);
28 	}
29 
30 	override void init(IPluginManager pluginman)
31 	{
32 		auto evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
33 		evDispatcher.subscribeToEvent(&handleDoGuiEvent);
34 		connection = pluginman.getPlugin!NetClientPlugin;
35 		connection.registerPacket!TelemetryPacket(&handleTelemetryPacket);
36 	}
37 
38 	void handleDoGuiEvent(ref DoGuiEvent event)
39 	{
40 		igBegin("Debug");
41 		foreach(key, var; dbg.vars) {
42 			igTextf("%s: %s", key, var);
43 		}
44 		foreach(key, ref buf; dbg.buffers) {
45 			igPlotLines2(key.ptr, &get_val, cast(void*)&buf, cast(int)buf.maxLen, cast(int)buf.next);
46 		}
47 		igEnd();
48 	}
49 
50 	private void handleTelemetryPacket(ubyte[] packetData, ClientId clientId)
51 	{
52 		auto packet = unpackPacketNoDup!TelemetryPacket(packetData);
53 		dbg.setVar(packet.name, packet.val);
54 	}
55 }
56 
57 extern(C) float get_val(void* data, int index)
58 {
59 	VarBuffer* buf = cast(VarBuffer*)data;
60 	return buf.vals[index % buf.maxLen];
61 }
62 
63 final class DebugServer : IPlugin
64 {
65 	mixin IdAndSemverFrom!(voxelman.dbg.plugininfo);
66 
67 	Debugger dbg;
68 	NetServerPlugin connection;
69 
70 	override void init(IPluginManager pluginman)
71 	{
72 		auto evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
73 		evDispatcher.subscribeToEvent(&handlePostUpdateEvent);
74 		connection = pluginman.getPlugin!NetServerPlugin;
75 		connection.registerPacket!TelemetryPacket();
76 	}
77 
78 	override void registerResourceManagers(void delegate(IResourceManager) registerHandler)
79 	{
80 		registerHandler(dbg = new Debugger);
81 	}
82 
83 	void handlePostUpdateEvent(ref PostUpdateEvent event)
84 	{
85 		foreach(pair; dbg.vars.byKeyValue())
86 		{
87 			connection.sendToAll(TelemetryPacket(pair.key, pair.value));
88 		}
89 	}
90 }
91 
92 struct VarBuffer
93 {
94 	this(float initVal, size_t _maxLen) {
95 		maxLen = _maxLen;
96 		vals = uninitializedArray!(float[])(maxLen);
97 		vals[0] = initVal;
98 		vals[1..$] = 0;
99 		length = 1;
100 		next = 1;
101 	}
102 	void insert(float val)
103 	{
104 		vals[next] = val;
105 		next = (next + 1) % maxLen;
106 		length = (length + 1) % maxLen;
107 	}
108 	@disable this();
109 	float[] vals;
110 	size_t next;
111 	size_t length;
112 	size_t maxLen;
113 }
114 
115 
116 final class Debugger : IResourceManager
117 {
118 	override string id() @property { return "voxelman.dbg.debugger"; }
119 	VarBuffer[string] buffers;
120 	float[string] vars;
121 
122 	void logVar(string name, float val, size_t maxLen)
123 	{
124 		if (auto buf = name in buffers)
125 			buf.insert(val);
126 		else
127 			buffers[name] = VarBuffer(val, maxLen);
128 	}
129 
130 	void setVar(string name, float val)
131 	{
132 		vars[name] = val;
133 	}
134 
135 	void clearVar(string name)
136 	{
137 		buffers.remove(name);
138 	}
139 }
140 
141 struct TelemetryPacket
142 {
143 	string name;
144 	float val;
145 }