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