File: LuaInterCall.cpp

package info (click to toggle)
spring 98.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 41,928 kB
  • ctags: 60,665
  • sloc: cpp: 356,167; ansic: 39,434; python: 12,228; java: 12,203; awk: 5,856; sh: 1,719; xml: 997; perl: 405; php: 253; objc: 194; makefile: 72; sed: 2
file content (143 lines) | stat: -rw-r--r-- 3,597 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */


#include "LuaInterCall.h"

#include "LuaInclude.h"

#include "LuaHandle.h"
#include "LuaGaia.h"
#include "LuaRules.h"
#include "LuaUI.h"


enum {
	LUA_UI,
	LUA_RULES,
	LUA_GAIA
};


static CLuaHandle* GetLuaHandle(lua_State* L, int index)
{
	int* addr = (int*) lua_touserdata(L, index);
	if (addr == NULL) {
		luaL_error(L, "Bad XCall target");
		return NULL;
	}

	const bool isSrcSynced = CLuaHandle::GetHandleSynced(L);
	switch (*addr) {
		case LUA_UI:
			if (!luaUI) return NULL; // handle is not currently active
			return luaUI;
		case LUA_RULES:
			if (!luaRules) return NULL; // handle is not currently active
			return (isSrcSynced) ? static_cast<CLuaHandle*>(&luaRules->syncedLuaHandle) : static_cast<CLuaHandle*>(&luaRules->unsyncedLuaHandle);
		case LUA_GAIA:
			if (!luaGaia) return NULL; // handle is not currently active
			return (isSrcSynced) ? static_cast<CLuaHandle*>(&luaGaia->syncedLuaHandle) : static_cast<CLuaHandle*>(&luaGaia->unsyncedLuaHandle);
		default:
			luaL_error(L, "Bad XCall target");
			return NULL;
	};
}


/******************************************************************************/
/******************************************************************************/


static int HandleXCall(lua_State* L)
{
	const int addrIndex = lua_upvalueindex(1);
	const int nameIndex = lua_upvalueindex(2);

	CLuaHandle* lh = GetLuaHandle(L, addrIndex);
	const std::string funcName = luaL_checksstring(L, nameIndex);

	if (lh == NULL) return 0;
	return lh->XCall(L, funcName);
}


static int IndexHook(lua_State* L)
{
	if (!lua_israwstring(L, -1)) {
		return luaL_error(L, "Script.XYZ: only strings allowed got ", lua_typename(L, -1));
	}

	lua_pushvalue(L, lua_upvalueindex(1));
	lua_pushvalue(L, -2);
	lua_pushcclosure(L, HandleXCall, 2);
	return 1;
}


static int CallHook(lua_State* L)
{
	const int addrIndex = lua_upvalueindex(1);
	CLuaHandle* lh = GetLuaHandle(L, addrIndex);
	if (lh == NULL) return 0;

	const int args = lua_gettop(L); // arg 1 is the table
	if (args <= 1) {
		// is the handle currently active?
		lua_pushboolean(L, (lh != NULL));
		return 1;
	}
	else if (args >= 2) {
		// see if the specified function exists
		const string funcName = luaL_checksstring(L, 2);
		lua_pushboolean(L, lh->HasXCall(funcName));
		return 1;
	}
	return 0;
}


static int PushCallHandler(lua_State* L, int luaInstance, const string& name)
{
	lua_pushsstring(L, name);
	int* ptr = (int*) lua_newuserdata(L, sizeof(int));
	*ptr = luaInstance;
	{ // create metatable of the userdata
		lua_newtable(L); {
			lua_pushliteral(L, "__index");
			lua_pushvalue(L, -3); //userdata
			lua_pushcclosure(L,  IndexHook, 1);
			lua_rawset(L, -3);
			lua_pushliteral(L, "__call");
			lua_pushvalue(L, -3); //userdata
			lua_pushcclosure(L, CallHook, 1);
			lua_rawset(L, -3);
			lua_pushliteral(L, "__metatable");
			lua_pushliteral(L, "can't touch this");
			lua_rawset(L, -3);
		}
		lua_setmetatable(L, -2); // set the userdata's metatable
	}
	lua_rawset(L, -3);
	return 0;
}


bool LuaInterCall::PushEntriesSynced(lua_State* L)
{
	PushCallHandler(L, LUA_GAIA,  "LuaGaia");
	PushCallHandler(L, LUA_RULES, "LuaRules");
	return true;
}


bool LuaInterCall::PushEntriesUnsynced(lua_State* L)
{
	PushCallHandler(L, LUA_GAIA,  "LuaGaia");
	PushCallHandler(L, LUA_RULES, "LuaRules");
	PushCallHandler(L, LUA_UI,    "LuaUI");
	return true;
}


/******************************************************************************/
/******************************************************************************/