#include "settings.h"
#include "profiler.h"
#include "log.h"
-#include "script.h"
-#include "scriptapi.h"
+#include "script/cpp_api/scriptapi.h"
#include "nodedef.h"
#include "itemdef.h"
#include "craftdef.h"
m_simple_singleplayer_mode(simple_singleplayer_mode),
m_async_fatal_error(""),
m_env(NULL),
- m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
+ m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
+ g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
m_rollback(NULL),
m_rollback_sink_enabled(true),
m_enable_rollback_recording(false),
m_emerge(NULL),
- m_biomedef(NULL),
- m_lua(NULL),
+ m_script(NULL),
m_itemdef(createItemDefManager()),
m_nodedef(createNodeDefManager()),
m_craftdef(createCraftDefManager()),
Settings gamedefaults;
getGameMinetestConfig(gamespec.path, gamedefaults);
override_default_settings(g_settings, &gamedefaults);
-
- // Create biome definition manager
- m_biomedef = new BiomeDefManager(this);
// Create emerge manager
- m_emerge = new EmergeManager(this, m_biomedef);
+ m_emerge = new EmergeManager(this);
// Create rollback manager
std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
ModConfiguration modconf(m_path_world);
m_mods = modconf.getMods();
- std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
+ std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
// complain about mods with unsatisfied dependencies
if(!modconf.isConsistent())
{
- for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
+ for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
it != unsatisfied_mods.end(); ++it)
{
ModSpec mod = *it;
std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
worldmt_settings.readConfigFile(worldmt.c_str());
std::vector<std::string> names = worldmt_settings.getNames();
- std::set<std::string> exclude_mod_names;
std::set<std::string> load_mod_names;
for(std::vector<std::string>::iterator it = names.begin();
it != names.end(); ++it)
{
std::string name = *it;
- if (name.compare(0,9,"load_mod_")==0)
- {
- if(worldmt_settings.getBool(name))
- load_mod_names.insert(name.substr(9));
- else
- exclude_mod_names.insert(name.substr(9));
- }
+ if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
+ load_mod_names.insert(name.substr(9));
}
// complain about mods declared to be loaded, but not found
for(std::vector<ModSpec>::iterator it = m_mods.begin();
it != m_mods.end(); ++it)
load_mod_names.erase((*it).name);
- for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
+ for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
it != unsatisfied_mods.end(); ++it)
load_mod_names.erase((*it).name);
if(!load_mod_names.empty())
// Initialize scripting
infostream<<"Server: Initializing Lua"<<std::endl;
- m_lua = script_init();
- assert(m_lua);
- // Export API
- scriptapi_export(m_lua, this);
+
+ m_script = new ScriptApi(this);
+
+
// Load and run builtin.lua
infostream<<"Server: Loading builtin.lua [\""
<<builtinpath<<"\"]"<<std::endl;
- bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
+ bool success = m_script->loadMod(builtinpath, "__builtin");
if(!success){
errorstream<<"Server: Failed to load and run "
<<builtinpath<<std::endl;
std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
<<scriptpath<<"\"]"<<std::endl;
- bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
+ bool success = m_script->loadMod(scriptpath, mod.name);
if(!success){
errorstream<<"Server: Failed to load and run "
<<scriptpath<<std::endl;
// Apply item aliases in the node definition manager
m_nodedef->updateAliases(m_itemdef);
- // Add default biomes after nodedef had its aliases added
- m_biomedef->addDefaultBiomes();
-
// Initialize Environment
ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
- m_env = new ServerEnvironment(servermap, m_lua, this, this);
+ m_env = new ServerEnvironment(servermap, m_script, this, this);
+
+ // Run some callbacks after the MG params have been set up but before activation
+ MapgenParams *mgparams = servermap->getMapgenParams();
+ m_script->environment_OnMapgenInit(mgparams);
- m_emerge->initMapgens(servermap->getMapgenParams());
+ // Initialize mapgens
+ m_emerge->initMapgens(mgparams);
// Give environment reference to scripting api
- scriptapi_add_environment(m_lua, m_env);
+ m_script->initializeEnvironment(m_env);
// Register us to receive map edit events
servermap->addEventReceiver(this);
/*
Execute script shutdown hooks
*/
- scriptapi_on_shutdown(m_lua);
+ m_script->on_shutdown();
}
{
*/
stop();
+ //shutdown all emerge threads first!
+ delete m_emerge;
+
/*
Delete clients
*/
// Delete things in the reverse order of creation
delete m_env;
delete m_rollback;
- delete m_emerge;
delete m_event;
delete m_itemdef;
delete m_nodedef;
// Deinitialize scripting
infostream<<"Server: Deinitializing scripting"<<std::endl;
- script_deinit(m_lua);
+ delete m_script;
// Delete detached inventories
{
SendPlayerHP(client->peer_id);
}
+ /*
+ Send player breath if changed
+ */
+ if(playersao->m_breath_not_sent){
+ SendPlayerBreath(client->peer_id);
+ }
+
/*
Send player inventories if necessary
*/
float &counter = m_masterserver_timer;
if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
{
- ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
+ ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
counter = 0.01;
}
counter += dtime;
return;
}
+ if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
+ {
+ actionstream<<"Server: Player with an invalid name "
+ <<"tried to connect from "<<addr_s<<std::endl;
+ SendAccessDenied(m_con, peer_id,
+ L"Name is not allowed");
+ return;
+ }
+
infostream<<"Server: New connection: \""<<playername<<"\" from "
<<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
}
std::string checkpwd; // Password hash to check against
- bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
+ bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
// If no authentication info exists for user, create it
if(!has_auth){
if (raw_default_password.length() == 0)
initial_password = given_password;
- scriptapi_create_auth(m_lua, playername, initial_password);
+ m_script->createAuth(playername, initial_password);
}
- has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
+ has_auth = m_script->getAuth(playername, &checkpwd, NULL);
if(!has_auth){
SendAccessDenied(m_con, peer_id, L"Not allowed to login");
SendMovement(m_con, peer_id);
// Send item definitions
- SendItemDef(m_con, peer_id, m_itemdef);
+ SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
// Send node definitions
SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
if(g_settings->getBool("enable_damage"))
SendPlayerHP(peer_id);
+ // Send Breath
+ SendPlayerBreath(peer_id);
+
// Send detached inventories
sendDetachedInventories(peer_id);
os<<player->getName()<<" ";
}
- actionstream<<player->getName()<<" joins game. List of players: "
+ actionstream<<player->getName()<<" ["<<addr_s<<"] "<<" joins game. List of players: "
<<os.str()<<std::endl;
}
setInventoryModified(da->from_inv);
+ /*
+ Disable dropping items out of craftpreview
+ */
+ if(da->from_list == "craftpreview")
+ {
+ infostream<<"Ignoring IDropAction from "
+ <<(da->from_inv.dump())<<":"<<da->from_list
+ <<" because src is "<<da->from_list<<std::endl;
+ delete a;
+ return;
+ }
+
// Disallow dropping items if not allowed to interact
if(!checkPriv(player->getName(), "interact"))
{
std::wstring name = narrow_to_wide(player->getName());
// Run script hook
- bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
+ bool ate = m_script->on_chat_message(player->getName(),
wide_to_narrow(message));
// If script ate the message, don't proceed
if(ate)
SendPlayerHP(peer_id);
}
}
+ else if(command == TOSERVER_BREATH)
+ {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+ u16 breath = readU16(is);
+ playersao->setBreath(breath);
+ }
else if(command == TOSERVER_PASSWORD)
{
/*
std::string playername = player->getName();
std::string checkpwd;
- scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
+ m_script->getAuth(playername, &checkpwd, NULL);
if(oldpwd != checkpwd)
{
return;
}
- bool success = scriptapi_set_password(m_lua, playername, newpwd);
+ bool success = m_script->setPassword(playername, newpwd);
if(success){
actionstream<<player->getName()<<" changes password"<<std::endl;
SendChatMessage(peer_id, L"Password change successful.");
m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
}
if(n.getContent() != CONTENT_IGNORE)
- scriptapi_node_on_punch(m_lua, p_under, n, playersao);
+ m_script->node_on_punch(p_under, n, playersao);
// Cheat prevention
playersao->noCheatDigStart(p_under);
}
/* Actually dig node */
if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
- scriptapi_node_on_dig(m_lua, p_under, n, playersao);
+ m_script->node_on_dig(p_under, n, playersao);
// Send unusual result (that is, node not being removed)
if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
// Do stuff
pointed_object->rightClick(playersao);
}
- else if(scriptapi_item_on_place(m_lua,
+ else if(m_script->item_OnPlace(
item, playersao, pointed))
{
// Placement was handled in lua
playersao->setWieldedItem(item);
}
- // If item has node placement prediction, always send the above
- // node to make sure the client knows what exactly happened
+ // If item has node placement prediction, always send the
+ // blocks to make sure the client knows what exactly happened
if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
RemoteClient *client = getClient(peer_id);
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
client->SetBlockNotSent(blockpos);
+ v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
+ if(blockpos2 != blockpos){
+ client->SetBlockNotSent(blockpos2);
+ }
}
} // action == 3
actionstream<<player->getName()<<" uses "<<item.name
<<", pointing at "<<pointed.dump()<<std::endl;
- if(scriptapi_item_on_use(m_lua,
+ if(m_script->item_OnUse(
item, playersao, pointed))
{
// Apply returned ItemStack
// Check the target node for rollback data; leave others unnoticed
RollbackNode rn_old(&m_env->getMap(), p, this);
- scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
- playersao);
+ m_script->node_on_receive_fields(p, formname, fields,playersao);
// Report rollback data
RollbackNode rn_new(&m_env->getMap(), p, this);
fields[fieldname] = fieldvalue;
}
- scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
+ m_script->on_playerReceiveFields(playersao, formname, fields);
}
else
{
}
}
-std::list<PlayerInfo> Server::getPlayerInfo()
-{
- DSTACK(__FUNCTION_NAME);
- JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
-
- std::list<PlayerInfo> list;
-
- std::list<Player*> players = m_env->getPlayers();
-
- std::list<Player*>::iterator i;
- for(i = players.begin();
- i != players.end(); ++i)
- {
- PlayerInfo info;
-
- Player *player = *i;
-
- try{
- // Copy info from connection to info struct
- info.id = player->peer_id;
- info.address = m_con.GetPeerAddress(player->peer_id);
- info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
- }
- catch(con::PeerNotFoundException &e)
- {
- // Set dummy peer info
- info.id = 0;
- info.address = Address(0,0,0,0,0);
- info.avg_rtt = 0.0;
- }
-
- snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
- info.position = player->getPosition();
-
- list.push_back(info);
- }
-
- return list;
-}
+//std::list<PlayerInfo> Server::getPlayerInfo()
+//{
+// DSTACK(__FUNCTION_NAME);
+// JMutexAutoLock envlock(m_env_mutex);
+// JMutexAutoLock conlock(m_con_mutex);
+//
+// std::list<PlayerInfo> list;
+//
+// std::list<Player*> players = m_env->getPlayers();
+//
+// std::list<Player*>::iterator i;
+// for(i = players.begin();
+// i != players.end(); ++i)
+// {
+// PlayerInfo info;
+//
+// Player *player = *i;
+//
+// try{
+// // Copy info from connection to info struct
+// info.id = player->peer_id;
+// info.address = m_con.GetPeerAddress(player->peer_id);
+// info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
+// }
+// catch(con::PeerNotFoundException &e)
+// {
+// // Set dummy peer info
+// info.id = 0;
+// info.address = Address(0,0,0,0,0);
+// info.avg_rtt = 0.0;
+// }
+//
+// snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
+// info.position = player->getPosition();
+//
+// list.push_back(info);
+// }
+//
+// return list;
+//}
void Server::peerAdded(con::Peer *peer)
con.Send(peer_id, 0, data, true);
}
+void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
+{
+ DSTACK(__FUNCTION_NAME);
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOCLIENT_BREATH);
+ writeU16(os, breath);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ con.Send(peer_id, 0, data, true);
+}
+
void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
const std::wstring &reason)
{
}
void Server::SendItemDef(con::Connection &con, u16 peer_id,
- IItemDefManager *itemdef)
+ IItemDefManager *itemdef, u16 protocol_version)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
*/
writeU16(os, TOCLIENT_ITEMDEF);
std::ostringstream tmp_os(std::ios::binary);
- itemdef->serialize(tmp_os);
+ itemdef->serialize(tmp_os, protocol_version);
std::ostringstream tmp_os2(std::ios::binary);
compressZlib(tmp_os.str(), tmp_os2);
os<<serializeLongString(tmp_os2.str());
// Send as reliable
m_con.Send(peer_id, 0, data, true);
}
-void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
+
+void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
+ const std::string formname)
{
DSTACK(__FUNCTION_NAME);
}
// Spawns a particle on peer with peer_id
-void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
+void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
+ float expirationtime, float size, bool collisiondetection,
+ std::string texture)
{
DSTACK(__FUNCTION_NAME);
}
// Spawns a particle on all peers
-void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
+void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
+ float expirationtime, float size, bool collisiondetection,
+ std::string texture)
{
for(std::map<u16, RemoteClient*>::iterator
i = m_clients.begin();
}
}
+void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
+{
+ std::ostringstream os(std::ios_base::binary);
+
+ // Write command
+ writeU16(os, TOCLIENT_HUDADD);
+ writeU32(os, id);
+ writeU8(os, (u8)form->type);
+ writeV2F1000(os, form->pos);
+ os << serializeString(form->name);
+ writeV2F1000(os, form->scale);
+ os << serializeString(form->text);
+ writeU32(os, form->number);
+ writeU32(os, form->item);
+ writeU32(os, form->dir);
+ writeV2F1000(os, form->align);
+ writeV2F1000(os, form->offset);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendHUDRemove(u16 peer_id, u32 id)
+{
+ std::ostringstream os(std::ios_base::binary);
+
+ // Write command
+ writeU16(os, TOCLIENT_HUDRM);
+ writeU32(os, id);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
+{
+ std::ostringstream os(std::ios_base::binary);
+
+ // Write command
+ writeU16(os, TOCLIENT_HUDCHANGE);
+ writeU32(os, id);
+ writeU8(os, (u8)stat);
+ switch (stat) {
+ case HUD_STAT_POS:
+ case HUD_STAT_SCALE:
+ case HUD_STAT_ALIGN:
+ case HUD_STAT_OFFSET:
+ writeV2F1000(os, *(v2f *)value);
+ break;
+ case HUD_STAT_NAME:
+ case HUD_STAT_TEXT:
+ os << serializeString(*(std::string *)value);
+ break;
+ case HUD_STAT_NUMBER:
+ case HUD_STAT_ITEM:
+ case HUD_STAT_DIR:
+ default:
+ writeU32(os, *(u32 *)value);
+ break;
+ }
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
+{
+ std::ostringstream os(std::ios_base::binary);
+
+ // Write command
+ writeU16(os, TOCLIENT_HUD_SET_FLAGS);
+ writeU32(os, flags);
+ writeU32(os, mask);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
+{
+ std::ostringstream os(std::ios_base::binary);
+
+ // Write command
+ writeU16(os, TOCLIENT_HUD_SET_PARAM);
+ writeU16(os, param);
+ os<<serializeString(value);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
void Server::BroadcastChatMessage(const std::wstring &message)
{
for(std::map<u16, RemoteClient*>::iterator
SendHP(m_con, peer_id, playersao->getHP());
}
+void Server::SendPlayerBreath(u16 peer_id)
+{
+ DSTACK(__FUNCTION_NAME);
+ PlayerSAO *playersao = getPlayerSAO(peer_id);
+ assert(playersao);
+ playersao->m_breath_not_sent = false;
+ SendBreath(m_con, peer_id, playersao->getBreath());
+}
+
void Server::SendMovePlayer(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
return;
std::set<std::string> privs;
- scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
+ m_script->getAuth(player->getName(), NULL, &privs);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_PRIVILEGES);
playersao->setHP(0);
// Trigger scripted stuff
- scriptapi_on_dieplayer(m_lua, playersao);
+ m_script->on_dieplayer(playersao);
SendPlayerHP(peer_id);
SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
playersao->setHP(PLAYER_MAX_HP);
- bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
+ bool repositioned = m_script->on_respawnplayer(playersao);
if(!repositioned){
v3f pos = findSpawnPos(m_env->getServerMap());
playersao->setPos(pos);
std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
{
std::set<std::string> privs;
- scriptapi_get_auth(m_lua, name, NULL, &privs);
+ m_script->getAuth(name, NULL, &privs);
return privs;
}
g_settings->updateConfigFile(m_path_config.c_str());
}
-void Server::notifyPlayer(const char *name, const std::wstring msg)
+void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
{
Player *player = m_env->getPlayer(name);
if(!player)
return;
- SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
+ if (prepend)
+ SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
+ else
+ SendChatMessage(player->peer_id, msg);
}
bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
return true;
}
+u32 Server::hudAdd(Player *player, HudElement *form) {
+ if (!player)
+ return -1;
+
+ u32 id = hud_get_free_id(player);
+ if (id < player->hud.size())
+ player->hud[id] = form;
+ else
+ player->hud.push_back(form);
+
+ SendHUDAdd(player->peer_id, id, form);
+ return id;
+}
+
+bool Server::hudRemove(Player *player, u32 id) {
+ if (!player || id >= player->hud.size() || !player->hud[id])
+ return false;
+
+ delete player->hud[id];
+ player->hud[id] = NULL;
+
+ SendHUDRemove(player->peer_id, id);
+ return true;
+}
+
+bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
+ if (!player)
+ return false;
+
+ SendHUDChange(player->peer_id, id, stat, data);
+ return true;
+}
+
+bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
+ if (!player)
+ return false;
+
+ SendHUDSetFlags(player->peer_id, flags, mask);
+ return true;
+}
+
+bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
+ if (!player)
+ return false;
+ if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
+ return false;
+
+ std::ostringstream os(std::ios::binary);
+ writeS32(os, hotbar_itemcount);
+ SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
+ return true;
+}
+
void Server::notifyPlayers(const std::wstring msg)
{
BroadcastChatMessage(msg);
{
s32 range = 1 + i;
// We're going to try to throw the player to this position
- v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
- -range + (myrand()%(range*2)));
- //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
- // Get ground height at point (fallbacks to heightmap function)
+ v2s16 nodepos2d = v2s16(
+ -range + (myrand() % (range * 2)),
+ -range + (myrand() % (range * 2)));
+
+ // Get ground height at point
s16 groundheight = map.findGroundLevel(nodepos2d);
- // Don't go underwater
- if(groundheight <= water_level)
- {
- //infostream<<"-> Underwater"<<std::endl;
+ if (groundheight <= water_level) // Don't go underwater
continue;
- }
- // Don't go to high places
- if(groundheight > water_level + 6)
- {
- //infostream<<"-> Underwater"<<std::endl;
+ if (groundheight > water_level + 6) // Don't go to high places
continue;
- }
- nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
+ nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
bool is_good = false;
s32 air_count = 0;
- for(s32 i=0; i<10; i++){
+ for (s32 i = 0; i < 10; i++) {
v3s16 blockpos = getNodeBlockPos(nodepos);
map.emergeBlock(blockpos, true);
- MapNode n = map.getNodeNoEx(nodepos);
- if(n.getContent() == CONTENT_AIR){
+ content_t c = map.getNodeNoEx(nodepos).getContent();
+ if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
air_count++;
- if(air_count >= 2){
+ if (air_count >= 2){
is_good = true;
- nodepos.Y -= 1;
break;
}
}
getPlayerEffectivePrivs(player->getName()),
isSingleplayer());
+ /* Clean up old HUD elements from previous sessions */
+ player->hud.clear();
+
/* Add object to environment */
m_env->addActiveObject(playersao);
/* Run scripts */
if(newplayer)
- scriptapi_on_newplayer(m_lua, playersao);
+ m_script->on_newplayer(playersao);
- scriptapi_on_joinplayer(m_lua, playersao);
+ m_script->on_joinplayer(playersao);
return playersao;
}
PlayerSAO *playersao = player->getPlayerSAO();
assert(playersao);
- scriptapi_on_leaveplayer(m_lua, playersao);
+ m_script->on_leaveplayer(playersao);
playersao->disconnected();
}