1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "cpp_api/s_player.h"
21 #include "cpp_api/s_internal.h"
22 #include "common/c_converter.h"
23 #include "common/c_content.h"
24 #include "debug.h"
25 #include "inventorymanager.h"
26 #include "lua_api/l_inventory.h"
27 #include "lua_api/l_item.h"
28 #include "util/string.h"
29
on_newplayer(ServerActiveObject * player)30 void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
31 {
32 SCRIPTAPI_PRECHECKHEADER
33
34 // Get core.registered_on_newplayers
35 lua_getglobal(L, "core");
36 lua_getfield(L, -1, "registered_on_newplayers");
37 // Call callbacks
38 objectrefGetOrCreate(L, player);
39 runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
40 }
41
on_dieplayer(ServerActiveObject * player,const PlayerHPChangeReason & reason)42 void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player, const PlayerHPChangeReason &reason)
43 {
44 SCRIPTAPI_PRECHECKHEADER
45
46 // Get callback table
47 lua_getglobal(L, "core");
48 lua_getfield(L, -1, "registered_on_dieplayers");
49
50 // Push arguments
51 objectrefGetOrCreate(L, player);
52 pushPlayerHPChangeReason(L, reason);
53
54 // Run callbacks
55 runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
56 }
57
on_punchplayer(ServerActiveObject * player,ServerActiveObject * hitter,float time_from_last_punch,const ToolCapabilities * toolcap,v3f dir,s16 damage)58 bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
59 ServerActiveObject *hitter,
60 float time_from_last_punch,
61 const ToolCapabilities *toolcap,
62 v3f dir,
63 s16 damage)
64 {
65 SCRIPTAPI_PRECHECKHEADER
66 // Get core.registered_on_punchplayers
67 lua_getglobal(L, "core");
68 lua_getfield(L, -1, "registered_on_punchplayers");
69 // Call callbacks
70 objectrefGetOrCreate(L, player);
71 objectrefGetOrCreate(L, hitter);
72 lua_pushnumber(L, time_from_last_punch);
73 push_tool_capabilities(L, *toolcap);
74 push_v3f(L, dir);
75 lua_pushnumber(L, damage);
76 runCallbacks(6, RUN_CALLBACKS_MODE_OR);
77 return readParam<bool>(L, -1);
78 }
79
on_rightclickplayer(ServerActiveObject * player,ServerActiveObject * clicker)80 void ScriptApiPlayer::on_rightclickplayer(ServerActiveObject *player,
81 ServerActiveObject *clicker)
82 {
83 SCRIPTAPI_PRECHECKHEADER
84 // Get core.registered_on_rightclickplayers
85 lua_getglobal(L, "core");
86 lua_getfield(L, -1, "registered_on_rightclickplayers");
87 // Call callbacks
88 objectrefGetOrCreate(L, player);
89 objectrefGetOrCreate(L, clicker);
90 runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
91 }
92
on_player_hpchange(ServerActiveObject * player,s32 hp_change,const PlayerHPChangeReason & reason)93 s32 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
94 s32 hp_change, const PlayerHPChangeReason &reason)
95 {
96 SCRIPTAPI_PRECHECKHEADER
97
98 int error_handler = PUSH_ERROR_HANDLER(L);
99
100 // Get core.registered_on_player_hpchange
101 lua_getglobal(L, "core");
102 lua_getfield(L, -1, "registered_on_player_hpchange");
103 lua_remove(L, -2);
104
105 // Push arguments
106 objectrefGetOrCreate(L, player);
107 lua_pushnumber(L, hp_change);
108 pushPlayerHPChangeReason(L, reason);
109
110 // Call callbacks
111 PCALL_RES(lua_pcall(L, 3, 1, error_handler));
112 hp_change = lua_tointeger(L, -1);
113 lua_pop(L, 2); // Pop result and error handler
114 return hp_change;
115 }
116
on_respawnplayer(ServerActiveObject * player)117 bool ScriptApiPlayer::on_respawnplayer(ServerActiveObject *player)
118 {
119 SCRIPTAPI_PRECHECKHEADER
120
121 // Get core.registered_on_respawnplayers
122 lua_getglobal(L, "core");
123 lua_getfield(L, -1, "registered_on_respawnplayers");
124 // Call callbacks
125 objectrefGetOrCreate(L, player);
126 runCallbacks(1, RUN_CALLBACKS_MODE_OR);
127 return readParam<bool>(L, -1);
128 }
129
on_prejoinplayer(const std::string & name,const std::string & ip,std::string * reason)130 bool ScriptApiPlayer::on_prejoinplayer(
131 const std::string &name,
132 const std::string &ip,
133 std::string *reason)
134 {
135 SCRIPTAPI_PRECHECKHEADER
136
137 // Get core.registered_on_prejoinplayers
138 lua_getglobal(L, "core");
139 lua_getfield(L, -1, "registered_on_prejoinplayers");
140 lua_pushstring(L, name.c_str());
141 lua_pushstring(L, ip.c_str());
142 runCallbacks(2, RUN_CALLBACKS_MODE_OR);
143 if (lua_isstring(L, -1)) {
144 reason->assign(readParam<std::string>(L, -1));
145 return true;
146 }
147 return false;
148 }
149
can_bypass_userlimit(const std::string & name,const std::string & ip)150 bool ScriptApiPlayer::can_bypass_userlimit(const std::string &name, const std::string &ip)
151 {
152 SCRIPTAPI_PRECHECKHEADER
153
154 // Get core.registered_on_prejoinplayers
155 lua_getglobal(L, "core");
156 lua_getfield(L, -1, "registered_can_bypass_userlimit");
157 lua_pushstring(L, name.c_str());
158 lua_pushstring(L, ip.c_str());
159 runCallbacks(2, RUN_CALLBACKS_MODE_OR);
160 return lua_toboolean(L, -1);
161 }
162
on_joinplayer(ServerActiveObject * player,s64 last_login)163 void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player, s64 last_login)
164 {
165 SCRIPTAPI_PRECHECKHEADER
166
167 // Get core.registered_on_joinplayers
168 lua_getglobal(L, "core");
169 lua_getfield(L, -1, "registered_on_joinplayers");
170 // Call callbacks
171 objectrefGetOrCreate(L, player);
172 if (last_login != -1)
173 lua_pushinteger(L, last_login);
174 else
175 lua_pushnil(L);
176 runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
177 }
178
on_leaveplayer(ServerActiveObject * player,bool timeout)179 void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player,
180 bool timeout)
181 {
182 SCRIPTAPI_PRECHECKHEADER
183
184 // Get core.registered_on_leaveplayers
185 lua_getglobal(L, "core");
186 lua_getfield(L, -1, "registered_on_leaveplayers");
187 // Call callbacks
188 objectrefGetOrCreate(L, player);
189 lua_pushboolean(L, timeout);
190 runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
191 }
192
on_cheat(ServerActiveObject * player,const std::string & cheat_type)193 void ScriptApiPlayer::on_cheat(ServerActiveObject *player,
194 const std::string &cheat_type)
195 {
196 SCRIPTAPI_PRECHECKHEADER
197
198 // Get core.registered_on_cheats
199 lua_getglobal(L, "core");
200 lua_getfield(L, -1, "registered_on_cheats");
201 // Call callbacks
202 objectrefGetOrCreate(L, player);
203 lua_newtable(L);
204 lua_pushlstring(L, cheat_type.c_str(), cheat_type.size());
205 lua_setfield(L, -2, "type");
206 runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
207 }
208
on_playerReceiveFields(ServerActiveObject * player,const std::string & formname,const StringMap & fields)209 void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
210 const std::string &formname,
211 const StringMap &fields)
212 {
213 SCRIPTAPI_PRECHECKHEADER
214
215 // Get core.registered_on_player_receive_fields
216 lua_getglobal(L, "core");
217 lua_getfield(L, -1, "registered_on_player_receive_fields");
218 // Call callbacks
219 // param 1
220 objectrefGetOrCreate(L, player);
221 // param 2
222 lua_pushstring(L, formname.c_str());
223 // param 3
224 lua_newtable(L);
225 StringMap::const_iterator it;
226 for (it = fields.begin(); it != fields.end(); ++it) {
227 const std::string &name = it->first;
228 const std::string &value = it->second;
229 lua_pushstring(L, name.c_str());
230 lua_pushlstring(L, value.c_str(), value.size());
231 lua_settable(L, -3);
232 }
233 runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC);
234 }
235
on_authplayer(const std::string & name,const std::string & ip,bool is_success)236 void ScriptApiPlayer::on_authplayer(const std::string &name, const std::string &ip, bool is_success)
237 {
238 SCRIPTAPI_PRECHECKHEADER
239
240 // Get core.registered_on_authplayers
241 lua_getglobal(L, "core");
242 lua_getfield(L, -1, "registered_on_authplayers");
243
244 // Call callbacks
245 lua_pushstring(L, name.c_str());
246 lua_pushstring(L, ip.c_str());
247 lua_pushboolean(L, is_success);
248 runCallbacks(3, RUN_CALLBACKS_MODE_FIRST);
249 }
250
pushMoveArguments(const MoveAction & ma,int count,ServerActiveObject * player)251 void ScriptApiPlayer::pushMoveArguments(
252 const MoveAction &ma, int count,
253 ServerActiveObject *player)
254 {
255 lua_State *L = getStack();
256 objectrefGetOrCreate(L, player); // player
257 lua_pushstring(L, "move"); // action
258 InvRef::create(L, ma.from_inv); // inventory
259 lua_newtable(L);
260 {
261 // Table containing the action information
262 lua_pushstring(L, ma.from_list.c_str());
263 lua_setfield(L, -2, "from_list");
264 lua_pushstring(L, ma.to_list.c_str());
265 lua_setfield(L, -2, "to_list");
266
267 lua_pushinteger(L, ma.from_i + 1);
268 lua_setfield(L, -2, "from_index");
269 lua_pushinteger(L, ma.to_i + 1);
270 lua_setfield(L, -2, "to_index");
271
272 lua_pushinteger(L, count);
273 lua_setfield(L, -2, "count");
274 }
275 }
276
pushPutTakeArguments(const char * method,const InventoryLocation & loc,const std::string & listname,int index,const ItemStack & stack,ServerActiveObject * player)277 void ScriptApiPlayer::pushPutTakeArguments(
278 const char *method, const InventoryLocation &loc,
279 const std::string &listname, int index, const ItemStack &stack,
280 ServerActiveObject *player)
281 {
282 lua_State *L = getStack();
283 objectrefGetOrCreate(L, player); // player
284 lua_pushstring(L, method); // action
285 InvRef::create(L, loc); // inventory
286 lua_newtable(L);
287 {
288 // Table containing the action information
289 lua_pushstring(L, listname.c_str());
290 lua_setfield(L, -2, "listname");
291
292 lua_pushinteger(L, index + 1);
293 lua_setfield(L, -2, "index");
294
295 LuaItemStack::create(L, stack);
296 lua_setfield(L, -2, "stack");
297 }
298 }
299
300 // Return number of accepted items to be moved
player_inventory_AllowMove(const MoveAction & ma,int count,ServerActiveObject * player)301 int ScriptApiPlayer::player_inventory_AllowMove(
302 const MoveAction &ma, int count,
303 ServerActiveObject *player)
304 {
305 SCRIPTAPI_PRECHECKHEADER
306
307 lua_getglobal(L, "core");
308 lua_getfield(L, -1, "registered_allow_player_inventory_actions");
309 pushMoveArguments(ma, count, player);
310 runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);
311
312 return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : count;
313 }
314
315 // Return number of accepted items to be put
player_inventory_AllowPut(const MoveAction & ma,const ItemStack & stack,ServerActiveObject * player)316 int ScriptApiPlayer::player_inventory_AllowPut(
317 const MoveAction &ma, const ItemStack &stack,
318 ServerActiveObject *player)
319 {
320 SCRIPTAPI_PRECHECKHEADER
321
322 lua_getglobal(L, "core");
323 lua_getfield(L, -1, "registered_allow_player_inventory_actions");
324 pushPutTakeArguments("put", ma.to_inv, ma.to_list, ma.to_i, stack, player);
325 runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);
326
327 return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : stack.count;
328 }
329
330 // Return number of accepted items to be taken
player_inventory_AllowTake(const MoveAction & ma,const ItemStack & stack,ServerActiveObject * player)331 int ScriptApiPlayer::player_inventory_AllowTake(
332 const MoveAction &ma, const ItemStack &stack,
333 ServerActiveObject *player)
334 {
335 SCRIPTAPI_PRECHECKHEADER
336
337 lua_getglobal(L, "core");
338 lua_getfield(L, -1, "registered_allow_player_inventory_actions");
339 pushPutTakeArguments("take", ma.from_inv, ma.from_list, ma.from_i, stack, player);
340 runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);
341
342 return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : stack.count;
343 }
344
345 // Report moved items
player_inventory_OnMove(const MoveAction & ma,int count,ServerActiveObject * player)346 void ScriptApiPlayer::player_inventory_OnMove(
347 const MoveAction &ma, int count,
348 ServerActiveObject *player)
349 {
350 SCRIPTAPI_PRECHECKHEADER
351
352 lua_getglobal(L, "core");
353 lua_getfield(L, -1, "registered_on_player_inventory_actions");
354 pushMoveArguments(ma, count, player);
355 runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
356 }
357
358 // Report put items
player_inventory_OnPut(const MoveAction & ma,const ItemStack & stack,ServerActiveObject * player)359 void ScriptApiPlayer::player_inventory_OnPut(
360 const MoveAction &ma, const ItemStack &stack,
361 ServerActiveObject *player)
362 {
363 SCRIPTAPI_PRECHECKHEADER
364
365 lua_getglobal(L, "core");
366 lua_getfield(L, -1, "registered_on_player_inventory_actions");
367 pushPutTakeArguments("put", ma.to_inv, ma.to_list, ma.to_i, stack, player);
368 runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
369 }
370
371 // Report taken items
player_inventory_OnTake(const MoveAction & ma,const ItemStack & stack,ServerActiveObject * player)372 void ScriptApiPlayer::player_inventory_OnTake(
373 const MoveAction &ma, const ItemStack &stack,
374 ServerActiveObject *player)
375 {
376 SCRIPTAPI_PRECHECKHEADER
377
378 lua_getglobal(L, "core");
379 lua_getfield(L, -1, "registered_on_player_inventory_actions");
380 pushPutTakeArguments("take", ma.from_inv, ma.from_list, ma.from_i, stack, player);
381 runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
382 }
383