]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/debug.qh
Merge branch 'TimePath/botammo_div0' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / debug.qh
1 #pragma once
2
3 #ifdef CSQC
4 .entity tag_entity;
5 #endif
6
7 #ifdef GAMEQC
8 .bool debug;
9 .int sv_entnum;
10 REGISTER_NET_TEMP(net_debug)
11 #endif
12
13 #ifdef CSQC
14         NET_HANDLE(net_debug, bool isNew)
15         {
16                 Net_Accept(net_debug);
17                 this.sv_entnum = ReadShort();
18                 if (ReadByte()) make_pure(this);
19                 this.origin_x = ReadCoord();
20                 this.origin_y = ReadCoord();
21                 this.origin_z = ReadCoord();
22                 setorigin(this, this.origin);
23                 this.debug = true;  // identify server entities by this
24                 this.classname = strzone(ReadString());
25                 this.sourceLoc = strzone(ReadString());
26                 return true;
27         }
28 #endif
29
30 #ifdef SVQC
31         bool debug_send(entity this, entity to, int sf)
32         {
33                 int channel = MSG_ONE;
34                 msg_entity = to;
35                 WriteHeader(channel, net_debug);
36                 WriteShort(channel, etof(this));
37                 WriteByte(channel, is_pure(this));
38                 vector o = this.origin;
39                 if (o == '0 0 0') // brushes
40                         o = (this.absmin + this.absmax) / 2;
41                 if (this.tag_entity)
42                         o += this.tag_entity.origin;
43                 WriteCoord(channel, o.x); WriteCoord(channel, o.y); WriteCoord(channel, o.z);
44                 WriteString(channel, this.classname);
45                 WriteString(channel, this.sourceLoc);
46                 return true;
47         }
48 #endif
49
50 #if ENABLE_DEBUGDRAW
51 #ifdef GAMEQC
52 /**
53  * 0: off
54  * 1: on
55  * 2: on (pure)
56  * 3: on (.entnum != 0)
57  * 4: on (.origin == '0 0 0')
58  * 5: on (.debug != 0), server only
59  * 6: on (.solid != 0)
60  */
61 bool autocvar_debugdraw;
62 #endif
63
64 #ifdef CSQC
65         string autocvar_debugdraw_filter, autocvar_debugdraw_filterout;
66         .int debugdraw_last;
67         vector project_3d_to_2d(vector vec);
68         void Debug_Draw()
69         {
70                 if (!autocvar_debugdraw) return;
71                 static int debugdraw_frame;
72                 ++debugdraw_frame;
73                 const int sz = 8;
74                 FOREACH_ENTITY(true, {
75                         if (it.debugdraw_last == debugdraw_frame) continue;
76                         int ofs = 0;
77                         FOREACH_ENTITY_RADIUS(it.origin, 100, it.debugdraw_last != debugdraw_frame, {
78                                 it.debugdraw_last = debugdraw_frame;
79                                 vector rgb = (it.debug) ? '0 0 1' : '1 0 0';
80                                 if (autocvar_debugdraw_filterout != "" && strhasword(autocvar_debugdraw_filterout, it.classname)) continue;
81                                 if (autocvar_debugdraw_filter != "" && !strhasword(autocvar_debugdraw_filter, it.classname)) continue;
82                                 if (autocvar_debugdraw == 3)
83                                 {
84                                         if (!it.entnum) continue;
85                                 }
86                                 if (autocvar_debugdraw == 4)
87                                 {
88                                         if (it.origin) continue;
89                                 }
90                                 if (autocvar_debugdraw == 5)
91                                 {
92                                         if (!it.debug) continue;
93                                 }
94                                 else if (autocvar_debugdraw > 5)
95                                 {
96                                         bool flag = true;
97                                         do {
98 //                                              if (it.modelindex) break;
99 //                                              if (it.absmin) break;
100 //                                              if (it.absmax) break;
101 //                                              if (it.entnum) break;
102 //                                              if (it.drawmask) break;
103 //                                              if (it.predraw) break;
104 //                                              if (it.move_movetype) break;
105                                                 if (it.solid) break;
106 //                                              if (it.origin) break;
107 //                                              if (it.oldorigin) break;
108 //                                              if (it.velocity) break;
109 //                                              if (it.angles) break;
110 //                                              if (it.avelocity) break;
111 //                                              if (it.classname) break;
112 //                                              if (it.model) break;
113 //                                              if (it.frame) break;
114 //                                              if (it.skin) break;
115 //                                              if (it.effects) break;
116 //                                              if (it.mins) break;
117 //                                              if (it.maxs) break;
118 //                                              if (it.size) break;
119 //                                              if (it.touch) break;
120 //                                              if (it.use) break;
121 //                                              if (it.think) break;
122 //                                              if (it.blocked) break;
123 //                                              if (it.nextthink) break;
124 //                                              if (it.chain) break;
125 //                                              if (it.netname) break;
126 //                                              if (it.enemy) break;
127 //                                              if (it.flags) break;
128 //                                              if (it.colormap) break;
129 //                                              if (it.owner) break;
130                                                 flag = false;
131                                         } while (0);
132                                         if (!flag) continue;
133                                 }
134                                 else if (is_pure(it))
135                                 {
136                                         if (autocvar_debugdraw < 2) continue;
137                                         rgb.y = 1;
138                                 }
139                                 vector o = it.origin;
140                                 if (it.tag_entity)
141                                         o += it.tag_entity.origin;
142                                 vector pos = project_3d_to_2d(o);
143                                 if (pos.z < 0) continue;
144                                 pos.z = 0;
145                                 pos.y += ofs * sz;
146                                 drawcolorcodedstring2_builtin(pos,
147                                         sprintf("%d: '%s'@%s", (it.debug ? it.sv_entnum : etof(it)),
148                                         it.classname, it.sourceLoc),
149                                         sz * '1 1 0', rgb, 0.5, DRAWFLAG_NORMAL);
150                                 ++ofs;
151             });
152                 });
153         }
154 #endif
155
156 #ifdef SVQC
157         COMMON_COMMAND(debugdraw_sv, "Dump all server entities")
158         {
159                 switch (request)
160                 {
161                         case CMD_REQUEST_COMMAND:
162                         {
163                                 if (!autocvar_debugdraw) return;
164                                 int n = 1000;
165                                 int rem = n;
166                                 for (entity e = NULL; (e = findfloat(e, debug, 0)) && rem > 0; )
167                                 {
168                                         if (autocvar_debugdraw < 2 && is_pure(e)) continue;
169                                         debug_send(e, caller, 0);
170                                         e.debug = true;
171                                         --rem;
172                                 }
173                                 LOG_INFOF("%d server entities sent\n", n - rem);
174                                 return;
175                         }
176
177                         default:
178                         case CMD_REQUEST_USAGE:
179                         {
180                                 LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " debugdraw_sv"));
181                                 return;
182                         }
183                 }
184         }
185 #endif
186 #endif
187
188 GENERIC_COMMAND(bufstr_get, "Examine a string buffer object")
189 {
190         switch (request)
191         {
192                 case CMD_REQUEST_COMMAND:
193                 {
194                         int bufhandle = stof(argv(1));
195                         int string_index = stof(argv(2));
196                         string s = bufstr_get(bufhandle, string_index);
197                         LOG_INFOF("%s\n", s);
198                         return;
199                 }
200
201                 default:
202                 case CMD_REQUEST_USAGE:
203                 {
204                         LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " bufstr_get bufhandle string_index"));
205                         return;
206                 }
207         }
208 }
209
210 GENERIC_COMMAND(version, "Print the current version")
211 {
212         switch (request)
213         {
214                 case CMD_REQUEST_COMMAND:
215                 {
216                         LOG_INFO(WATERMARK "\n");
217                         return;
218                 }
219                 default:
220                 case CMD_REQUEST_USAGE:
221                 {
222                         LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " version"));
223                         return;
224                 }
225         }
226 }
227
228 #ifdef CSQC
229 void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
230 #endif
231 GENERIC_COMMAND(cvar_localchanges, "Print locally changed cvars")
232 {
233         switch (request)
234         {
235                 case CMD_REQUEST_COMMAND:
236                 {
237                         string s = "";
238                         int h = buf_create();
239                         buf_cvarlist(h, "", "_"); // exclude all _ cvars as they are temporary
240                         int n = buf_getsize(h);
241                         for (int i = 0; i < n; ++i) {
242                                 string k = bufstr_get(h, i);
243                                 string v = cvar_string(k);
244                                 string d = cvar_defstring(k);
245                                 if (v == d)
246                                         continue;
247                                 s = strcat(s, k, " \"", v, "\" // \"", d, "\"\n");
248                         }
249                         buf_del(h);
250                         LOG_INFO(s);
251                         return;
252                 }
253                 default:
254                 case CMD_REQUEST_USAGE:
255                 {
256                         LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " cvar_localchanges"));
257                         return;
258                 }
259         }
260 }
261
262 #if ENABLE_DEBUGTRACE
263 REGISTER_STAT(TRACE_ENT, int)
264 #ifdef SVQC
265 bool autocvar_debugtrace;
266
267 REGISTER_MUTATOR(trace, autocvar_debugtrace);
268
269 .bool debug_trace_button;
270 .int solid_prev;
271 MUTATOR_HOOKFUNCTION(trace, SV_StartFrame)
272 {
273         FOREACH_CLIENT(true, {
274                 bool skip = false;
275                 bool btn = PHYS_INPUT_BUTTON_HOOK(it);
276                 if (btn == it.debug_trace_button) skip = true;
277                 it.debug_trace_button = btn;
278                 if (!btn || skip) continue;
279                 FOREACH_ENTITY(true, {
280                     it.solid_prev = it.solid;
281                         it.solid = SOLID_BBOX;
282                 });
283                 vector forward = '0 0 0'; vector right = '0 0 0'; vector up = '0 0 0';
284                 MAKEVECTORS(makevectors, it.v_angle, forward, right, up);
285                 vector pos = it.origin + it.view_ofs;
286                 traceline(pos, pos + forward * max_shot_distance, MOVE_NORMAL, it);
287                 FOREACH_ENTITY(true, {
288                     it.solid = it.solid_prev;
289             it.solid_prev = 0;
290                 });
291                 entity e = trace_ent;
292                 int i = etof(e);
293                 STAT(TRACE_ENT, it) = i;
294                 if (!e) continue;
295                 setorigin(e, e.origin + '0 0 100');
296                 stuffcmd(it, sprintf("prvm_edict server %d\n", i));
297         });
298 }
299 #endif
300 #ifdef CSQC
301 entity TRACE_ENT;
302 void Trace_draw2d(entity this)
303 {
304         int e = STAT(TRACE_ENT);
305         if (!e) return;
306         vector pos = '0 0 0';
307         pos.y += vid_conheight / 2;
308         drawstring(pos, sprintf("prvm_edict server %d", e), '10 10 0', '1 1 1', 1, DRAWFLAG_NORMAL);
309 }
310
311 STATIC_INIT(TRACE_ENT)
312 {
313         entity e = TRACE_ENT = new_pure(TRACE_ENT);
314         e.draw2d = Trace_draw2d;
315         IL_PUSH(g_drawables_2d, e);
316 }
317 #endif
318 #endif
319
320 GENERIC_COMMAND(find, "Search through entities for matching classname")
321 {
322         switch (request)
323         {
324                 case CMD_REQUEST_COMMAND:
325                 {
326                         int entcnt = 0;
327                         FOREACH_ENTITY_CLASS_ORDERED(argv(1), true,
328                         {
329                                 LOG_INFOF("%i (%s)\n", it, it.classname);
330                                 ++entcnt;
331                         });
332                         if(entcnt)
333                                 LOG_INFOF("Found %d entities\n", entcnt);
334                         return;
335                 }
336
337                 default:
338                 {
339                         LOG_INFO("Incorrect parameters for ^2find^7\n");
340         }
341                 case CMD_REQUEST_USAGE:
342                 {
343                         LOG_INFO("\nUsage:^3 " GetProgramCommandPrefix() " find classname\n");
344                         LOG_INFO("  Where 'classname' is the classname to search for.\n");
345                         return;
346                 }
347         }
348 }
349
350 GENERIC_COMMAND(findat, "Search through entities for matching origin")
351 {
352         switch (request)
353         {
354                 case CMD_REQUEST_COMMAND:
355                 {
356                     vector match = stov(argv(1));
357                     FOREACH_ENTITY_ORDERED(it.origin == match, LOG_INFOF("%i (%s)\n", it, it.classname));
358                         return;
359                 }
360
361                 default:
362                         LOG_INFO("Incorrect parameters for ^2findat^7\n");
363                 case CMD_REQUEST_USAGE:
364                 {
365                         LOG_INFO("\nUsage:^3 " GetProgramCommandPrefix() " findat \"0 0 0\"\n");
366                         return;
367                 }
368         }
369 }