1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #include "LuaUnsyncedRead.h"
4 
5 #include "LuaInclude.h"
6 #include "LuaHandle.h"
7 #include "LuaHashString.h"
8 #include "LuaUtils.h"
9 #include "Game/Camera.h"
10 #include "Game/CameraHandler.h"
11 #include "Game/Game.h"
12 #include "Game/GameHelper.h"
13 #include "Game/GameSetup.h"
14 #include "Game/GlobalUnsynced.h"
15 #include "Game/Players/Player.h"
16 #include "Game/Players/PlayerHandler.h"
17 #include "Net/GameServer.h"
18 #include "Game/GUI/PlayerRoster.h"
19 #include "Game/SelectedUnitsHandler.h"
20 #include "Game/TraceRay.h"
21 #include "Game/Camera/CameraController.h"
22 #include "Game/UI/GuiHandler.h"
23 #include "Game/UI/InfoConsole.h"
24 #include "Game/UI/KeyCodes.h"
25 #include "Game/UI/KeySet.h"
26 #include "Game/UI/KeyBindings.h"
27 #include "Game/UI/MiniMap.h"
28 #include "Game/UI/MouseHandler.h"
29 #include "Map/BaseGroundDrawer.h"
30 #include "Map/BaseGroundTextures.h"
31 #include "Map/Ground.h"
32 #include "Map/ReadMap.h"
33 #include "Rendering/GlobalRendering.h"
34 #include "Rendering/IconHandler.h"
35 #include "Rendering/ShadowHandler.h"
36 #include "Rendering/UnitDrawer.h"
37 #include "Rendering/Env/IWater.h"
38 #include "Sim/Features/Feature.h"
39 #include "Sim/Features/FeatureDef.h"
40 #include "Sim/Features/FeatureHandler.h"
41 #include "Sim/Misc/TeamHandler.h"
42 #include "Sim/Misc/QuadField.h"
43 #include "Sim/Projectiles/Projectile.h"
44 #include "Sim/Units/Unit.h"
45 #include "Sim/Units/UnitHandler.h"
46 #include "Sim/Units/UnitTypes/TransportUnit.h"
47 #include "Sim/Units/Groups/Group.h"
48 #include "Sim/Units/Groups/GroupHandler.h"
49 #include "Net/Protocol/NetProtocol.h"
50 #include "System/Config/ConfigVariable.h"
51 #include "System/Input/KeyInput.h"
52 #include "System/FileSystem/FileHandler.h"
53 #include "System/FileSystem/VFSHandler.h"
54 #include "System/FileSystem/FileSystem.h"
55 #include "System/LoadSave/demofile.h"
56 #include "System/LoadSave/DemoReader.h"
57 #include "System/Log/DefaultFilter.h"
58 #include "System/Platform/SDL1_keysym.h"
59 #include "System/Sound/ISoundChannels.h"
60 #include "System/Misc/SpringTime.h"
61 
62 #if !defined(HEADLESS) && !defined(NO_SOUND)
63 	#include "System/Sound/OpenAL/EFX.h"
64 	#include "System/Sound/OpenAL/EFXPresets.h"
65 #endif
66 
67 #include <set>
68 #include <list>
69 #include <cctype>
70 
71 #include <SDL_clipboard.h>
72 #include <SDL_keycode.h>
73 #include <SDL_mouse.h>
74 
75 const int CMD_INDEX_OFFSET = 1; // starting index for command descriptions
76 
77 /******************************************************************************/
78 /******************************************************************************/
79 
PushEntries(lua_State * L)80 bool LuaUnsyncedRead::PushEntries(lua_State* L)
81 {
82 #define REGISTER_LUA_CFUNC(x) \
83 	lua_pushstring(L, #x);      \
84 	lua_pushcfunction(L, x);    \
85 	lua_rawset(L, -3)
86 
87 #define REGISTER_NAMED_LUA_CFUNC(x,name) \
88 	lua_pushstring(L, #name);      \
89 	lua_pushcfunction(L, x);    \
90 	lua_rawset(L, -3)
91 
92 	REGISTER_LUA_CFUNC(IsReplay);
93 	REGISTER_LUA_CFUNC(GetReplayLength);
94 	REGISTER_LUA_CFUNC(GetModUICtrl);
95 
96 	REGISTER_LUA_CFUNC(GetDrawFrame);
97 	REGISTER_LUA_CFUNC(GetFrameTimeOffset);
98 	REGISTER_LUA_CFUNC(GetLastUpdateSeconds);
99 	REGISTER_LUA_CFUNC(GetHasLag);
100 
101 	REGISTER_LUA_CFUNC(GetViewGeometry);
102 	REGISTER_LUA_CFUNC(GetWindowGeometry);
103 	REGISTER_LUA_CFUNC(GetScreenGeometry);
104 	REGISTER_LUA_CFUNC(GetMiniMapGeometry);
105 	REGISTER_LUA_CFUNC(GetMiniMapDualScreen);
106 	REGISTER_LUA_CFUNC(IsAboveMiniMap);
107 	REGISTER_LUA_CFUNC(IsGUIHidden);
108 
109 	REGISTER_LUA_CFUNC(IsAABBInView);
110 	REGISTER_LUA_CFUNC(IsSphereInView);
111 
112 	REGISTER_LUA_CFUNC(IsUnitAllied);
113 	REGISTER_LUA_CFUNC(IsUnitInView);
114 	REGISTER_LUA_CFUNC(IsUnitVisible);
115 	REGISTER_LUA_CFUNC(IsUnitIcon);
116 	REGISTER_LUA_CFUNC(IsUnitSelected);
117 
118 	REGISTER_LUA_CFUNC(GetUnitLuaDraw);
119 	REGISTER_LUA_CFUNC(GetUnitNoDraw);
120 	REGISTER_LUA_CFUNC(GetUnitNoMinimap);
121 	REGISTER_LUA_CFUNC(GetUnitNoSelect);
122 	REGISTER_LUA_CFUNC(GetFeatureLuaDraw);
123 
124 	REGISTER_LUA_CFUNC(GetUnitTransformMatrix);
125 	REGISTER_LUA_CFUNC(GetUnitViewPosition);
126 
127 	REGISTER_LUA_CFUNC(GetVisibleUnits);
128 	REGISTER_LUA_CFUNC(GetVisibleFeatures);
129 	REGISTER_LUA_CFUNC(GetVisibleProjectiles);
130 
131 	REGISTER_LUA_CFUNC(GetTeamColor);
132 	REGISTER_LUA_CFUNC(GetTeamOrigColor);
133 
134 	REGISTER_LUA_CFUNC(GetLocalPlayerID);
135 	REGISTER_LUA_CFUNC(GetLocalTeamID);
136 	REGISTER_LUA_CFUNC(GetLocalAllyTeamID);
137 
138 	REGISTER_NAMED_LUA_CFUNC(GetLocalPlayerID,   GetMyPlayerID);
139 	REGISTER_NAMED_LUA_CFUNC(GetLocalTeamID,     GetMyTeamID);
140 	REGISTER_NAMED_LUA_CFUNC(GetLocalAllyTeamID, GetMyAllyTeamID);
141 
142 	REGISTER_LUA_CFUNC(GetSpectatingState);
143 
144 	REGISTER_LUA_CFUNC(GetSelectedUnits);
145 	REGISTER_LUA_CFUNC(GetSelectedUnitsSorted);
146 	REGISTER_LUA_CFUNC(GetSelectedUnitsCounts);
147 	REGISTER_LUA_CFUNC(GetSelectedUnitsCount);
148 
149 	REGISTER_LUA_CFUNC(HaveShadows);
150 	REGISTER_LUA_CFUNC(HaveAdvShading);
151 	REGISTER_LUA_CFUNC(GetWaterMode);
152 	REGISTER_LUA_CFUNC(GetMapDrawMode);
153 	REGISTER_LUA_CFUNC(GetMapSquareTexture);
154 
155 	REGISTER_LUA_CFUNC(GetCameraNames);
156 	REGISTER_LUA_CFUNC(GetCameraState);
157 	REGISTER_LUA_CFUNC(GetCameraPosition);
158 	REGISTER_LUA_CFUNC(GetCameraDirection);
159 	REGISTER_LUA_CFUNC(GetCameraFOV);
160 	REGISTER_LUA_CFUNC(GetCameraVectors);
161 	REGISTER_LUA_CFUNC(WorldToScreenCoords);
162 	REGISTER_LUA_CFUNC(TraceScreenRay);
163 	REGISTER_LUA_CFUNC(GetPixelDir);
164 
165 	REGISTER_LUA_CFUNC(GetTimer);
166 	REGISTER_LUA_CFUNC(DiffTimers);
167 
168 	REGISTER_LUA_CFUNC(GetSoundStreamTime);
169 	REGISTER_LUA_CFUNC(GetSoundEffectParams);
170 
171 	REGISTER_LUA_CFUNC(GetFPS);
172 	REGISTER_LUA_CFUNC(GetGameSpeed);
173 
174 	REGISTER_LUA_CFUNC(GetActiveCommand);
175 	REGISTER_LUA_CFUNC(GetDefaultCommand);
176 	REGISTER_LUA_CFUNC(GetActiveCmdDescs);
177 	REGISTER_LUA_CFUNC(GetActiveCmdDesc);
178 	REGISTER_LUA_CFUNC(GetCmdDescIndex);
179 	REGISTER_LUA_CFUNC(GetBuildFacing);
180 	REGISTER_LUA_CFUNC(GetBuildSpacing);
181 	REGISTER_LUA_CFUNC(GetGatherMode);
182 	REGISTER_LUA_CFUNC(GetActivePage);
183 
184 	REGISTER_LUA_CFUNC(GetMouseState);
185 	REGISTER_LUA_CFUNC(GetMouseCursor);
186 	REGISTER_LUA_CFUNC(GetMouseStartPosition);
187 
188 	REGISTER_LUA_CFUNC(GetKeyState);
189 	REGISTER_LUA_CFUNC(GetModKeyState);
190 	REGISTER_LUA_CFUNC(GetPressedKeys);
191 	REGISTER_LUA_CFUNC(GetInvertQueueKey);
192 
193 	REGISTER_LUA_CFUNC(GetClipboard);
194 
195 	REGISTER_LUA_CFUNC(GetKeyCode);
196 	REGISTER_LUA_CFUNC(GetKeySymbol);
197 	REGISTER_LUA_CFUNC(GetKeyBindings);
198 	REGISTER_LUA_CFUNC(GetActionHotKeys);
199 
200 	REGISTER_LUA_CFUNC(GetLastMessagePositions);
201 	REGISTER_LUA_CFUNC(GetConsoleBuffer);
202 	REGISTER_LUA_CFUNC(GetCurrentTooltip);
203 
204 	REGISTER_LUA_CFUNC(GetUnitGroup);
205 	REGISTER_LUA_CFUNC(GetGroupList);
206 	REGISTER_LUA_CFUNC(GetSelectedGroup);
207 	REGISTER_LUA_CFUNC(GetGroupUnits);
208 	REGISTER_LUA_CFUNC(GetGroupUnitsSorted);
209 	REGISTER_LUA_CFUNC(GetGroupUnitsCounts);
210 	REGISTER_LUA_CFUNC(GetGroupUnitsCount);
211 
212 	REGISTER_LUA_CFUNC(GetPlayerRoster);
213 	REGISTER_LUA_CFUNC(GetPlayerTraffic);
214 	REGISTER_LUA_CFUNC(GetPlayerStatistics);
215 
216 	REGISTER_LUA_CFUNC(GetDrawSelectionInfo);
217 
218 	REGISTER_LUA_CFUNC(GetConfigParams);
219 	REGISTER_LUA_CFUNC(GetLogSections);
220 
221 	return true;
222 }
223 
224 
225 /******************************************************************************/
226 /******************************************************************************/
227 //
228 //  Parsing helpers
229 //
230 
ParseUnit(lua_State * L,const char * caller,int index)231 static inline CUnit* ParseUnit(lua_State* L, const char* caller, int index)
232 {
233 	if (!lua_isnumber(L, index)) {
234 		luaL_error(L, "%s(): Bad unitID", caller);
235 		return NULL;
236 	}
237 	const int unitID = lua_toint(L, index);
238 	if ((unitID < 0) || (static_cast<size_t>(unitID) >= unitHandler->MaxUnits())) {
239 		luaL_error(L, "%s(): Bad unitID: %d\n", caller, unitID);
240 	}
241 	CUnit* unit = unitHandler->units[unitID];
242 	if (unit == NULL) {
243 		return NULL;
244 	}
245 	const int readAllyTeam = CLuaHandle::GetHandleReadAllyTeam(L);
246 	if (readAllyTeam < 0) {
247 		return CLuaHandle::GetHandleFullRead(L) ? unit : NULL;
248 	}
249 	if ((unit->losStatus[readAllyTeam] & (LOS_INLOS | LOS_INRADAR)) == 0) {
250 		return NULL;
251 	}
252 	return unit;
253 }
254 
ParseFeature(lua_State * L,const char * caller,int index)255 static inline CFeature* ParseFeature(lua_State* L, const char* caller, int index)
256 {
257 	if (!lua_isnumber(L, index)) {
258 		luaL_error(L, "%s(): Bad featureID", caller);
259 		return NULL;
260 	}
261 	const int featureID = lua_toint(L, index);
262 	CFeature* feature = featureHandler->GetFeature(featureID);
263 
264 	if (CLuaHandle::GetHandleFullRead(L)) { return feature; }
265 
266 	const int readAllyTeam = CLuaHandle::GetHandleReadAllyTeam(L);
267 	if (readAllyTeam < 0) { return NULL; }
268 	if (feature == NULL) { return NULL; }
269 	if (feature->IsInLosForAllyTeam(readAllyTeam)) { return feature; }
270 
271 	return NULL;
272 }
273 
274 
275 
276 /******************************************************************************/
277 /******************************************************************************/
278 //
279 //  The call-outs
280 //
281 
IsReplay(lua_State * L)282 int LuaUnsyncedRead::IsReplay(lua_State* L)
283 {
284 	if (gameSetup && gameSetup->hostDemo) {
285 		lua_pushboolean(L, true);
286 	} else {
287 		lua_pushboolean(L, false);
288 	}
289 	return 1;
290 }
291 
292 
GetReplayLength(lua_State * L)293 int LuaUnsyncedRead::GetReplayLength(lua_State* L)
294 {
295 	if (gameServer && gameServer->GetDemoReader()) {
296 		lua_pushnumber(L, gameServer->GetDemoReader()->GetFileHeader().gameTime);
297 		return 1;
298 	}
299 	return 0;
300 }
301 
302 
GetModUICtrl(lua_State * L)303 int LuaUnsyncedRead::GetModUICtrl(lua_State* L)
304 {
305 	lua_pushboolean(L, CLuaHandle::GetModUICtrl());
306 	return 1;
307 }
308 
309 
310 /******************************************************************************/
311 
GetViewGeometry(lua_State * L)312 int LuaUnsyncedRead::GetViewGeometry(lua_State* L)
313 {
314 	lua_pushnumber(L, globalRendering->viewSizeX);
315 	lua_pushnumber(L, globalRendering->viewSizeY);
316 	lua_pushnumber(L, globalRendering->viewPosX);
317 	lua_pushnumber(L, globalRendering->viewPosY);
318 	return 4;
319 }
320 
321 
GetWindowGeometry(lua_State * L)322 int LuaUnsyncedRead::GetWindowGeometry(lua_State* L)
323 {
324 	// origin BOTTOMLEFT
325 	const int winPosY_bl = globalRendering->screenSizeY - globalRendering->winSizeY - globalRendering->winPosY;
326 
327 	lua_pushnumber(L, globalRendering->winSizeX);
328 	lua_pushnumber(L, globalRendering->winSizeY);
329 	lua_pushnumber(L, globalRendering->winPosX);
330 	lua_pushnumber(L, winPosY_bl);
331 	return 4;
332 }
333 
334 
GetScreenGeometry(lua_State * L)335 int LuaUnsyncedRead::GetScreenGeometry(lua_State* L)
336 {
337 	lua_pushnumber(L, globalRendering->screenSizeX);
338 	lua_pushnumber(L, globalRendering->screenSizeY);
339 	lua_pushnumber(L, 0.0f);
340 	lua_pushnumber(L, 0.0f);
341 	return 4;
342 }
343 
344 
GetMiniMapGeometry(lua_State * L)345 int LuaUnsyncedRead::GetMiniMapGeometry(lua_State* L)
346 {
347 	if (minimap == NULL) {
348 		return 0;
349 	}
350 	lua_pushnumber(L, minimap->GetPosX());
351 	lua_pushnumber(L, minimap->GetPosY());
352 	lua_pushnumber(L, minimap->GetSizeX());
353 	lua_pushnumber(L, minimap->GetSizeY());
354 	lua_pushboolean(L, minimap->GetMinimized());
355 	lua_pushboolean(L, minimap->GetMaximized());
356 
357 	return 6;
358 }
359 
360 
GetMiniMapDualScreen(lua_State * L)361 int LuaUnsyncedRead::GetMiniMapDualScreen(lua_State* L)
362 {
363 	if (minimap == NULL) {
364 		return 0;
365 	}
366 	if (!globalRendering->dualScreenMode) {
367 		lua_pushboolean(L, false);
368 	} else {
369 		if (globalRendering->dualScreenMiniMapOnLeft) {
370 			lua_pushliteral(L, "left");
371 		} else {
372 			lua_pushliteral(L, "right");
373 		}
374 	}
375 	return 1;
376 }
377 
378 
IsAboveMiniMap(lua_State * L)379 int LuaUnsyncedRead::IsAboveMiniMap(lua_State* L)
380 {
381 	if (minimap == NULL) {
382 		return 0;
383 	}
384 
385 	if (minimap->GetMinimized() || game->hideInterface) {
386 		return false;
387 	}
388 
389 	const int x = luaL_checkint(L, 1) + globalRendering->viewPosX;
390 	const int y = luaL_checkint(L, 2);
391 
392 	const int x0 = minimap->GetPosX();
393 	const int y0 = minimap->GetPosY();
394 	const int x1 = x0 + minimap->GetSizeX();
395 	const int y1 = y0 + minimap->GetSizeY();
396 
397 	lua_pushboolean(L, (x >= x0) && (x < x1) &&
398 	                   (y >= y0) && (y < y1));
399 
400 	return 1;
401 }
402 
403 
404 /******************************************************************************/
405 
GetDrawFrame(lua_State * L)406 int LuaUnsyncedRead::GetDrawFrame(lua_State* L)
407 {
408 	lua_pushnumber(L, globalRendering->drawFrame & 0xFFFF);
409 	lua_pushnumber(L, (globalRendering->drawFrame >> 16) & 0xFFFF);
410 	return 2;
411 }
412 
413 
GetFrameTimeOffset(lua_State * L)414 int LuaUnsyncedRead::GetFrameTimeOffset(lua_State* L)
415 {
416 	lua_pushnumber(L, globalRendering->timeOffset);
417 	return 1;
418 }
419 
420 
GetLastUpdateSeconds(lua_State * L)421 int LuaUnsyncedRead::GetLastUpdateSeconds(lua_State* L)
422 {
423 	lua_pushnumber(L, game->updateDeltaSeconds);
424 	return 1;
425 }
426 
GetHasLag(lua_State * L)427 int LuaUnsyncedRead::GetHasLag(lua_State* L)
428 {
429 	lua_pushboolean(L, (game != NULL)? game->IsLagging(luaL_optfloat(L, 1, 500.0f)) : false);
430 	return 1;
431 }
432 
IsAABBInView(lua_State * L)433 int LuaUnsyncedRead::IsAABBInView(lua_State* L)
434 {
435 	float3 mins = float3(luaL_checkfloat(L, 1),
436 	                     luaL_checkfloat(L, 2),
437 	                     luaL_checkfloat(L, 3));
438 	float3 maxs = float3(luaL_checkfloat(L, 4),
439 	                     luaL_checkfloat(L, 5),
440 	                     luaL_checkfloat(L, 6));
441 	lua_pushboolean(L, camera->InView(mins, maxs));
442 	return 1;
443 }
444 
445 
IsSphereInView(lua_State * L)446 int LuaUnsyncedRead::IsSphereInView(lua_State* L)
447 {
448 	const float3 pos(luaL_checkfloat(L, 1),
449 	                 luaL_checkfloat(L, 2),
450 	                 luaL_checkfloat(L, 3));
451 	const float radius = lua_israwnumber(L, 4) ? lua_tofloat(L, 4) : 0.0f;
452 
453 	lua_pushboolean(L, camera->InView(pos, radius));
454 	return 1;
455 }
456 
457 
IsUnitAllied(lua_State * L)458 int LuaUnsyncedRead::IsUnitAllied(lua_State* L)
459 {
460 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
461 	if (unit == NULL) {
462 		return 0;
463 	}
464 	if (CLuaHandle::GetHandleReadAllyTeam(L) < 0) {
465 		lua_pushboolean(L, CLuaHandle::GetHandleFullRead(L));
466 	} else {
467 		lua_pushboolean(L, (unit->allyteam == CLuaHandle::GetHandleReadAllyTeam(L)));
468 	}
469 	return 1;
470 }
471 
472 
IsUnitInView(lua_State * L)473 int LuaUnsyncedRead::IsUnitInView(lua_State* L)
474 {
475 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
476 	if (unit == NULL) {
477 		return 0;
478 	}
479 	lua_pushboolean(L, camera->InView(unit->midPos, unit->radius));
480 	return 1;
481 }
482 
483 
UnitIsIcon(const CUnit * unit)484 static bool UnitIsIcon(const CUnit* unit)
485 {
486 	return (unitDrawer->DrawAsIcon(unit, (unit->pos - camera->GetPos()).SqLength()));
487 }
488 
489 
IsUnitVisible(lua_State * L)490 int LuaUnsyncedRead::IsUnitVisible(lua_State* L)
491 {
492 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
493 	if (unit == NULL) {
494 		return 0;
495 	}
496 	const float radius = luaL_optnumber(L, 2, unit->radius);
497 	const bool checkIcon = lua_toboolean(L, 3);
498 
499 	const int readAllyTeam = CLuaHandle::GetHandleReadAllyTeam(L);
500 
501 	if (readAllyTeam < 0) {
502 		if (!CLuaHandle::GetHandleFullRead(L)) {
503 			lua_pushboolean(L, false);
504 		} else {
505 			lua_pushboolean(L,
506 				(!checkIcon || !UnitIsIcon(unit)) &&
507 				camera->InView(unit->midPos, radius));
508 		}
509 	}
510 	else {
511 		if ((unit->losStatus[readAllyTeam] & LOS_INLOS) == 0) {
512 			lua_pushboolean(L, false);
513 		} else {
514 			lua_pushboolean(L,
515 				(!checkIcon || !UnitIsIcon(unit)) &&
516 				camera->InView(unit->midPos, radius));
517 		}
518 	}
519 	return 1;
520 }
521 
522 
IsUnitIcon(lua_State * L)523 int LuaUnsyncedRead::IsUnitIcon(lua_State* L)
524 {
525 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
526 	if (unit == NULL) {
527 		return 0;
528 	}
529 	lua_pushboolean(L, UnitIsIcon(unit));
530 	return 1;
531 }
532 
533 
IsUnitSelected(lua_State * L)534 int LuaUnsyncedRead::IsUnitSelected(lua_State* L)
535 {
536 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
537 	if (unit == NULL) {
538 		return 0;
539 	}
540 	const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
541 	lua_pushboolean(L, selUnits.find(unit) != selUnits.end());
542 	return 1;
543 }
544 
545 
GetUnitLuaDraw(lua_State * L)546 int LuaUnsyncedRead::GetUnitLuaDraw(lua_State* L)
547 {
548 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
549 	if (unit == NULL) {
550 		return 0;
551 	}
552 	lua_pushboolean(L, unit->luaDraw);
553 	return 1;
554 }
555 
GetUnitNoDraw(lua_State * L)556 int LuaUnsyncedRead::GetUnitNoDraw(lua_State* L)
557 {
558 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
559 	if (unit == NULL) {
560 		return 0;
561 	}
562 	lua_pushboolean(L, unit->noDraw);
563 	return 1;
564 }
565 
GetUnitNoMinimap(lua_State * L)566 int LuaUnsyncedRead::GetUnitNoMinimap(lua_State* L)
567 {
568 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
569 	if (unit == NULL) {
570 		return 0;
571 	}
572 	lua_pushboolean(L, unit->noMinimap);
573 	return 1;
574 }
575 
GetUnitNoSelect(lua_State * L)576 int LuaUnsyncedRead::GetUnitNoSelect(lua_State* L)
577 {
578 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
579 	if (unit == NULL) {
580 		return 0;
581 	}
582 	lua_pushboolean(L, unit->noSelect);
583 	return 1;
584 }
585 
586 
GetFeatureLuaDraw(lua_State * L)587 int LuaUnsyncedRead::GetFeatureLuaDraw(lua_State* L)
588 {
589 	CFeature* feature = ParseFeature(L, __FUNCTION__, 1);
590 	if (feature == NULL) {
591 		return 0;
592 	}
593 	lua_pushboolean(L, feature->luaDraw);
594 	return 1;
595 }
596 
597 
598 
GetUnitTransformMatrix(lua_State * L)599 int LuaUnsyncedRead::GetUnitTransformMatrix(lua_State* L)
600 {
601 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
602 	if (unit == NULL) {
603 		return 0;
604 	}
605 
606 	CMatrix44f m = unit->GetTransformMatrix(false, false);
607 
608 	if (luaL_optboolean(L, 2, false)) {
609 		m = m.InvertAffine();
610 	}
611 
612 	for (int i = 0; i < 16; i += 4) {
613 		lua_pushnumber(L, m[i    ]);
614 		lua_pushnumber(L, m[i + 1]);
615 		lua_pushnumber(L, m[i + 2]);
616 		lua_pushnumber(L, m[i + 3]);
617 	}
618 
619 	return 16;
620 }
621 
GetUnitViewPosition(lua_State * L)622 int LuaUnsyncedRead::GetUnitViewPosition(lua_State* L)
623 {
624 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
625 	if (unit == NULL) {
626 		return 0;
627 	}
628 	const bool midPos = luaL_optboolean(L, 2, false);
629 
630 	float3& pos = midPos ? unit->drawMidPos : unit->drawPos;
631 	lua_pushnumber(L, pos.x);
632 	lua_pushnumber(L, pos.y);
633 	lua_pushnumber(L, pos.z);
634 	return 3;
635 }
636 
637 
638 /******************************************************************************/
639 /******************************************************************************/
640 
641 // FIXME -- copied from LuaSyncedRead.cpp, commonize
642 enum UnitAllegiance {
643 	AllUnits   = -1,
644 	MyUnits    = -2,
645 	AllyUnits  = -3,
646 	EnemyUnits = -4
647 };
648 
649 
650 // never instantiated directly
651 template<class T> class CWorldObjectQuadDrawer: public CReadMap::IQuadDrawer {
652 public:
653 	typedef std::list<T*> ObjectList;
654 	typedef std::vector< const ObjectList* > ObjectVector;
655 
Reset()656 	void Reset() {
657 		objectLists.clear();
658 		objectLists.reserve(64);
659 
660 		objectCount = 0;
661 	}
662 
GetQuadCount() const663 	unsigned int GetQuadCount() const { return (objectLists.size()); }
GetObjectCount() const664 	unsigned int GetObjectCount() const { return objectCount; }
665 
GetObjectLists()666 	const ObjectVector& GetObjectLists() { return objectLists; }
667 
AddObjectList(const ObjectList * objects)668 	void AddObjectList(const ObjectList* objects) {
669 		if (objects->empty())
670 			return;
671 
672 		objectLists.push_back(objects);
673 		objectCount += objects->size();
674 	}
675 
676 protected:
677 	// note: stores pointers to lists, not copies
678 	// its size equals the number of visible quads
679 	ObjectVector objectLists;
680 
681 	unsigned int objectCount;
682 };
683 
684 
685 class CVisUnitQuadDrawer: public CWorldObjectQuadDrawer<CUnit> {
686 public:
DrawQuad(int x,int y)687 	void DrawQuad(int x, int y) {
688 		const CQuadField::Quad& q = quadField->GetQuadAt(x, y);
689 		const ObjectList* o = &q.units;
690 
691 		AddObjectList(o);
692 	}
693 };
694 
695 class CVisFeatureQuadDrawer: public CWorldObjectQuadDrawer<CFeature> {
696 public:
DrawQuad(int x,int y)697 	void DrawQuad(int x, int y) {
698 		const CQuadField::Quad& q = quadField->GetQuadAt(x, y);
699 		const ObjectList* o = &q.features;
700 
701 		AddObjectList(o);
702 	}
703 };
704 
705 class CVisProjectileQuadDrawer: public CWorldObjectQuadDrawer<CProjectile> {
706 public:
DrawQuad(int x,int y)707 	void DrawQuad(int x, int y) {
708 		const CQuadField::Quad& q = quadField->GetQuadAt(x, y);
709 		const ObjectList* o = &q.projectiles;
710 
711 		AddObjectList(o);
712 	}
713 };
714 
715 
716 
717 
GetVisibleUnits(lua_State * L)718 int LuaUnsyncedRead::GetVisibleUnits(lua_State* L)
719 {
720 	// arg 1 - teamID
721 	int teamID = luaL_optint(L, 1, -1);
722 	int allyTeamID = CLuaHandle::GetHandleReadAllyTeam(L);
723 
724 	if (teamID == MyUnits) {
725 		const int scriptTeamID = CLuaHandle::GetHandleReadTeam(L);
726 
727 		if (scriptTeamID >= 0) {
728 			teamID = scriptTeamID;
729 		} else {
730 			teamID = AllUnits;
731 		}
732 	}
733 
734 	if (teamID >= 0) {
735 		if (!teamHandler->IsValidTeam(teamID))
736 			return 0;
737 
738 		allyTeamID = teamHandler->AllyTeam(teamID);
739 	}
740 	if (allyTeamID < 0) {
741 		if (!CLuaHandle::GetHandleFullRead(L)) {
742 			return 0;
743 		}
744 	}
745 
746 	// arg 2 - unit radius
747 	bool fixedRadius = false;
748 	// arg 3 - noIcons
749 	const bool noIcons = !luaL_optboolean(L, 3, true);
750 
751 	float testRadius = WORLDOBJECT_DEFAULT_DRAWRADIUS;
752 	const float iconLength = unitDrawer->iconLength;
753 
754 	if (lua_israwnumber(L, 2)) {
755 		testRadius = lua_tofloat(L, 2);
756 		fixedRadius = (testRadius < 0.0f);
757 		testRadius = std::max(testRadius, -testRadius);
758 	}
759 
760 	vector<const CUnitSet*> unitSets;
761 	vector<const CUnitSet*>::const_iterator setIt;
762 
763 	static CUnitSet visQuadUnits;
764 	static CVisUnitQuadDrawer unitQuadIter;
765 
766 	unsigned int count = 0;
767 
768 	{
769 		unitQuadIter.Reset();
770 		readMap->GridVisibility(camera, CQuadField::BASE_QUAD_SIZE / SQUARE_SIZE, 1e9, &unitQuadIter, INT_MAX);
771 
772 		lua_createtable(L, unitQuadIter.GetObjectCount(), 0);
773 
774 		// setup the list of unit sets
775 		//
776 		// if we see nearly all features, it is just faster to
777 		// check them all, instead of doing slow duplication checks
778 		//
779 		// FIXME? one-third != "nearly all"
780 		//
781 		if (unitQuadIter.GetObjectCount() > unitHandler->activeUnits.size() / 3) {
782 			if (teamID >= 0) {
783 				unitSets.push_back(&teamHandler->Team(teamID)->units);
784 			} else {
785 				for (int t = 0; t < teamHandler->ActiveTeams(); t++) {
786 					if ((teamID == AllUnits) ||
787 						((teamID == AllyUnits)  && (allyTeamID == teamHandler->AllyTeam(t))) ||
788 						((teamID == EnemyUnits) && (allyTeamID != teamHandler->AllyTeam(t))))
789 					{
790 						unitSets.push_back(&teamHandler->Team(t)->units);
791 					}
792 				}
793 			}
794 		} else {
795 			// objects can exist in multiple quads, so we still need to do a duplication check
796 			visQuadUnits.clear();
797 
798 			const CVisUnitQuadDrawer::ObjectVector& visUnits = unitQuadIter.GetObjectLists();
799 
800 			CVisUnitQuadDrawer::ObjectVector::const_iterator visUnitLists;
801 			CVisUnitQuadDrawer::ObjectList::const_iterator unitIt;
802 
803 			for (visUnitLists = visUnits.begin(); visUnitLists != visUnits.end(); ++visUnitLists) {
804 				for (unitIt = (*visUnitLists)->begin(); unitIt != (*visUnitLists)->end(); ++unitIt) {
805 					CUnit* unit = *unitIt;
806 
807 					if ((teamID == AllUnits) ||
808 						((teamID >= 0) && (teamID == unit->team)) ||
809 						((teamID == AllyUnits)  && (allyTeamID == unit->allyteam)) ||
810 						((teamID == EnemyUnits) && (allyTeamID != unit->allyteam)))
811 					{
812 						visQuadUnits.insert(unit);
813 					}
814 				}
815 			}
816 			unitSets.push_back(&visQuadUnits);
817 		}
818 	}
819 
820 	for (setIt = unitSets.begin(); setIt != unitSets.end(); ++setIt) {
821 		const CUnitSet* unitSet = *setIt;
822 
823 		CUnitSet::const_iterator unitIt;
824 
825 		for (unitIt = unitSet->begin(); unitIt != unitSet->end(); ++unitIt) {
826 			const CUnit* unit = *unitIt;
827 
828 			if (unit->noDraw)
829 				continue;
830 
831 			if (allyTeamID >= 0 && !(unit->losStatus[allyTeamID] & LOS_INLOS))
832 				continue;
833 
834 			if (noIcons) {
835 				const float sqDist = (unit->pos - camera->GetPos()).SqLength();
836 				const float iconDistSqrMult = unit->unitDef->iconType->GetDistanceSqr();
837 				const float realIconLength = iconLength * iconDistSqrMult;
838 
839 				if (sqDist > realIconLength)
840 					continue;
841 			}
842 
843 			if (!camera->InView(unit->midPos, testRadius + (unit->drawRadius * !fixedRadius)))
844 				continue;
845 
846 			// add the unit
847 			count++;
848 			lua_pushnumber(L, unit->id);
849 			lua_rawseti(L, -2, count);
850 		}
851 	}
852 
853 	return 1;
854 }
855 
856 
GetVisibleFeatures(lua_State * L)857 int LuaUnsyncedRead::GetVisibleFeatures(lua_State* L)
858 {
859 	// arg 1 - allyTeamID
860 	int allyTeamID = luaL_optint(L, 1, -1);
861 
862 	if (allyTeamID >= 0) {
863 		if (!teamHandler->ValidAllyTeam(allyTeamID)) {
864 			return 0;
865 		}
866 	} else {
867 		allyTeamID = -1;
868 
869 		if (!CLuaHandle::GetHandleFullRead(L)) {
870 			allyTeamID = CLuaHandle::GetHandleReadAllyTeam(L);
871 		}
872 	}
873 
874 	// arg 2 - feature radius
875 	bool fixedRadius = false;
876 	bool scanAll = false;
877 
878 	float testRadius = WORLDOBJECT_DEFAULT_DRAWRADIUS;
879 
880 	if (lua_israwnumber(L, 2)) {
881 		testRadius = lua_tofloat(L, 2);
882 		fixedRadius = (testRadius < 0.0f);
883 		testRadius = std::max(testRadius, -testRadius);
884 	}
885 
886 	const bool noIcons = !luaL_optboolean(L, 3, true);
887 	const bool noGeos = !luaL_optboolean(L, 4, true);
888 
889 	static CFeatureSet visQuadFeatures;
890 	static CVisFeatureQuadDrawer featureQuadIter;
891 
892 	unsigned int count = 0;
893 
894 	{
895 		featureQuadIter.Reset();
896 		readMap->GridVisibility(camera, CQuadField::BASE_QUAD_SIZE / SQUARE_SIZE, 3000.0f * 2.0f, &featureQuadIter, INT_MAX);
897 
898 		lua_createtable(L, featureQuadIter.GetObjectCount(), 0);
899 
900 		// setup the list of features
901 		//
902 		// if we see nearly all features, it is just faster to
903 		// check them all, instead of doing slow duplication checks
904 		//
905 		// FIXME? one-third != "nearly all"
906 		//
907 		if (!(scanAll = (featureQuadIter.GetObjectCount() > featureHandler->GetActiveFeatures().size() / 3))) {
908 			visQuadFeatures.clear();
909 
910 			const CVisFeatureQuadDrawer::ObjectVector& visFeatures = featureQuadIter.GetObjectLists();
911 
912 			CVisFeatureQuadDrawer::ObjectVector::const_iterator featureListIt;
913 			CVisFeatureQuadDrawer::ObjectList::const_iterator featureIt;
914 
915 			// features can exist in multiple quads, so we need to do a duplication check
916 			for (featureListIt = visFeatures.begin(); featureListIt != visFeatures.end(); ++featureListIt) {
917 				for (featureIt = (*featureListIt)->begin(); featureIt != (*featureListIt)->end(); ++featureIt) {
918 					visQuadFeatures.insert(*featureIt);
919 				}
920 			}
921 		}
922 	}
923 
924 	const CFeatureSet& featureSet = (scanAll) ? featureHandler->GetActiveFeatures() : visQuadFeatures;
925 
926 	for (CFeatureSet::const_iterator featureIt = featureSet.begin(); featureIt != featureSet.end(); ++featureIt) {
927 		const CFeature& f = **featureIt;
928 
929 		if (noGeos && f.def->geoThermal)
930 			continue;
931 
932 		if (noIcons) {
933 			const float sqDist = (f.pos - camera->GetPos()).SqLength2D();
934 			const float farLength = f.sqRadius * unitDrawer->unitDrawDist * unitDrawer->unitDrawDist;
935 
936 			if (sqDist >= farLength) {
937 				continue;
938 			}
939 		}
940 
941 		if (!gu->spectatingFullView && !f.IsInLosForAllyTeam(allyTeamID))
942 			continue;
943 
944 		if (!camera->InView(f.midPos, testRadius + (f.drawRadius * !fixedRadius)))
945 			continue;
946 
947 		// add the unit
948 		count++;
949 		lua_pushnumber(L, f.id);
950 		lua_rawseti(L, -2, count);
951 	}
952 
953 	return 1;
954 }
955 
GetVisibleProjectiles(lua_State * L)956 int LuaUnsyncedRead::GetVisibleProjectiles(lua_State* L)
957 {
958 	int allyTeamID = luaL_optint(L, 1, -1);
959 
960 	if (allyTeamID >= 0) {
961 		if (!teamHandler->ValidAllyTeam(allyTeamID)) {
962 			return 0;
963 		}
964 	} else {
965 		allyTeamID = -1;
966 
967 		if (!CLuaHandle::GetHandleFullRead(L)) {
968 			allyTeamID = CLuaHandle::GetHandleReadAllyTeam(L);
969 		}
970 	}
971 
972 	static CVisProjectileQuadDrawer projQuadIter;
973 
974 	/*const bool addSyncedProjectiles =*/ luaL_optboolean(L, 2, true);
975 	const bool addWeaponProjectiles = luaL_optboolean(L, 3, true);
976 	const bool addPieceProjectiles = luaL_optboolean(L, 4, true);
977 
978 	unsigned int count = 0;
979 
980 	{
981 		projQuadIter.Reset();
982 		readMap->GridVisibility(camera, CQuadField::BASE_QUAD_SIZE / SQUARE_SIZE, 1e9, &projQuadIter, INT_MAX);
983 
984 		lua_createtable(L, projQuadIter.GetObjectCount(), 0);
985 
986 		const CVisProjectileQuadDrawer::ObjectVector& visProjectiles = projQuadIter.GetObjectLists();
987 		const CVisProjectileQuadDrawer::ObjectList* quadProjectiles = NULL;
988 
989 		CVisProjectileQuadDrawer::ObjectList::const_iterator it;
990 
991 		for (unsigned int n = 0; n < visProjectiles.size(); n++) {
992 			quadProjectiles = visProjectiles[n];
993 
994 			for (it = quadProjectiles->begin(); it != quadProjectiles->end(); ++it) {
995 				const CProjectile* pro = *it;
996 
997 				if (allyTeamID >= 0 && !losHandler->InLos(pro, allyTeamID))
998 					continue;
999 
1000 				if (!camera->InView(pro->pos, pro->drawRadius))
1001 					continue;
1002 
1003 				#if 1
1004 				// filter out unsynced projectiles, the SyncedRead
1005 				// projecile Get* functions accept only synced ID's
1006 				// (specifically they interpret all ID's as synced)
1007 				if (!pro->synced)
1008 					continue;
1009 				#else
1010 				if (!addSyncedProjectiles && pro->synced)
1011 					continue;
1012 				#endif
1013 				if (!addWeaponProjectiles && pro->weapon)
1014 					continue;
1015 				if (!addPieceProjectiles && pro->piece)
1016 					continue;
1017 
1018 				count++;
1019 				lua_pushnumber(L, pro->id);
1020 				lua_rawseti(L, -2, count);
1021 			}
1022 		}
1023 	}
1024 
1025 	return 1;
1026 }
1027 
1028 
1029 /******************************************************************************/
1030 /******************************************************************************/
1031 
GetLocalPlayerID(lua_State * L)1032 int LuaUnsyncedRead::GetLocalPlayerID(lua_State* L)
1033 {
1034 	lua_pushnumber(L, gu->myPlayerNum);
1035 	return 1;
1036 }
1037 
1038 
GetLocalTeamID(lua_State * L)1039 int LuaUnsyncedRead::GetLocalTeamID(lua_State* L)
1040 {
1041 	lua_pushnumber(L, gu->myTeam);
1042 	return 1;
1043 }
1044 
1045 
GetLocalAllyTeamID(lua_State * L)1046 int LuaUnsyncedRead::GetLocalAllyTeamID(lua_State* L)
1047 {
1048 	lua_pushnumber(L, gu->myAllyTeam);
1049 	return 1;
1050 }
1051 
1052 
GetSpectatingState(lua_State * L)1053 int LuaUnsyncedRead::GetSpectatingState(lua_State* L)
1054 {
1055 	lua_pushboolean(L, gu->spectating);
1056 	lua_pushboolean(L, gu->spectatingFullView);
1057 	lua_pushboolean(L, gu->spectatingFullSelect);
1058 	return 3;
1059 }
1060 
1061 
1062 /******************************************************************************/
1063 /******************************************************************************/
1064 
GetSelectedUnits(lua_State * L)1065 int LuaUnsyncedRead::GetSelectedUnits(lua_State* L)
1066 {
1067 	unsigned int count = 0;
1068 	const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
1069 
1070 	// { [1] = number unitID, ... }
1071 	lua_createtable(L, selUnits.size(), 0);
1072 
1073 	CUnitSet::const_iterator it;
1074 	for (it = selUnits.begin(); it != selUnits.end(); ++it) {
1075 		lua_pushnumber(L, (*it)->id);
1076 		lua_rawseti(L, -2, ++count);
1077 	}
1078 	return 1;
1079 }
1080 
1081 
GetSelectedUnitsSorted(lua_State * L)1082 int LuaUnsyncedRead::GetSelectedUnitsSorted(lua_State* L)
1083 {
1084 	map<int, vector<CUnit*> > unitDefMap;
1085 	map<int, vector<CUnit*> >::const_iterator mit;
1086 
1087 	const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
1088 	CUnitSet::const_iterator it;
1089 
1090 	for (it = selUnits.begin(); it != selUnits.end(); ++it) {
1091 		CUnit* unit = *it;
1092 		unitDefMap[unit->unitDef->id].push_back(unit);
1093 	}
1094 
1095 	// { [number unitDefID] = { [1] = [number unitID], ...}, ... }
1096 	lua_createtable(L, 0, unitDefMap.size());
1097 
1098 	for (mit = unitDefMap.begin(); mit != unitDefMap.end(); ++mit) {
1099 		const vector<CUnit*>& v = mit->second;
1100 
1101 		// inner array-table
1102 		lua_createtable(L, v.size(), 0);
1103 
1104 		{
1105 			for (unsigned int i = 0; i < v.size(); i++) {
1106 				lua_pushnumber(L, v[i]->id);
1107 				lua_rawseti(L, -2, i + 1);
1108 			}
1109 		}
1110 
1111 		// push the UnitDef index
1112 		lua_rawseti(L, -2, mit->first);
1113 	}
1114 
1115 	// UnitDef ID keys are not necessarily consecutive
1116 	HSTR_PUSH_NUMBER(L, "n", unitDefMap.size());
1117 	return 1;
1118 }
1119 
1120 
GetSelectedUnitsCounts(lua_State * L)1121 int LuaUnsyncedRead::GetSelectedUnitsCounts(lua_State* L)
1122 {
1123 	map<int, int> countMap;
1124 	map<int, int>::const_iterator mit;
1125 
1126 	const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
1127 	CUnitSet::const_iterator it;
1128 
1129 	// tally the types
1130 	for (it = selUnits.begin(); it != selUnits.end(); ++it) {
1131 		CUnit* unit = *it;
1132 		map<int, int>::iterator mit = countMap.find(unit->unitDef->id);
1133 
1134 		if (mit == countMap.end()) {
1135 			countMap[unit->unitDef->id] = 1;
1136 		} else {
1137 			mit->second++;
1138 		}
1139 	}
1140 
1141 	// { [number unitDefID] = number count, ... }
1142 	lua_createtable(L, 0, countMap.size());
1143 
1144 	for (mit = countMap.begin(); mit != countMap.end(); ++mit) {
1145 		lua_pushnumber(L, mit->second); // push the UnitDef unit count (value)
1146 		lua_rawseti(L, -2, mit->first); // push the UnitDef index (key)
1147 	}
1148 
1149 	// UnitDef ID keys are not necessarily consecutive
1150 	HSTR_PUSH_NUMBER(L, "n", countMap.size());
1151 	return 1;
1152 }
1153 
1154 
GetSelectedUnitsCount(lua_State * L)1155 int LuaUnsyncedRead::GetSelectedUnitsCount(lua_State* L)
1156 {
1157 	lua_pushnumber(L, selectedUnitsHandler.selectedUnits.size());
1158 	return 1;
1159 }
1160 
1161 
1162 /******************************************************************************/
1163 /******************************************************************************/
1164 
IsGUIHidden(lua_State * L)1165 int LuaUnsyncedRead::IsGUIHidden(lua_State* L)
1166 {
1167 	if (game == NULL) {
1168 		return 0;
1169 	}
1170 	lua_pushboolean(L, game->hideInterface);
1171 	return 1;
1172 }
1173 
1174 
HaveShadows(lua_State * L)1175 int LuaUnsyncedRead::HaveShadows(lua_State* L)
1176 {
1177 	if (shadowHandler == NULL) {
1178 		return 0;
1179 	}
1180 	lua_pushboolean(L, shadowHandler->shadowsLoaded);
1181 	return 1;
1182 }
1183 
1184 
HaveAdvShading(lua_State * L)1185 int LuaUnsyncedRead::HaveAdvShading(lua_State* L)
1186 {
1187 	if (unitDrawer == NULL) {
1188 		return 0;
1189 	}
1190 	lua_pushboolean(L, unitDrawer->UseAdvShading());
1191 	return 1;
1192 }
1193 
1194 
GetWaterMode(lua_State * L)1195 int LuaUnsyncedRead::GetWaterMode(lua_State* L)
1196 {
1197 	if (water == NULL) {
1198 		return 0;
1199 	}
1200 
1201 	const int mode = water->GetID();
1202 	const char* modeName = water->GetName();
1203 
1204 	lua_pushnumber(L, mode);
1205 	lua_pushstring(L, modeName);
1206 	return 2;
1207 }
1208 
1209 
GetMapDrawMode(lua_State * L)1210 int LuaUnsyncedRead::GetMapDrawMode(lua_State* L)
1211 {
1212 	switch (readMap->GetGroundDrawer()->GetDrawMode()) {
1213 		case CBaseGroundDrawer::drawNormal:   { HSTR_PUSH(L, "normal"            ); break; }
1214 		case CBaseGroundDrawer::drawHeight:   { HSTR_PUSH(L, "height"            ); break; }
1215 		case CBaseGroundDrawer::drawMetal:    { HSTR_PUSH(L, "metal"             ); break; }
1216 		case CBaseGroundDrawer::drawLos:      { HSTR_PUSH(L, "los"               ); break; }
1217 		case CBaseGroundDrawer::drawPathTrav: { HSTR_PUSH(L, "pathTraversability"); break; }
1218 		case CBaseGroundDrawer::drawPathHeat: { HSTR_PUSH(L, "pathHeat"          ); break; }
1219 		case CBaseGroundDrawer::drawPathFlow: { HSTR_PUSH(L, "pathFlow"          ); break; }
1220 		case CBaseGroundDrawer::drawPathCost: { HSTR_PUSH(L, "pathCost"          ); break; }
1221 	}
1222 	return 1;
1223 }
1224 
1225 
GetMapSquareTexture(lua_State * L)1226 int LuaUnsyncedRead::GetMapSquareTexture(lua_State* L)
1227 {
1228 	if (CLuaHandle::GetHandleSynced(L)) {
1229 		return 0;
1230 	}
1231 
1232 	const int texSquareX = luaL_checkint(L, 1);
1233 	const int texSquareY = luaL_checkint(L, 2);
1234 	const int texMipLevel = luaL_checkint(L, 3);
1235 	const std::string& texName = luaL_checkstring(L, 4);
1236 
1237 	CBaseGroundDrawer* groundDrawer = readMap->GetGroundDrawer();
1238 	CBaseGroundTextures* groundTextures = groundDrawer->GetGroundTextures();
1239 
1240 	if (groundTextures == NULL) {
1241 		lua_pushboolean(L, false);
1242 		return 1;
1243 	}
1244 	if (texName.empty()) {
1245 		lua_pushboolean(L, false);
1246 		return 1;
1247 	}
1248 
1249 	const LuaTextures& luaTextures = CLuaHandle::GetActiveTextures(L);
1250 	const LuaTextures::Texture* luaTexture = luaTextures.GetInfo(texName);
1251 
1252 	if (luaTexture == NULL) {
1253 		// not a valid texture (name)
1254 		lua_pushboolean(L, false);
1255 		return 1;
1256 	}
1257 
1258 	const int tid = luaTexture->id;
1259 	const int txs = luaTexture->xsize;
1260 	const int tys = luaTexture->ysize;
1261 
1262 	if (txs != tys) {
1263 		// square textures only
1264 		lua_pushboolean(L, false);
1265 		return 1;
1266 	}
1267 
1268 	lua_pushboolean(L, groundTextures->GetSquareLuaTexture(texSquareX, texSquareY, tid, txs, tys, texMipLevel));
1269 	return 1;
1270 }
1271 
1272 /******************************************************************************/
1273 
GetCameraNames(lua_State * L)1274 int LuaUnsyncedRead::GetCameraNames(lua_State* L)
1275 {
1276 	lua_newtable(L);
1277 	const std::vector<CCameraController*>& cc = camHandler->GetAvailableControllers();
1278 	for (size_t i = 0; i < cc.size(); ++i) {
1279 		lua_pushsstring(L, cc[i]->GetName());
1280 		lua_pushnumber(L, i);
1281 		lua_rawset(L, -3);
1282 	}
1283 
1284 	return 1;
1285 }
1286 
1287 
GetCameraState(lua_State * L)1288 int LuaUnsyncedRead::GetCameraState(lua_State* L)
1289 {
1290 	lua_newtable(L);
1291 
1292 	lua_pushliteral(L, "name");
1293 	lua_pushsstring(L, camHandler->GetCurrentControllerName());
1294 	lua_rawset(L, -3);
1295 
1296 	CCameraController::StateMap camState;
1297 	CCameraController::StateMap::const_iterator it;
1298 	camHandler->GetState(camState);
1299 	for (it = camState.begin(); it != camState.end(); ++it) {
1300 		lua_pushsstring(L, it->first);
1301 		lua_pushnumber(L, it->second);
1302 		lua_rawset(L, -3);
1303 	}
1304 
1305 	return 1;
1306 }
1307 
1308 
GetCameraPosition(lua_State * L)1309 int LuaUnsyncedRead::GetCameraPosition(lua_State* L)
1310 {
1311 	lua_pushnumber(L, camera->GetPos().x);
1312 	lua_pushnumber(L, camera->GetPos().y);
1313 	lua_pushnumber(L, camera->GetPos().z);
1314 	return 3;
1315 }
1316 
1317 
GetCameraDirection(lua_State * L)1318 int LuaUnsyncedRead::GetCameraDirection(lua_State* L)
1319 {
1320 	lua_pushnumber(L, camera->forward.x);
1321 	lua_pushnumber(L, camera->forward.y);
1322 	lua_pushnumber(L, camera->forward.z);
1323 	return 3;
1324 }
1325 
1326 
GetCameraFOV(lua_State * L)1327 int LuaUnsyncedRead::GetCameraFOV(lua_State* L)
1328 {
1329 	lua_pushnumber(L, camera->GetFov());
1330 	return 1;
1331 }
1332 
1333 
GetCameraVectors(lua_State * L)1334 int LuaUnsyncedRead::GetCameraVectors(lua_State* L)
1335 {
1336 #define PACK_CAMERA_VECTOR(n) \
1337 	HSTR_PUSH(L, #n);           \
1338 	lua_createtable(L, 3, 0);            \
1339 	lua_pushnumber(L, camera-> n .x); lua_rawseti(L, -2, 1); \
1340 	lua_pushnumber(L, camera-> n .y); lua_rawseti(L, -2, 2); \
1341 	lua_pushnumber(L, camera-> n .z); lua_rawseti(L, -2, 3); \
1342 	lua_rawset(L, -3)
1343 
1344 	lua_newtable(L);
1345 	PACK_CAMERA_VECTOR(forward);
1346 	PACK_CAMERA_VECTOR(up);
1347 	PACK_CAMERA_VECTOR(right);
1348 	PACK_CAMERA_VECTOR(topFrustumSideDir);
1349 	PACK_CAMERA_VECTOR(botFrustumSideDir);
1350 	PACK_CAMERA_VECTOR(lftFrustumSideDir);
1351 	PACK_CAMERA_VECTOR(rgtFrustumSideDir);
1352 
1353 	return 1;
1354 }
1355 
1356 
WorldToScreenCoords(lua_State * L)1357 int LuaUnsyncedRead::WorldToScreenCoords(lua_State* L)
1358 {
1359 	const float3 worldPos(luaL_checkfloat(L, 1),
1360 	                      luaL_checkfloat(L, 2),
1361 	                      luaL_checkfloat(L, 3));
1362 	const float3 winPos = camera->CalcWindowCoordinates(worldPos);
1363 	lua_pushnumber(L, winPos.x);
1364 	lua_pushnumber(L, winPos.y);
1365 	lua_pushnumber(L, winPos.z);
1366 	return 3;
1367 }
1368 
1369 
TraceScreenRay(lua_State * L)1370 int LuaUnsyncedRead::TraceScreenRay(lua_State* L)
1371 {
1372 	// window coordinates
1373 	const int mx = luaL_checkint(L, 1);
1374 	const int my = luaL_checkint(L, 2);
1375 	const bool onlyCoords  = luaL_optboolean(L, 3, false);
1376 	const bool useMiniMap  = luaL_optboolean(L, 4, false);
1377 	const bool includeSky  = luaL_optboolean(L, 5, false);
1378 	const bool ignoreWater = luaL_optboolean(L, 6, false);
1379 
1380 	const int wx = mx + globalRendering->viewPosX;
1381 	const int wy = globalRendering->viewSizeY - 1 - my - globalRendering->viewPosY;
1382 
1383 	if (useMiniMap && (minimap != NULL) && !minimap->GetMinimized()) {
1384 		const int px = minimap->GetPosX() - globalRendering->viewPosX; // for left dualscreen
1385 		const int py = minimap->GetPosY();
1386 		const int sx = minimap->GetSizeX();
1387 		const int sy = minimap->GetSizeY();
1388 		if ((mx >= px) && (mx < (px + sx)) &&
1389 		    (my >= py) && (my < (py + sy))) {
1390 			const float3 pos = minimap->GetMapPosition(wx, wy);
1391 			if (!onlyCoords) {
1392 				const CUnit* unit = minimap->GetSelectUnit(pos);
1393 				if (unit != NULL) {
1394 					lua_pushliteral(L, "unit");
1395 					lua_pushnumber(L, unit->id);
1396 					return 2;
1397 				}
1398 			}
1399 			const float posY = CGround::GetHeightReal(pos.x, pos.z, false);
1400 			lua_pushliteral(L, "ground");
1401 			lua_createtable(L, 3, 0);
1402 			lua_pushnumber(L, pos.x); lua_rawseti(L, -2, 1);
1403 			lua_pushnumber(L, posY);  lua_rawseti(L, -2, 2);
1404 			lua_pushnumber(L, pos.z); lua_rawseti(L, -2, 3);
1405 			return 2;
1406 		}
1407 	}
1408 
1409 	if ((mx < 0) || (mx >= globalRendering->viewSizeX) ||
1410 	    (my < 0) || (my >= globalRendering->viewSizeY)) {
1411 		return 0;
1412 	}
1413 
1414 	CUnit* unit = NULL;
1415 	CFeature* feature = NULL;
1416 
1417 	const float range = globalRendering->viewRange * 1.4f;
1418 	const float badRange = range - 300.0f;
1419 
1420 	const float3& pos = camera->GetPos();
1421 	const float3 dir = camera->CalcPixelDir(wx, wy);
1422 
1423 
1424 // FIXME	const int origAllyTeam = gu->myAllyTeam;
1425 //	gu->myAllyTeam = readAllyTeam;
1426 	const float dist = TraceRay::GuiTraceRay(pos, dir, range, NULL, unit, feature, true, onlyCoords, ignoreWater);
1427 //	gu->myAllyTeam = origAllyTeam;
1428 
1429 	if ((dist < 0.0f || dist > badRange) && unit == NULL && feature == NULL) {
1430 		// ray went into the void (or started too far above terrain)
1431 		if (includeSky) {
1432 			lua_pushliteral(L, "sky");
1433 		} else {
1434 			return 0;
1435 		}
1436 	} else {
1437 		if (!onlyCoords) {
1438 			if (unit != NULL) {
1439 				lua_pushliteral(L, "unit");
1440 				lua_pushnumber(L, unit->id);
1441 				return 2;
1442 			}
1443 
1444 			if (feature != NULL) {
1445 				lua_pushliteral(L, "feature");
1446 				lua_pushnumber(L, feature->id);
1447 				return 2;
1448 			}
1449 		}
1450 
1451 		lua_pushliteral(L, "ground");
1452 	}
1453 
1454 	const float3 groundPos = pos + (dir * dist);
1455 	lua_createtable(L, 3, 0);
1456 	lua_pushnumber(L, groundPos.x); lua_rawseti(L, -2, 1);
1457 	lua_pushnumber(L, groundPos.y); lua_rawseti(L, -2, 2);
1458 	lua_pushnumber(L, groundPos.z); lua_rawseti(L, -2, 3);
1459 
1460 	return 2;
1461 }
1462 
1463 
GetPixelDir(lua_State * L)1464 int LuaUnsyncedRead::GetPixelDir(lua_State* L)
1465 {
1466 	const int x = luaL_checkint(L, 1);
1467 	const int y = luaL_checkint(L, 2);
1468 	const float3 dir = camera->CalcPixelDir(x,y);
1469 	lua_pushnumber(L, dir.x);
1470 	lua_pushnumber(L, dir.y);
1471 	lua_pushnumber(L, dir.z);
1472 	return 3;
1473 }
1474 
1475 
1476 
1477 /******************************************************************************/
1478 
AddPlayerToRoster(lua_State * L,int playerID,bool includePathingFlag)1479 static void AddPlayerToRoster(lua_State* L, int playerID, bool includePathingFlag)
1480 {
1481 #define PUSH_ROSTER_ENTRY(type, val) \
1482 	lua_push ## type(L, val); lua_rawseti(L, -2, index++);
1483 
1484 	const CPlayer* p = playerHandler->Player(playerID);
1485 	int index = 1;
1486 	lua_newtable(L);
1487 	PUSH_ROSTER_ENTRY(string, p->name.c_str());
1488 	PUSH_ROSTER_ENTRY(number, playerID);
1489 	PUSH_ROSTER_ENTRY(number, p->team);
1490 	PUSH_ROSTER_ENTRY(number, teamHandler->AllyTeam(p->team));
1491 	PUSH_ROSTER_ENTRY(boolean, p->spectator);
1492 	PUSH_ROSTER_ENTRY(number, p->cpuUsage);
1493 	const float pingScale = (GAME_SPEED * gs->speedFactor);
1494 
1495 	if (!includePathingFlag || p->ping != PATHING_FLAG) {
1496 		const float pingSecs = float(p->ping - 1) / pingScale;
1497 		PUSH_ROSTER_ENTRY(number, pingSecs);
1498 	} else {
1499 		const float pingSecs = float(p->ping);
1500 		PUSH_ROSTER_ENTRY(number, pingSecs);
1501 	}
1502 }
1503 
1504 
GetTeamColor(lua_State * L)1505 int LuaUnsyncedRead::GetTeamColor(lua_State* L)
1506 {
1507 	const int teamID = luaL_checkint(L, 1);
1508 	if ((teamID < 0) || (teamID >= teamHandler->ActiveTeams())) {
1509 		return 0;
1510 	}
1511 	const CTeam* team = teamHandler->Team(teamID);
1512 	if (team == NULL) {
1513 		return 0;
1514 	}
1515 
1516 	lua_pushnumber(L, (float)team->color[0] / 255.0f);
1517 	lua_pushnumber(L, (float)team->color[1] / 255.0f);
1518 	lua_pushnumber(L, (float)team->color[2] / 255.0f);
1519 	lua_pushnumber(L, (float)team->color[3] / 255.0f);
1520 
1521 	return 4;
1522 }
1523 
1524 
GetTeamOrigColor(lua_State * L)1525 int LuaUnsyncedRead::GetTeamOrigColor(lua_State* L)
1526 {
1527 	const int teamID = luaL_checkint(L, 1);
1528 	if ((teamID < 0) || (teamID >= teamHandler->ActiveTeams())) {
1529 		return 0;
1530 	}
1531 	const CTeam* team = teamHandler->Team(teamID);
1532 	if (team == NULL) {
1533 		return 0;
1534 	}
1535 
1536 	lua_pushnumber(L, (float)team->origColor[0] / 255.0f);
1537 	lua_pushnumber(L, (float)team->origColor[1] / 255.0f);
1538 	lua_pushnumber(L, (float)team->origColor[2] / 255.0f);
1539 	lua_pushnumber(L, (float)team->origColor[3] / 255.0f);
1540 
1541 	return 4;
1542 }
1543 
1544 
1545 /******************************************************************************/
1546 /******************************************************************************/
1547 
GetTimer(lua_State * L)1548 int LuaUnsyncedRead::GetTimer(lua_State* L)
1549 {
1550 	// use time since Spring's epoch in MILLIseconds because that
1551 	// is more likely to fit in a 32-bit pointer (on any platforms
1552 	// where sizeof(void*) == 4) than time since ::chrono's epoch
1553 	// (which can be arbitrarily large) and can be represented by
1554 	// single-precision floats better
1555 	//
1556 	// 4e9millis == 4e6s == 46.3 days until overflow
1557 	const spring_time time = spring_now();
1558 	const boost::uint64_t millis = time.toMilliSecs<boost::uint64_t>();
1559 
1560 	ptrdiff_t p = 0;
1561 
1562 	if (sizeof(void*) == 8) {
1563 		*reinterpret_cast<boost::uint64_t*>(&p) = millis;
1564 	} else {
1565 		*reinterpret_cast<boost::uint32_t*>(&p) = millis;
1566 	}
1567 
1568 	lua_pushlightuserdata(L, reinterpret_cast<void*>(p));
1569 	return 1;
1570 }
1571 
1572 
DiffTimers(lua_State * L)1573 int LuaUnsyncedRead::DiffTimers(lua_State* L)
1574 {
1575 	if (!lua_islightuserdata(L, 1) || !lua_islightuserdata(L, 2)) {
1576 		luaL_error(L, "Incorrect arguments to DiffTimers()");
1577 	}
1578 
1579 	const void* p1 = lua_touserdata(L, 1);
1580 	const void* p2 = lua_touserdata(L, 2);
1581 
1582 	const boost::uint64_t t1 = (sizeof(void*) == 8)?
1583 		*reinterpret_cast<boost::uint64_t*>(&p1):
1584 		*reinterpret_cast<boost::uint32_t*>(&p1);
1585 	const boost::uint64_t t2 = (sizeof(void*) == 8)?
1586 		*reinterpret_cast<boost::uint64_t*>(&p2):
1587 		*reinterpret_cast<boost::uint32_t*>(&p2);
1588 
1589 	// t1 is supposed to be the most recent time-point
1590 	assert(t1 >= t2);
1591 
1592 	const spring_time dt = spring_time::fromMilliSecs(t1 - t2);
1593 
1594 	if (luaL_optboolean(L, 3, false)) {
1595 		lua_pushnumber(L, dt.toMilliSecsf());
1596 	} else {
1597 		lua_pushnumber(L, dt.toSecsf());
1598 	}
1599 
1600 	return 1;
1601 }
1602 
1603 
1604 /******************************************************************************/
1605 /******************************************************************************/
1606 
GetSoundStreamTime(lua_State * L)1607 int LuaUnsyncedRead::GetSoundStreamTime(lua_State* L)
1608 {
1609 	lua_pushnumber(L, Channels::BGMusic->StreamGetPlayTime());
1610 	lua_pushnumber(L, Channels::BGMusic->StreamGetTime());
1611 	return 2;
1612 }
1613 
1614 
GetSoundEffectParams(lua_State * L)1615 int LuaUnsyncedRead::GetSoundEffectParams(lua_State* L)
1616 {
1617 #if defined(HEADLESS) || defined(NO_SOUND)
1618 	return 0;
1619 #else
1620 	if (!efx || !efx->sfxProperties)
1621 		return 0;
1622 
1623 	EAXSfxProps* efxprops = efx->sfxProperties;
1624 
1625 	lua_createtable(L, 0, 2);
1626 
1627 	size_t n = efxprops->filter_properties_f.size();
1628 	lua_pushliteral(L, "passfilter");
1629 	lua_createtable(L, 0, n);
1630 	lua_rawset(L, -3);
1631 	for (std::map<ALuint, ALfloat>::iterator it = efxprops->filter_properties_f.begin(); it != efxprops->filter_properties_f.end(); ++it)
1632 	{
1633 		const ALuint param = it->first;
1634 		std::map<ALuint, std::string>::iterator fit = alFilterParamToName.find(param);
1635 		if (fit != alFilterParamToName.end()) {
1636 			const std::string& name = fit->second;
1637 			lua_pushsstring(L, name);
1638 			lua_pushnumber(L, it->second);
1639 			lua_rawset(L, -3);
1640 		}
1641 	}
1642 
1643 
1644 	n = efxprops->properties_v.size() + efxprops->properties_f.size() + efxprops->properties_i.size();
1645 	lua_pushliteral(L, "reverb");
1646 	lua_createtable(L, 0, n);
1647 	lua_rawset(L, -3);
1648 	for (std::map<ALuint, ALfloat>::iterator it = efxprops->properties_f.begin(); it != efxprops->properties_f.end(); ++it)
1649 	{
1650 		const ALuint param = it->first;
1651 		std::map<ALuint, std::string>::iterator fit = alParamToName.find(param);
1652 		if (fit != alParamToName.end()) {
1653 			const std::string& name = fit->second;
1654 			lua_pushsstring(L, name);
1655 			lua_pushnumber(L, it->second);
1656 			lua_rawset(L, -3);
1657 		}
1658 	}
1659 	for (std::map<ALuint, float3>::iterator it = efxprops->properties_v.begin(); it != efxprops->properties_v.end(); ++it)
1660 	{
1661 		const ALuint param = it->first;
1662 		std::map<ALuint, std::string>::iterator fit = alParamToName.find(param);
1663 		if (fit != alParamToName.end()) {
1664 			const float3& v = it->second;
1665 			const std::string& name = fit->second;
1666 			lua_pushsstring(L, name);
1667 			lua_createtable(L, 3, 0);
1668 				lua_pushnumber(L, v.x);
1669 				lua_rawseti(L, -2, 1);
1670 				lua_pushnumber(L, v.y);
1671 				lua_rawseti(L, -2, 2);
1672 				lua_pushnumber(L, v.z);
1673 				lua_rawseti(L, -2, 3);
1674 			lua_rawset(L, -3);
1675 		}
1676 	}
1677 	for (std::map<ALuint, ALint>::iterator it = efxprops->properties_i.begin(); it != efxprops->properties_i.end(); ++it)
1678 	{
1679 		const ALuint param = it->first;
1680 		std::map<ALuint, std::string>::iterator fit = alParamToName.find(param);
1681 		if (fit != alParamToName.end()) {
1682 			const std::string& name = fit->second;
1683 			lua_pushsstring(L, name);
1684 			lua_pushboolean(L, it->second);
1685 			lua_rawset(L, -3);
1686 		}
1687 	}
1688 
1689 	return 1;
1690 #endif // defined(HEADLESS) || defined(NO_SOUND)
1691 }
1692 
1693 
1694 /******************************************************************************/
1695 /******************************************************************************/
1696 //
1697 // moved from LuaUI
1698 //
1699 /******************************************************************************/
1700 /******************************************************************************/
1701 
GetFPS(lua_State * L)1702 int LuaUnsyncedRead::GetFPS(lua_State* L)
1703 {
1704 	if (globalRendering) {
1705 		lua_pushnumber(L, (int)globalRendering->FPS);
1706 	} else {
1707 		lua_pushnumber(L, 0);
1708 	}
1709 	return 1;
1710 }
1711 
1712 
GetGameSpeed(lua_State * L)1713 int LuaUnsyncedRead::GetGameSpeed(lua_State* L)
1714 {
1715 	lua_pushnumber(L, gs->wantedSpeedFactor);
1716 	lua_pushnumber(L, gs->speedFactor);
1717 	lua_pushboolean(L, gs->paused);
1718 	return 3;
1719 }
1720 
1721 
1722 /******************************************************************************/
1723 
GetActiveCommand(lua_State * L)1724 int LuaUnsyncedRead::GetActiveCommand(lua_State* L)
1725 {
1726 	if (guihandler == NULL) {
1727 		return 0;
1728 	}
1729 
1730 	const vector<CommandDescription>& cmdDescs = guihandler->commands;
1731 	const int cmdDescCount = (int)cmdDescs.size();
1732 
1733 	const int inCommand = guihandler->inCommand;
1734 	lua_pushnumber(L, inCommand + CMD_INDEX_OFFSET);
1735 	if ((inCommand < 0) || (inCommand >= cmdDescCount)) {
1736 		return 1;
1737 	}
1738 	lua_pushnumber(L, cmdDescs[inCommand].id);
1739 	lua_pushnumber(L, cmdDescs[inCommand].type);
1740 	lua_pushsstring(L, cmdDescs[inCommand].name);
1741 	return 4;
1742 }
1743 
1744 
GetDefaultCommand(lua_State * L)1745 int LuaUnsyncedRead::GetDefaultCommand(lua_State* L)
1746 {
1747 	if (guihandler == NULL) {
1748 		return 0;
1749 	}
1750 
1751 	const int defCmd = guihandler->GetDefaultCommand(mouse->lastx, mouse->lasty);
1752 
1753 	const vector<CommandDescription>& cmdDescs = guihandler->commands;
1754 	const int cmdDescCount = (int)cmdDescs.size();
1755 
1756 	lua_pushnumber(L, defCmd + CMD_INDEX_OFFSET);
1757 	if ((defCmd < 0) || (defCmd >= cmdDescCount)) {
1758 		return 1;
1759 	}
1760 	lua_pushnumber(L, cmdDescs[defCmd].id);
1761 	lua_pushnumber(L, cmdDescs[defCmd].type);
1762 	lua_pushsstring(L, cmdDescs[defCmd].name);
1763 	return 4;
1764 }
1765 
1766 
GetActiveCmdDescs(lua_State * L)1767 int LuaUnsyncedRead::GetActiveCmdDescs(lua_State* L)
1768 {
1769 	if (guihandler == NULL) {
1770 		return 0;
1771 	}
1772 
1773 	const vector<CommandDescription>& cmdDescs = guihandler->commands;
1774 	const int cmdDescCount = (int)cmdDescs.size();
1775 
1776 	lua_checkstack(L, 1 + 2);
1777 	lua_newtable(L);
1778 
1779 	for (int i = 0; i < cmdDescCount; i++) {
1780 		LuaUtils::PushCommandDesc(L, cmdDescs[i]);
1781 		lua_rawseti(L, -2, i + CMD_INDEX_OFFSET);
1782 	}
1783 	return 1;
1784 }
1785 
1786 
GetActiveCmdDesc(lua_State * L)1787 int LuaUnsyncedRead::GetActiveCmdDesc(lua_State* L)
1788 {
1789 	if (guihandler == NULL) {
1790 		return 0;
1791 	}
1792 	const int cmdIndex = luaL_checkint(L, 1) - CMD_INDEX_OFFSET;
1793 
1794 	const vector<CommandDescription>& cmdDescs = guihandler->commands;
1795 	const int cmdDescCount = (int)cmdDescs.size();
1796 	if ((cmdIndex < 0) || (cmdIndex >= cmdDescCount)) {
1797 		return 0;
1798 	}
1799 	LuaUtils::PushCommandDesc(L, cmdDescs[cmdIndex]);
1800 	return 1;
1801 }
1802 
1803 
GetCmdDescIndex(lua_State * L)1804 int LuaUnsyncedRead::GetCmdDescIndex(lua_State* L)
1805 {
1806 	if (guihandler == NULL) {
1807 		return 0;
1808 	}
1809 	const int cmdId = luaL_checkint(L, 1);
1810 
1811 	const vector<CommandDescription>& cmdDescs = guihandler->commands;
1812 	const int cmdDescCount = (int)cmdDescs.size();
1813 	for (int i = 0; i < cmdDescCount; i++) {
1814 		if (cmdId == cmdDescs[i].id) {
1815 			lua_pushnumber(L, i + CMD_INDEX_OFFSET);
1816 			return 1;
1817 		}
1818 	}
1819 	return 0;
1820 }
1821 
1822 
1823 /******************************************************************************/
1824 
GetBuildFacing(lua_State * L)1825 int LuaUnsyncedRead::GetBuildFacing(lua_State* L)
1826 {
1827 	if (guihandler == NULL) {
1828 		return 0;
1829 	}
1830 	lua_pushnumber(L, guihandler->buildFacing);
1831 	return 1;
1832 }
1833 
1834 
GetBuildSpacing(lua_State * L)1835 int LuaUnsyncedRead::GetBuildSpacing(lua_State* L)
1836 {
1837 	if (guihandler == NULL) {
1838 		return 0;
1839 	}
1840 	lua_pushnumber(L, guihandler->buildSpacing);
1841 	return 1;
1842 }
1843 
1844 
GetGatherMode(lua_State * L)1845 int LuaUnsyncedRead::GetGatherMode(lua_State* L)
1846 {
1847 	if (guihandler == NULL) {
1848 		return 0;
1849 	}
1850 	lua_pushnumber(L, guihandler->GetGatherMode());
1851 	return 1;
1852 }
1853 
1854 
1855 /******************************************************************************/
1856 
GetActivePage(lua_State * L)1857 int LuaUnsyncedRead::GetActivePage(lua_State* L)
1858 {
1859 	if (guihandler == NULL) {
1860 		return 0;
1861 	}
1862 	lua_pushnumber(L, guihandler->GetActivePage());
1863 	lua_pushnumber(L, guihandler->GetMaxPage());
1864 	return 2;
1865 }
1866 
1867 
1868 /******************************************************************************/
1869 
GetMouseState(lua_State * L)1870 int LuaUnsyncedRead::GetMouseState(lua_State* L)
1871 {
1872 	lua_pushnumber(L, mouse->lastx - globalRendering->viewPosX);
1873 	lua_pushnumber(L, globalRendering->viewSizeY - mouse->lasty - 1);
1874 	lua_pushboolean(L, mouse->buttons[SDL_BUTTON_LEFT].pressed);
1875 	lua_pushboolean(L, mouse->buttons[SDL_BUTTON_MIDDLE].pressed);
1876 	lua_pushboolean(L, mouse->buttons[SDL_BUTTON_RIGHT].pressed);
1877 	return 5;
1878 }
1879 
1880 
GetMouseCursor(lua_State * L)1881 int LuaUnsyncedRead::GetMouseCursor(lua_State* L)
1882 {
1883 	lua_pushsstring(L, mouse->GetCurrentCursor());
1884 	lua_pushnumber(L, mouse->GetCurrentCursorScale());
1885 	return 2;
1886 }
1887 
1888 
GetMouseStartPosition(lua_State * L)1889 int LuaUnsyncedRead::GetMouseStartPosition(lua_State* L)
1890 {
1891 	if (mouse == NULL) {
1892 		return 0;
1893 	}
1894 	const int button = luaL_checkint(L, 1);
1895 	if ((button <= 0) || (button > NUM_BUTTONS)) {
1896 		return 0;
1897 	}
1898 	const CMouseHandler::ButtonPressEvt& bp = mouse->buttons[button];
1899 	lua_pushnumber(L, bp.x);
1900 	lua_pushnumber(L, bp.y);
1901 	lua_pushnumber(L, bp.camPos.x);
1902 	lua_pushnumber(L, bp.camPos.y);
1903 	lua_pushnumber(L, bp.camPos.z);
1904 	lua_pushnumber(L, bp.dir.x);
1905 	lua_pushnumber(L, bp.dir.y);
1906 	lua_pushnumber(L, bp.dir.z);
1907 	return 8;
1908 }
1909 
1910 
1911 /******************************************************************************/
1912 /******************************************************************************/
1913 
GetKeyState(lua_State * L)1914 int LuaUnsyncedRead::GetKeyState(lua_State* L)
1915 {
1916 	const int key = luaL_checkint(L, 1);
1917 	lua_pushboolean(L, KeyInput::IsKeyPressed(key));
1918 	return 1;
1919 }
1920 
1921 
GetModKeyState(lua_State * L)1922 int LuaUnsyncedRead::GetModKeyState(lua_State* L)
1923 {
1924 	lua_pushboolean(L, KeyInput::GetKeyModState(KMOD_ALT));
1925 	lua_pushboolean(L, KeyInput::GetKeyModState(KMOD_CTRL));
1926 	lua_pushboolean(L, KeyInput::GetKeyModState(KMOD_GUI));
1927 	lua_pushboolean(L, KeyInput::GetKeyModState(KMOD_SHIFT));
1928 	return 4;
1929 }
1930 
1931 
GetPressedKeys(lua_State * L)1932 int LuaUnsyncedRead::GetPressedKeys(lua_State* L)
1933 {
1934 	lua_newtable(L);
1935 	for (auto key: KeyInput::GetPressedKeys()) {
1936 		if (key.second) {
1937 			lua_pushboolean(L, true);
1938 			lua_rawseti(L, -2, key.first);
1939 		}
1940 	}
1941 	return 1;
1942 }
1943 
1944 
GetInvertQueueKey(lua_State * L)1945 int LuaUnsyncedRead::GetInvertQueueKey(lua_State* L)
1946 {
1947 	if (guihandler == NULL) {
1948 		return 0;
1949 	}
1950 	lua_pushboolean(L, guihandler->GetInvertQueueKey());
1951 	return 1;
1952 }
1953 
1954 /******************************************************************************/
1955 
GetClipboard(lua_State * L)1956 int LuaUnsyncedRead::GetClipboard(lua_State* L)
1957 {
1958 	char* text = SDL_GetClipboardText();
1959 	if (text == NULL) {
1960 		return 0;
1961 	}
1962 	lua_pushstring(L, text);
1963 	SDL_free(text);
1964 	return 1;
1965 }
1966 
1967 /******************************************************************************/
1968 
GetLastMessagePositions(lua_State * L)1969 int LuaUnsyncedRead::GetLastMessagePositions(lua_State* L)
1970 {
1971 	CInfoConsole* ic = game->infoConsole;
1972 
1973 	if (ic == NULL)
1974 		return 0;
1975 
1976 	lua_newtable(L);
1977 	for (unsigned int i = 1; i <= ic->GetMsgPosCount(); i++) {
1978 		lua_newtable(L); {
1979 			const float3 msgpos = ic->GetMsgPos();
1980 			lua_pushnumber(L, msgpos.x); lua_rawseti(L, -2, 1);
1981 			lua_pushnumber(L, msgpos.y); lua_rawseti(L, -2, 2);
1982 			lua_pushnumber(L, msgpos.z); lua_rawseti(L, -2, 3);
1983 		}
1984 		lua_rawseti(L, -2, i);
1985 	}
1986 	return 1;
1987 }
1988 
1989 /******************************************************************************/
1990 
GetConsoleBuffer(lua_State * L)1991 int LuaUnsyncedRead::GetConsoleBuffer(lua_State* L)
1992 {
1993 	CInfoConsole* ic = game->infoConsole;
1994 	if (ic == NULL) {
1995 		return true;
1996 	}
1997 
1998 	const int args = lua_gettop(L); // number of arguments
1999 
2000 	std::deque<CInfoConsole::RawLine> lines;
2001 	ic->GetRawLines(lines);
2002 	const int lineCount = (int)lines.size();
2003 
2004 	int start = 0;
2005 	if (args >= 1) {
2006 		const int maxLines = luaL_checkint(L, 1);
2007 		if (maxLines < lineCount) {
2008 			start = (lineCount - maxLines);
2009 		}
2010 	}
2011 
2012 	// table = { [1] = { text = string, zone = number}, etc... }
2013 	lua_newtable(L);
2014 
2015 	unsigned int count = 0;
2016 
2017 	for (int i = start; i < lineCount; i++) {
2018 		count++;
2019 		lua_pushnumber(L, count);
2020 		lua_newtable(L); {
2021 			lua_pushliteral(L, "text");
2022 			lua_pushsstring(L, lines[i].text);
2023 			lua_rawset(L, -3);
2024 			lua_pushliteral(L, "priority");
2025 			lua_pushnumber(L, lines[i].level);
2026 			lua_rawset(L, -3);
2027 		}
2028 		lua_rawset(L, -3);
2029 	}
2030 
2031 	return 1;
2032 }
2033 
2034 
GetCurrentTooltip(lua_State * L)2035 int LuaUnsyncedRead::GetCurrentTooltip(lua_State* L)
2036 {
2037 	lua_pushsstring(L, mouse->GetCurrentTooltip());
2038 	return 1;
2039 }
2040 
2041 
GetKeyCode(lua_State * L)2042 int LuaUnsyncedRead::GetKeyCode(lua_State* L)
2043 {
2044 	if (keyCodes == NULL) {
2045 		return 0;
2046 	}
2047 
2048 	const int keycode = keyCodes->GetCode(luaL_checksstring(L, 1));
2049 	lua_pushnumber(L, SDL21_keysyms(keycode));
2050 	return 1;
2051 }
2052 
2053 
GetKeySymbol(lua_State * L)2054 int LuaUnsyncedRead::GetKeySymbol(lua_State* L)
2055 {
2056 	const int keycode = SDL12_keysyms(luaL_checkint(L, 1));
2057 	lua_pushsstring(L, (keyCodes != NULL)? keyCodes->GetName(keycode): "");
2058 	lua_pushsstring(L, (keyCodes != NULL)? keyCodes->GetDefaultName(keycode): "");
2059 	return 2;
2060 }
2061 
2062 
GetKeyBindings(lua_State * L)2063 int LuaUnsyncedRead::GetKeyBindings(lua_State* L)
2064 {
2065 	CKeySet ks;
2066 
2067 	if (!ks.Parse(luaL_checksstring(L, 1)))
2068 		return 0;
2069 	if (keyBindings == NULL)
2070 		return 0;
2071 
2072 	const CKeyBindings::ActionList& actions = keyBindings->GetActionList(ks);
2073 
2074 	int i = 1;
2075 	lua_newtable(L);
2076 	for (const Action& action: actions) {
2077 		lua_newtable(L);
2078 			lua_pushsstring(L, action.command);
2079 			lua_pushsstring(L, action.extra);
2080 			lua_rawset(L, -3);
2081 			LuaPushNamedString(L, "command",   action.command);
2082 			LuaPushNamedString(L, "extra",     action.extra);
2083 			LuaPushNamedString(L, "boundWith", action.boundWith);
2084 		lua_rawseti(L, -2, i++);
2085 	}
2086 	return 1;
2087 }
2088 
2089 
GetActionHotKeys(lua_State * L)2090 int LuaUnsyncedRead::GetActionHotKeys(lua_State* L)
2091 {
2092 	if (keyBindings == NULL)
2093 		return 0;
2094 
2095 	const CKeyBindings::HotkeyList& hotkeys = keyBindings->GetHotkeys(luaL_checksstring(L, 1));
2096 
2097 	lua_newtable(L);
2098 	int i = 1;
2099 	for (const std::string& hotkey: hotkeys) {
2100 		lua_pushsstring(L, hotkey);
2101 		lua_rawseti(L, -2, i++);
2102 	}
2103 	return 1;
2104 }
2105 
2106 /******************************************************************************/
2107 
GetGroupList(lua_State * L)2108 int LuaUnsyncedRead::GetGroupList(lua_State* L)
2109 {
2110 	if (grouphandlers[gu->myTeam] == NULL) {
2111 		return 0;
2112 	}
2113 	lua_newtable(L);
2114 
2115 	unsigned int count = 0;
2116 
2117 	const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2118 	vector<CGroup*>::const_iterator git;
2119 	for (git = groups.begin(); git != groups.end(); ++git) {
2120 		const CGroup* group = *git;
2121 		if ((group != NULL) && !group->units.empty()) {
2122 			lua_pushnumber(L, group->units.size());
2123 			lua_rawseti(L, -2, group->id);
2124 			count++;
2125 		}
2126 	}
2127 	lua_pushnumber(L, count);
2128 	return 2;
2129 }
2130 
2131 
GetSelectedGroup(lua_State * L)2132 int LuaUnsyncedRead::GetSelectedGroup(lua_State* L)
2133 {
2134 	lua_pushnumber(L, selectedUnitsHandler.GetSelectedGroup());
2135 	return 1;
2136 }
2137 
2138 
GetUnitGroup(lua_State * L)2139 int LuaUnsyncedRead::GetUnitGroup(lua_State* L)
2140 {
2141 	CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
2142 	if (unit == NULL) {
2143 		return 0;
2144 	}
2145 	if ((unit->team == gu->myTeam) && (unit->group)) {
2146 		lua_pushnumber(L, unit->group->id);
2147 		return 1;
2148 	}
2149 	return 0;
2150 }
2151 
2152 
2153 /******************************************************************************/
2154 
GetGroupUnits(lua_State * L)2155 int LuaUnsyncedRead::GetGroupUnits(lua_State* L)
2156 {
2157 	const int groupID = luaL_checkint(L, 1);
2158 	const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2159 	if ((groupID < 0) || ((size_t)groupID >= groups.size()) ||
2160 	    (groups[groupID] == NULL)) {
2161 		return 0; // nils
2162 	}
2163 
2164 	lua_newtable(L);
2165 
2166 	unsigned int count = 0;
2167 
2168 	const CUnitSet& groupUnits = groups[groupID]->units;
2169 	CUnitSet::const_iterator it;
2170 	for (it = groupUnits.begin(); it != groupUnits.end(); ++it) {
2171 		count++;
2172 		lua_pushnumber(L, (*it)->id);
2173 		lua_rawseti(L, -2, count);
2174 	}
2175 
2176 	return 1;
2177 }
2178 
2179 
GetGroupUnitsSorted(lua_State * L)2180 int LuaUnsyncedRead::GetGroupUnitsSorted(lua_State* L)
2181 {
2182 	const int groupID = luaL_checkint(L, 1);
2183 	const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2184 	if ((groupID < 0) || ((size_t)groupID >= groups.size()) ||
2185 	    (groups[groupID] == NULL)) {
2186 		return 0; // nils
2187 	}
2188 
2189 	map<int, vector<CUnit*> > unitDefMap;
2190 	const CUnitSet& groupUnits = groups[groupID]->units;
2191 	CUnitSet::const_iterator it;
2192 	for (it = groupUnits.begin(); it != groupUnits.end(); ++it) {
2193 		CUnit* unit = *it;
2194 		unitDefMap[unit->unitDef->id].push_back(unit);
2195 	}
2196 
2197 	lua_newtable(L);
2198 	map<int, vector<CUnit*> >::const_iterator mit;
2199 	for (mit = unitDefMap.begin(); mit != unitDefMap.end(); ++mit) {
2200 		lua_pushnumber(L, mit->first); // push the UnitDef index
2201 		lua_newtable(L); {
2202 			const vector<CUnit*>& v = mit->second;
2203 			for (int i = 0; i < (int)v.size(); i++) {
2204 				CUnit* unit = v[i];
2205 				lua_pushnumber(L, unit->id);
2206 				lua_rawseti(L, -2, i + 1);
2207 			}
2208 		}
2209 		lua_rawset(L, -3);
2210 	}
2211 
2212 	return 1;
2213 }
2214 
2215 
GetGroupUnitsCounts(lua_State * L)2216 int LuaUnsyncedRead::GetGroupUnitsCounts(lua_State* L)
2217 {
2218 	const int groupID = luaL_checkint(L, 1);
2219 	const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2220 	if ((groupID < 0) || ((size_t)groupID >= groups.size()) ||
2221 	    (groups[groupID] == NULL)) {
2222 		return 0; // nils
2223 	}
2224 
2225 	map<int, int> countMap;
2226 	const CUnitSet& groupUnits = groups[groupID]->units;
2227 	CUnitSet::const_iterator it;
2228 	for (it = groupUnits.begin(); it != groupUnits.end(); ++it) {
2229 		CUnit* unit = *it;
2230 		const int udID = unit->unitDef->id;
2231 		map<int, int>::iterator mit = countMap.find(udID);
2232 		if (mit == countMap.end()) {
2233 			countMap[udID] = 1;
2234 		} else {
2235 			mit->second++;
2236 		}
2237 	}
2238 
2239 	lua_newtable(L);
2240 	map<int, int>::const_iterator mit;
2241 	for (mit = countMap.begin(); mit != countMap.end(); ++mit) {
2242 		lua_pushnumber(L, mit->second); // push the UnitDef unit count
2243 		lua_rawseti(L, -2, mit->first); // push the UnitDef index
2244 	}
2245 
2246 	return 1;
2247 }
2248 
2249 
GetGroupUnitsCount(lua_State * L)2250 int LuaUnsyncedRead::GetGroupUnitsCount(lua_State* L)
2251 {
2252 	const int groupID = luaL_checkint(L, 1);
2253 	const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2254 	if ((groupID < 0) || ((size_t)groupID >= groups.size()) ||
2255 	    (groups[groupID] == NULL)) {
2256 		return 0; // nils
2257 	}
2258 	lua_pushnumber(L, groups[groupID]->units.size());
2259 	return 1;
2260 }
2261 
2262 
2263 /******************************************************************************/
2264 /******************************************************************************/
2265 
GetPlayerRoster(lua_State * L)2266 int LuaUnsyncedRead::GetPlayerRoster(lua_State* L)
2267 {
2268 	const PlayerRoster::SortType oldSortType = playerRoster.GetSortType();
2269 
2270 	if (!lua_isnone(L, 1)) {
2271 		playerRoster.SetSortTypeByCode((PlayerRoster::SortType) luaL_checkint(L, 1));
2272 	}
2273 
2274 	const bool includePathingFlag = luaL_optboolean(L, 2, false);
2275 
2276 	int count;
2277 	const std::vector<int>& players = playerRoster.GetIndices(&count, includePathingFlag);
2278 
2279 	playerRoster.SetSortTypeByCode(oldSortType); // revert
2280 
2281 	lua_createtable(L, count, 0);
2282 	for (int i = 0; i < count; i++) {
2283 		AddPlayerToRoster(L, players[i], includePathingFlag);
2284 		lua_rawseti(L, -2, i + 1);
2285 	}
2286 
2287 	return 1;
2288 }
2289 
GetPlayerTraffic(lua_State * L)2290 int LuaUnsyncedRead::GetPlayerTraffic(lua_State* L)
2291 {
2292 	const int playerID = luaL_checkint(L, 1);
2293 	const int packetID = (int)luaL_optnumber(L, 2, -1);
2294 
2295 	const std::map<int, CGame::PlayerTrafficInfo>& traffic
2296 		= game->GetPlayerTraffic();
2297 	std::map<int, CGame::PlayerTrafficInfo>::const_iterator it;
2298 	it = traffic.find(playerID);
2299 	if (it == traffic.end()) {
2300 		lua_pushnumber(L, -1);
2301 		return 1;
2302 	}
2303 
2304 	// only allow viewing stats for specific packet types
2305 	if (
2306 		(playerID != -1) &&              // all system counts can be read
2307 		(playerID != gu->myPlayerNum) && // all  self  counts can be read
2308 		(packetID != -1) &&
2309 		(packetID != NETMSG_CHAT)     &&
2310 		(packetID != NETMSG_PAUSE)    &&
2311 		(packetID != NETMSG_LUAMSG)   &&
2312 		(packetID != NETMSG_STARTPOS) &&
2313 		(packetID != NETMSG_USER_SPEED)
2314 	) {
2315 		lua_pushnumber(L, -1);
2316 		return 1;
2317 	}
2318 
2319 	const CGame::PlayerTrafficInfo& pti = it->second;
2320 	if (packetID == -1) {
2321 		lua_pushnumber(L, pti.total);
2322 		return 1;
2323 	}
2324 	std::map<int, int>::const_iterator pit = pti.packets.find(packetID);
2325 	if (pit == pti.packets.end()) {
2326 		lua_pushnumber(L, -1);
2327 		return 1;
2328 	}
2329 	lua_pushnumber(L, pit->second);
2330 	return 1;
2331 }
2332 
GetPlayerStatistics(lua_State * L)2333 int LuaUnsyncedRead::GetPlayerStatistics(lua_State* L)
2334 {
2335 	const int playerID = luaL_checkint(L, 1);
2336 	if (!playerHandler->IsValidPlayer(playerID)) {
2337 		return 0;
2338 	}
2339 
2340 	const CPlayer* player = playerHandler->Player(playerID);
2341 	if (player == NULL) {
2342 		return 0;
2343 	}
2344 
2345 	const PlayerStatistics& pStats = player->currentStats;
2346 
2347 	lua_pushnumber(L, pStats.mousePixels);
2348 	lua_pushnumber(L, pStats.mouseClicks);
2349 	lua_pushnumber(L, pStats.keyPresses);
2350 	lua_pushnumber(L, pStats.numCommands);
2351 	lua_pushnumber(L, pStats.unitCommands);
2352 
2353 	return 5;
2354 }
2355 
2356 
2357 /******************************************************************************/
2358 /******************************************************************************/
2359 
GetDrawSelectionInfo(lua_State * L)2360 int LuaUnsyncedRead::GetDrawSelectionInfo(lua_State* L)
2361 {
2362 	lua_pushboolean(L, guihandler ? guihandler->GetDrawSelectionInfo() : 0);
2363 	return 1;
2364 }
2365 
2366 
2367 /******************************************************************************/
2368 /******************************************************************************/
2369 
GetConfigParams(lua_State * L)2370 int LuaUnsyncedRead::GetConfigParams(lua_State* L)
2371 {
2372 	ConfigVariable::MetaDataMap cfgmap = ConfigVariable::GetMetaDataMap();
2373 	lua_createtable(L, cfgmap.size(), 0);
2374 
2375 	int i = 1;
2376 	for (ConfigVariable::MetaDataMap::const_iterator it = cfgmap.begin(); it != cfgmap.end(); ++it)
2377 	{
2378 		const ConfigVariableMetaData* meta = it->second;
2379 
2380 		lua_createtable(L, 0, 9);
2381 
2382 			lua_pushliteral(L, "name");
2383 			lua_pushsstring(L, meta->GetKey());
2384 			lua_rawset(L, -3);
2385 			if (meta->GetDescription().IsSet()) {
2386 				lua_pushliteral(L, "description");
2387 				lua_pushsstring(L, meta->GetDescription().ToString());
2388 				lua_rawset(L, -3);
2389 			}
2390 			lua_pushliteral(L, "type");
2391 			lua_pushsstring(L, meta->GetType());
2392 			lua_rawset(L, -3);
2393 			if (meta->GetDefaultValue().IsSet()) {
2394 				lua_pushliteral(L, "defaultValue");
2395 				lua_pushsstring(L, meta->GetDefaultValue().ToString());
2396 				lua_rawset(L, -3);
2397 			}
2398 			if (meta->GetMinimumValue().IsSet()) {
2399 				lua_pushliteral(L, "minimumValue");
2400 				lua_pushsstring(L, meta->GetMinimumValue().ToString());
2401 				lua_rawset(L, -3);
2402 			}
2403 			if (meta->GetMaximumValue().IsSet()) {
2404 				lua_pushliteral(L, "maximumValue");
2405 				lua_pushsstring(L, meta->GetMaximumValue().ToString());
2406 				lua_rawset(L, -3);
2407 			}
2408 			if (meta->GetSafemodeValue().IsSet()) {
2409 				lua_pushliteral(L, "safemodeValue");
2410 				lua_pushsstring(L, meta->GetSafemodeValue().ToString());
2411 				lua_rawset(L, -3);
2412 			}
2413 			if (meta->GetDeclarationFile().IsSet()) {
2414 				lua_pushliteral(L, "declarationFile");
2415 				lua_pushsstring(L, meta->GetDeclarationFile().ToString());
2416 				lua_rawset(L, -3);
2417 			}
2418 			if (meta->GetDeclarationLine().IsSet()) {
2419 				lua_pushliteral(L, "declarationLine");
2420 				lua_pushnumber(L, meta->GetDeclarationLine().Get());
2421 				lua_rawset(L, -3);
2422 			}
2423 			if (meta->GetReadOnly().IsSet()) {
2424 				lua_pushliteral(L, "readOnly");
2425 				lua_pushboolean(L, !!meta->GetReadOnly().Get());
2426 				lua_rawset(L, -3);
2427 			}
2428 
2429 		lua_rawseti(L, -2, i++);
2430 	}
2431 	return 1;
2432 }
2433 
2434 /******************************************************************************/
2435 /******************************************************************************/
2436 
GetLogSections(lua_State * L)2437 int LuaUnsyncedRead::GetLogSections(lua_State* L) {
2438 	const int numLogSections = log_filter_section_getNumRegisteredSections();
2439 
2440 	lua_createtable(L, 0, numLogSections);
2441 	for (int i = 0; i < numLogSections; ++i) {
2442 		const char* sectionName = log_filter_section_getRegisteredIndex(i);
2443 		const int logLevel = log_filter_section_getMinLevel(sectionName);
2444 
2445 		lua_pushstring(L, sectionName);
2446 		lua_pushnumber(L, logLevel);
2447 		lua_rawset(L, -3);
2448 	}
2449 
2450 	return 1;
2451 }
2452 
2453 /******************************************************************************/
2454 /******************************************************************************/
2455