#include "settings.h"
#include "profiler.h"
#include "log.h"
-#include "serverscripting.h"
+#include "scripting_server.h"
#include "nodedef.h"
#include "itemdef.h"
#include "craftdef.h"
#include "util/base64.h"
#include "util/sha1.h"
#include "util/hex.h"
+#include "database.h"
class ClientNotFoundException : public BaseException
{
const SubgameSpec &gamespec,
bool simple_singleplayer_mode,
bool ipv6,
+ bool dedicated,
ChatInterface *iface
):
m_path_world(path_world),
m_gamespec(gamespec),
m_simple_singleplayer_mode(simple_singleplayer_mode),
+ m_dedicated(dedicated),
m_async_fatal_error(""),
m_env(NULL),
m_con(PROTOCOL_ID,
m_clients(&m_con),
m_shutdown_requested(false),
m_shutdown_ask_reconnect(false),
+ m_shutdown_timer(0.0f),
m_admin_chat(iface),
m_ignore_map_edit_events(false),
m_ignore_map_edit_events_peer_id(0),
ScopeProfiler sp(g_profiler, "Server: liquid transform");
std::map<v3s16, MapBlock*> modified_blocks;
- m_env->getMap().transformLiquids(modified_blocks);
+ m_env->getMap().transformLiquids(modified_blocks, m_env);
#if 0
/*
Update lighting
// send masterserver announce
{
float &counter = m_masterserver_timer;
- if(!isSingleplayer() && (!counter || counter >= 300.0) &&
- g_settings->getBool("server_announce"))
- {
- ServerList::sendAnnounce(counter ? "update" : "start",
+ if (!isSingleplayer() && (!counter || counter >= 300.0) &&
+ g_settings->getBool("server_announce")) {
+ ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
+ ServerList::AA_START,
m_bind_addr.getPort(),
m_clients.getPlayerNames(),
m_uptime.get(),
m_lag,
m_gamespec.id,
Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
- m_mods);
+ m_mods,
+ m_dedicated);
counter = 0.01;
}
counter += dtime;
m_env->saveMeta();
}
}
+
+ // Timed shutdown
+ static const float shutdown_msg_times[] =
+ {
+ 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
+ };
+
+ if (m_shutdown_timer > 0.0f) {
+ // Automated messages
+ if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
+ for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
+ // If shutdown timer matches an automessage, shot it
+ if (m_shutdown_timer > shutdown_msg_times[i] &&
+ m_shutdown_timer - dtime < shutdown_msg_times[i]) {
+ std::wstringstream ws;
+
+ ws << L"*** Server shutting down in "
+ << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
+ << ".";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ break;
+ }
+ }
+ }
+
+ m_shutdown_timer -= dtime;
+ if (m_shutdown_timer < 0.0f) {
+ m_shutdown_timer = 0.0f;
+ m_shutdown_requested = true;
+ }
+ }
}
void Server::Receive()
// Send inventory
SendInventory(playersao);
- // Send HP
- SendPlayerHPOrDie(playersao);
+ // Send HP or death screen
+ if (playersao->isDead())
+ SendDeathscreen(peer_id, false, v3f(0,0,0));
+ else
+ SendPlayerHPOrDie(playersao);
// Send Breath
SendPlayerBreath(playersao);
- // Show death screen if necessary
- if (playersao->isDead())
- SendDeathscreen(peer_id, false, v3f(0,0,0));
-
// Note things in chat if not in simple singleplayer mode
if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
// Send information about server to player in chat
Send(&pkt);
}
else {
- m_clients.sendToAll(0, &pkt, true);
+ m_clients.sendToAll(&pkt);
}
}
Send(&pkt);
}
else {
- m_clients.sendToAll(0, &pkt, true);
+ m_clients.sendToAll(&pkt);
}
}
pkt << time << time_speed;
if (peer_id == PEER_ID_INEXISTENT) {
- m_clients.sendToAll(0, &pkt, true);
+ m_clients.sendToAll(&pkt);
}
else {
Send(&pkt);
if (client != 0) {
pkt << p << n.param0 << n.param1 << n.param2
<< (u8) (remove_metadata ? 0 : 1);
-
- if (!remove_metadata) {
- if (client->net_proto_version <= 21) {
- // Old clients always clear metadata; fix it
- // by sending the full block again.
- client->SetBlockNotSent(getNodeBlockPos(p));
- }
- }
}
m_clients.unlock();
std::ostringstream os(std::ios_base::binary);
block->serialize(os, ver, false);
- block->serializeNetworkSpecific(os, net_proto_version);
+ block->serializeNetworkSpecific(os);
std::string s = os.str();
NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
const std::string &check = m_detached_inventories_player[name];
if (peer_id == PEER_ID_INEXISTENT) {
if (check == "")
- return m_clients.sendToAll(0, &pkt, true);
+ return m_clients.sendToAll(&pkt);
RemotePlayer *p = m_env->getPlayer(check.c_str());
if (p)
m_clients.send(p->peer_id, 0, &pkt, true);
bool repositioned = m_script->on_respawnplayer(playersao);
if (!repositioned) {
- v3f pos = findSpawnPos();
// setPos will send the new position to client
- playersao->setPos(pos);
+ playersao->setPos(findSpawnPos());
}
SendPlayerHP(peer_id);
// Whether to send line to the player that sent the message, or to all players
bool broadcast_line = true;
- // Commands are implemented in Lua, so only catch invalid
- // commands that were not "eaten" and send an error back
- if (wmessage[0] == L'/') {
- std::wstring wcmd = wmessage.substr(1);
+ if (check_shout_priv && !checkPriv(name, "shout")) {
+ line += L"-!- You don't have permission to shout.";
broadcast_line = false;
- if (wcmd.length() == 0)
- line += L"-!- Empty command";
- else
- line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
} else {
- if (check_shout_priv && !checkPriv(name, "shout")) {
- line += L"-!- You don't have permission to shout.";
- broadcast_line = false;
- } else {
- line += L"<";
- line += wname;
- line += L"> ";
- line += wmessage;
- }
+ line += L"<";
+ line += wname;
+ line += L"> ";
+ line += wmessage;
}
/*
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)));
+ -range + (myrand() % (range * 2)),
+ -range + (myrand() % (range * 2)));
// Get spawn level at point
s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
return nodeposf;
}
-PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
+void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
{
- bool newplayer = false;
+ m_shutdown_timer = delay;
+ m_shutdown_msg = msg;
+ m_shutdown_ask_reconnect = reconnect;
+ if (delay == 0.0f) {
+ // No delay, shutdown immediately
+ m_shutdown_requested = true;
+ // only print to the infostream, a chat message saying
+ // "Server Shutting Down" is sent when the server destructs.
+ infostream << "*** Immediate Server shutdown requested." << std::endl;
+ } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
+ // Negative delay, cancel shutdown if requested
+ m_shutdown_timer = 0.0f;
+ m_shutdown_msg = "";
+ m_shutdown_ask_reconnect = false;
+ m_shutdown_requested = false;
+ std::wstringstream ws;
+
+ ws << L"*** Server shutdown canceled.";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ } else if (delay > 0.0f) {
+ // Positive delay, tell the clients when the server will shut down
+ std::wstringstream ws;
+
+ ws << L"*** Server shutting down in "
+ << duration_to_string(myround(m_shutdown_timer)).c_str()
+ << ".";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ }
+}
+
+PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
+{
/*
Try to get an existing player
*/
return NULL;
}
- // Create a new player active object
- PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
- player = m_env->loadPlayer(name, playersao);
-
- // Create player if it doesn't exist
if (!player) {
- newplayer = true;
- player = new RemotePlayer(name, this->idef());
- // Set player position
- infostream<<"Server: Finding spawn place for player \""
- <<name<<"\""<<std::endl;
- playersao->setBasePosition(findSpawnPos());
-
- // Make sure the player is saved
- player->setModified(true);
-
- // Add player to environment
- m_env->addPlayer(player);
- } else {
- // If the player exists, ensure that they respawn inside legal bounds
- // This fixes an assert crash when the player can't be added
- // to the environment
- if (objectpos_over_limit(playersao->getBasePosition())) {
- actionstream << "Respawn position for player \""
- << name << "\" outside limits, resetting" << std::endl;
- playersao->setBasePosition(findSpawnPos());
- }
+ player = new RemotePlayer(name, idef());
}
- playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
-
- player->protocol_version = proto_version;
+ bool newplayer = false;
- /* Clean up old HUD elements from previous sessions */
- player->clearHud();
+ // Load player
+ PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
- /* Add object to environment */
- m_env->addActiveObject(playersao);
+ // Complete init with server parts
+ playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
+ player->protocol_version = proto_version;
/* Run scripts */
if (newplayer) {
}
server.step(steplen);
- if(server.getShutdownRequested() || kill)
- {
- infostream<<"Dedicated server quitting"<<std::endl;
-#if USE_CURL
- if(g_settings->getBool("server_announce"))
- ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
-#endif
+ if (server.getShutdownRequested() || kill)
break;
- }
/*
Profiler
}
}
}
+
+ infostream << "Dedicated server quitting" << std::endl;
+#if USE_CURL
+ if (g_settings->getBool("server_announce"))
+ ServerList::sendAnnounce(ServerList::AA_DELETE,
+ server.m_bind_addr.getPort());
+#endif
}