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 }