summaryrefslogtreecommitdiff
path: root/src/mods.h
Commit message (Expand)AuthorAge
* Fix addModsFormConfig typo (#6420)Greg2017-09-16
* Modernize various files (src/m*) (#6267)Loïc Blot2017-08-18
* C++ modernize: Pragma once (#6264)Loïc Blot2017-08-17
* Remove remaining modstore code (#6120)Elijah Duffy2017-07-14
* Cpp11 patchset 11: continue working on constructor style migration (#6004)Loïc Blot2017-06-18
* C++11 patchset 2: remove util/cpp11.h and util/cpp11_container.h (#5821)Loïc Blot2017-06-04
* Real control fix (#5787)Loïc Blot2017-05-20
* Fix various variables passed by copy instead of const ref (#5610)Loïc Blot2017-04-19
* [CSM] implement client side mod loading (#5123)Loïc Blot2017-03-13
* Add ModMetadata API (#5131)Loïc Blot2017-02-08
* Fixes for compiling with a newer (system) jsoncpp (#4429)Rogier-52016-08-10
* Fix server crashing on Lua errorsShadowNinja2015-10-31
* Remove ugly curl struct pointer from jsonFetchValue signaturesapier2014-06-19
* Pass arguments by referenceSelat2014-03-12
* Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenuKahrl2013-08-14
* Add support for modstore screenshotssapier2013-07-22
* Replace C++ mainmenu by formspec powered onesapier2013-07-02
* Optional dependencies and properly handle mod name conflicts againKahrl2013-05-03
* Migrate to STL containers/algorithms.Ilya Zhuravlev2013-03-11
* Update Copyright YearsSfan52013-02-24
* Change Minetest-c55 to MinetestPilzAdam2013-02-24
* Improve behaviour for empty modpacks and when no mods at all are installed:Jürgen Doser2013-01-22
* Basic support for configuring which mods to load for each worldJürgen Doser2013-01-21
* Optimize headersPerttu Ahola2012-06-17
* Switch the license to be LGPLv2/later, with small parts still remaining as GP...Perttu Ahola2012-06-05
* Add minetest.get_modpath(modname)Perttu Ahola2011-12-11
* Better mod loading error handlingPerttu Ahola2011-12-03
'n233' href='#n233'>233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "cpp_api/s_player.h"
#include "cpp_api/s_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "debug.h"
#include "inventorymanager.h"
#include "lua_api/l_inventory.h"
#include "lua_api/l_item.h"
#include "util/string.h"

void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_newplayers
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_newplayers");
	// Call callbacks
	objectrefGetOrCreate(L, player);
	runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}

void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player, const PlayerHPChangeReason &reason)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get callback table
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_dieplayers");

	// Push arguments
	objectrefGetOrCreate(L, player);
	pushPlayerHPChangeReason(L, reason);

	// Run callbacks
	runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
}

bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
		ServerActiveObject *hitter,
		float time_from_last_punch,
		const ToolCapabilities *toolcap,
		v3f dir,
		s16 damage)
{
	SCRIPTAPI_PRECHECKHEADER
	// Get core.registered_on_punchplayers
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_punchplayers");
	// Call callbacks
	objectrefGetOrCreate(L, player);
	objectrefGetOrCreate(L, hitter);
	lua_pushnumber(L, time_from_last_punch);
	push_tool_capabilities(L, *toolcap);
	push_v3f(L, dir);
	lua_pushnumber(L, damage);
	runCallbacks(6, RUN_CALLBACKS_MODE_OR);
	return readParam<bool>(L, -1);
}

s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
	s16 hp_change, const PlayerHPChangeReason &reason)
{
	SCRIPTAPI_PRECHECKHEADER

	int error_handler = PUSH_ERROR_HANDLER(L);

	// Get core.registered_on_player_hpchange
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_player_hpchange");
	lua_remove(L, -2);

	// Push arguments
	objectrefGetOrCreate(L, player);
	lua_pushnumber(L, hp_change);
	pushPlayerHPChangeReason(L, reason);

	// Call callbacks
	PCALL_RES(lua_pcall(L, 3, 1, error_handler));
	hp_change = lua_tointeger(L, -1);
	lua_pop(L, 2); // Pop result and error handler
	return hp_change;
}

bool ScriptApiPlayer::on_respawnplayer(ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_respawnplayers
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_respawnplayers");
	// Call callbacks
	objectrefGetOrCreate(L, player);
	runCallbacks(1, RUN_CALLBACKS_MODE_OR);
	return readParam<bool>(L, -1);
}

bool ScriptApiPlayer::on_prejoinplayer(
	const std::string &name,
	const std::string &ip,
	std::string *reason)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_prejoinplayers
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_prejoinplayers");
	lua_pushstring(L, name.c_str());
	lua_pushstring(L, ip.c_str());
	runCallbacks(2, RUN_CALLBACKS_MODE_OR);
	if (lua_isstring(L, -1)) {
		reason->assign(readParam<std::string>(L, -1));
		return true;
	}
	return false;
}

bool ScriptApiPlayer::can_bypass_userlimit(const std::string &name, const std::string &ip)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_prejoinplayers
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_can_bypass_userlimit");
	lua_pushstring(L, name.c_str());
	lua_pushstring(L, ip.c_str());
	runCallbacks(2, RUN_CALLBACKS_MODE_OR);
	return lua_toboolean(L, -1);
}

void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_joinplayers
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_joinplayers");
	// Call callbacks
	objectrefGetOrCreate(L, player);
	runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}

void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player,
		bool timeout)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_leaveplayers
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_leaveplayers");
	// Call callbacks
	objectrefGetOrCreate(L, player);
	lua_pushboolean(L, timeout);
	runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
}

void ScriptApiPlayer::on_cheat(ServerActiveObject *player,
		const std::string &cheat_type)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_cheats
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_cheats");
	// Call callbacks
	objectrefGetOrCreate(L, player);
	lua_newtable(L);
	lua_pushlstring(L, cheat_type.c_str(), cheat_type.size());
	lua_setfield(L, -2, "type");
	runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
}

void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
		const std::string &formname,
		const StringMap &fields)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_player_receive_fields
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_player_receive_fields");
	// Call callbacks
	// param 1
	objectrefGetOrCreate(L, player);
	// param 2
	lua_pushstring(L, formname.c_str());
	// param 3
	lua_newtable(L);
	StringMap::const_iterator it;
	for (it = fields.begin(); it != fields.end(); ++it) {
		const std::string &name = it->first;
		const std::string &value = it->second;
		lua_pushstring(L, name.c_str());
		lua_pushlstring(L, value.c_str(), value.size());
		lua_settable(L, -3);
	}
	runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC);
}

void ScriptApiPlayer::on_auth_failure(const std::string &name, const std::string &ip)
{
	SCRIPTAPI_PRECHECKHEADER

	// Get core.registered_on_auth_failure
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_auth_fail");
	lua_pushstring(L, name.c_str());
	lua_pushstring(L, ip.c_str());
	runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
}

void ScriptApiPlayer::pushMoveArguments(
		const MoveAction &ma, int count,
		ServerActiveObject *player)
{
	lua_State *L = getStack();
	objectrefGetOrCreate(L, player); // player
	lua_pushstring(L, "move");       // action
	InvRef::create(L, ma.from_inv);  // inventory
	lua_newtable(L);
	{
		// Table containing the action information
		lua_pushstring(L, ma.from_list.c_str());
		lua_setfield(L, -2, "from_list");
		lua_pushstring(L, ma.to_list.c_str());
		lua_setfield(L, -2, "to_list");

		lua_pushinteger(L, ma.from_i + 1);
		lua_setfield(L, -2, "from_index");
		lua_pushinteger(L, ma.to_i + 1);
		lua_setfield(L, -2, "to_index");

		lua_pushinteger(L, count);
		lua_setfield(L, -2, "count");
	}
}

void ScriptApiPlayer::pushPutTakeArguments(
		const char *method, const InventoryLocation &loc,
		const std::string &listname, int index, const ItemStack &stack,
		ServerActiveObject *player)
{
	lua_State *L = getStack();
	objectrefGetOrCreate(L, player); // player
	lua_pushstring(L, method);       // action
	InvRef::create(L, loc);          // inventory
	lua_newtable(L);
	{
		// Table containing the action information
		lua_pushstring(L, listname.c_str());
		lua_setfield(L, -2, "listname");

		lua_pushinteger(L, index + 1);
		lua_setfield(L, -2, "index");

		LuaItemStack::create(L, stack);
		lua_setfield(L, -2, "stack");
	}
}

// Return number of accepted items to be moved
int ScriptApiPlayer::player_inventory_AllowMove(
		const MoveAction &ma, int count,
		ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_allow_player_inventory_actions");
	pushMoveArguments(ma, count, player);
	runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);

	return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : count;
}

// Return number of accepted items to be put
int ScriptApiPlayer::player_inventory_AllowPut(
		const MoveAction &ma, const ItemStack &stack,
		ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_allow_player_inventory_actions");
	pushPutTakeArguments("put", ma.to_inv, ma.to_list, ma.to_i, stack, player);
	runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);

	return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : stack.count;
}

// Return number of accepted items to be taken
int ScriptApiPlayer::player_inventory_AllowTake(
		const MoveAction &ma, const ItemStack &stack,
		ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_allow_player_inventory_actions");
	pushPutTakeArguments("take", ma.from_inv, ma.from_list, ma.from_i, stack, player);
	runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);

	return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : stack.count;
}

// Report moved items
void ScriptApiPlayer::player_inventory_OnMove(
		const MoveAction &ma, int count,
		ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_player_inventory_actions");
	pushMoveArguments(ma, count, player);
	runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
}

// Report put items
void ScriptApiPlayer::player_inventory_OnPut(
		const MoveAction &ma, const ItemStack &stack,
		ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_player_inventory_actions");
	pushPutTakeArguments("put", ma.to_inv, ma.to_list, ma.to_i, stack, player);
	runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
}

// Report taken items
void ScriptApiPlayer::player_inventory_OnTake(
		const MoveAction &ma, const ItemStack &stack,
		ServerActiveObject *player)
{
	SCRIPTAPI_PRECHECKHEADER

	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_on_player_inventory_actions");
	pushPutTakeArguments("take", ma.from_inv, ma.from_list, ma.from_i, stack, player);
	runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
}