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