1 /** 2 Copyright: Copyright (c) 2016-2018 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 voxelman.log; 9 import std.array; 10 import std.container.rbtree; 11 import pluginlib; 12 import voxelman.core.events; 13 import voxelman.eventdispatcher.plugin; 14 import voxelman.net.plugin; 15 import voxelman.graphics.plugin; 16 import voxelman.text.textformatter; 17 18 alias DebugGuiHandler = void delegate(); 19 20 enum FPS_ORDER = 0; 21 enum INFO_ORDER = 50; 22 enum DEBUG_ORDER = 100; 23 enum SETTINGS_ORDER = 200; 24 25 struct DebugGuiHandlerItem 26 { 27 int order; 28 string name; 29 DebugGuiHandler handler; 30 31 int opCmp(ref const DebugGuiHandlerItem other) const { 32 int orderDiff = other.order - order; 33 if (orderDiff == 0) return other.name < name; 34 return orderDiff; 35 } 36 } 37 38 final class DebugClient : IPlugin 39 { 40 mixin IdAndSemverFrom!"voxelman.dbg.plugininfo"; 41 42 Debugger dbg; 43 NetClientPlugin connection; 44 RedBlackTree!(DebugGuiHandlerItem, "a>b") handlerList; 45 LineBuffer* debugText; 46 47 override void registerResourceManagers(void delegate(IResourceManager) registerHandler) 48 { 49 registerHandler(dbg = new Debugger); 50 } 51 52 override void preInit() 53 { 54 handlerList = new typeof(handlerList); 55 registerDebugGuiHandler(&drawDebugGroup, DEBUG_ORDER, "Debug"); 56 } 57 58 override void init(IPluginManager pluginman) 59 { 60 auto evDispatcher = pluginman.getPlugin!EventDispatcherPlugin; 61 evDispatcher.subscribeToEvent(&handleDoGuiEvent); 62 connection = pluginman.getPlugin!NetClientPlugin; 63 connection.registerPacket!TelemetryPacket(&handleTelemetryPacket); 64 auto graphics = pluginman.getPlugin!GraphicsPlugin; 65 debugText = &graphics.debugText; 66 } 67 68 // bigger order items go lower in menu 69 void registerDebugGuiHandler(DebugGuiHandler handler, int order, string name) 70 { 71 handlerList.insert(DebugGuiHandlerItem(order, name, handler)); 72 } 73 74 void handleDoGuiEvent(ref DoGuiEvent event) 75 { 76 //igSetNextWindowSize(ImVec2(225, 380), ImGuiSetCond_Once); 77 //igSetNextWindowPos(ImVec2(0, 0), ImGuiSetCond_Once); 78 //igBegin("Debug"); 79 foreach(item; handlerList[]) 80 { 81 item.handler(); 82 } 83 //igEnd(); 84 } 85 86 private void drawDebugGroup() 87 { 88 //if (igCollapsingHeader("Debug")) 89 //{ 90 // foreach(key, var; dbg.vars) { 91 // igTextf("%s: %s", key, var); 92 // } 93 // foreach(key, ref buf; dbg.buffers) { 94 // igPlotLines2(key.ptr, &get_val, cast(void*)&buf, cast(int)buf.maxLen, cast(int)buf.next); 95 // } 96 //} 97 98 foreach(key, var; dbg.vars) { 99 debugText.putfln("%s: %s", key, var); 100 } 101 } 102 103 private void handleTelemetryPacket(ubyte[] packetData) 104 { 105 auto packet = unpackPacketNoDup!TelemetryPacket(packetData); 106 dbg.setVar(packet.name, packet.val); 107 } 108 } 109 110 extern(C) float get_val(void* data, int index) 111 { 112 VarBuffer* buf = cast(VarBuffer*)data; 113 return buf.vals[index % buf.maxLen]; 114 } 115 116 final class DebugServer : IPlugin 117 { 118 mixin IdAndSemverFrom!"voxelman.dbg.plugininfo"; 119 120 Debugger dbg; 121 NetServerPlugin connection; 122 123 override void init(IPluginManager pluginman) 124 { 125 auto evDispatcher = pluginman.getPlugin!EventDispatcherPlugin; 126 evDispatcher.subscribeToEvent(&handlePostUpdateEvent); 127 connection = pluginman.getPlugin!NetServerPlugin; 128 connection.registerPacket!TelemetryPacket(); 129 } 130 131 override void registerResourceManagers(void delegate(IResourceManager) registerHandler) 132 { 133 registerHandler(dbg = new Debugger); 134 } 135 136 void handlePostUpdateEvent(ref PostUpdateEvent event) 137 { 138 foreach(pair; dbg.vars.byKeyValue()) 139 { 140 connection.sendToAll(TelemetryPacket(pair.key, pair.value)); 141 } 142 } 143 } 144 145 struct VarBuffer 146 { 147 this(double initVal, size_t _maxLen) { 148 maxLen = _maxLen; 149 vals = uninitializedArray!(double[])(maxLen); 150 vals[0] = initVal; 151 vals[1..$] = 0; 152 length = 1; 153 next = 1; 154 } 155 void insert(double val) 156 { 157 vals[next] = val; 158 next = (next + 1) % maxLen; 159 length = (length + 1) % maxLen; 160 } 161 @disable this(); 162 double[] vals; 163 size_t next; 164 size_t length; 165 size_t maxLen; 166 } 167 168 169 final class Debugger : IResourceManager 170 { 171 override string id() @property { return "voxelman.dbg.debugger"; } 172 VarBuffer[string] buffers; 173 double[string] vars; 174 175 void logVar(string name, double val, size_t maxLen) 176 { 177 if (auto buf = name in buffers) 178 buf.insert(val); 179 else 180 buffers[name] = VarBuffer(val, maxLen); 181 } 182 183 void setVar(string name, double val) 184 { 185 vars[name] = val; 186 } 187 188 void clearVar(string name) 189 { 190 buffers.remove(name); 191 } 192 } 193 194 struct TelemetryPacket 195 { 196 string name; 197 double val; 198 }