#include "craftdef.h"
#include "emerge.h"
#include "mapgen.h"
-#include "biome.h"
+#include "mg_biome.h"
#include "content_mapnode.h"
#include "content_nodemeta.h"
#include "content_abm.h"
ThreadStarted();
+ porting::setThreadName("ServerThread");
+
while(!StopRequested())
{
try{
Server::Server(
const std::string &path_world,
const SubgameSpec &gamespec,
- bool simple_singleplayer_mode
+ bool simple_singleplayer_mode,
+ bool ipv6
):
m_path_world(path_world),
m_gamespec(gamespec),
m_con(PROTOCOL_ID,
512,
CONNECTION_TIMEOUT,
- g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"),
+ ipv6,
this),
m_banmanager(NULL),
m_rollback(NULL),
- m_rollback_sink_enabled(true),
m_enable_rollback_recording(false),
m_emerge(NULL),
m_script(NULL),
m_clients(&m_con),
m_shutdown_requested(false),
m_ignore_map_edit_events(false),
- m_ignore_map_edit_events_peer_id(0)
+ m_ignore_map_edit_events_peer_id(0),
+ m_next_sound_id(0)
{
m_liquid_transform_timer = 0.0;
throw ServerError("Failed to initialize world");
// Create ban manager
- std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
+ std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
m_banmanager = new BanManager(ban_path);
// Create rollback manager
- std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
- m_rollback = createRollbackManager(rollback_path, this);
+ m_rollback = new RollbackManager(m_path_world, this);
ModConfiguration modconf(m_path_world);
m_mods = modconf.getMods();
errorstream << std::endl;
}
- // Path to builtin.lua
- std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
-
// Lock environment
JMutexAutoLock envlock(m_env_mutex);
+ // Load mapgen params from Settings
+ m_emerge->loadMapgenParams();
+
+ // Create the Map (loads map_meta.txt, overriding configured mapgen params)
+ ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
+
// Initialize scripting
infostream<<"Server: Initializing Lua"<<std::endl;
m_script = new GameScripting(this);
+ std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
+
+ if (!m_script->loadScript(scriptpath))
+ throw ModError("Failed to load and run " + scriptpath);
- // Load and run builtin.lua
- infostream<<"Server: Loading builtin.lua [\""
- <<builtinpath<<"\"]"<<std::endl;
- bool success = m_script->loadMod(builtinpath, "__builtin");
- if(!success){
- errorstream<<"Server: Failed to load and run "
- <<builtinpath<<std::endl;
- throw ModError("Failed to load and run "+builtinpath);
- }
// Print 'em
infostream<<"Server: Loading mods: ";
for(std::vector<ModSpec>::iterator i = m_mods.begin();
// Apply item aliases in the node definition manager
m_nodedef->updateAliases(m_itemdef);
+ m_nodedef->setNodeRegistrationStatus(true);
+
+ // Perform pending node name resolutions
+ m_nodedef->runNodeResolverCallbacks();
+
// Initialize Environment
- ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
- m_env = new ServerEnvironment(servermap, m_script, this);
+ m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
m_clients.setEnv(m_env);
- // Run some callbacks after the MG params have been set up but before activation
- m_script->environment_OnMapgenInit(&m_emerge->params);
-
// Initialize mapgens
m_emerge->initMapgens();
servermap->addEventReceiver(this);
// If file exists, load environment metadata
- if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
+ if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
{
infostream<<"Server: Loading environment metadata"<<std::endl;
- m_env->loadMeta(m_path_world);
+ m_env->loadMeta();
}
- // Load players
- infostream<<"Server: Loading players"<<std::endl;
- m_env->deSerializePlayers(m_path_world);
-
- /*
- Add some test ActiveBlockModifiers to environment
- */
+ // Add some test ActiveBlockModifiers to environment
add_legacy_abms(m_env, m_nodedef);
m_liquid_transform_every = g_settings->getFloat("liquid_update");
{
infostream<<"Server destructing"<<std::endl;
- /*
- Send shutdown message
- */
- {
- std::wstring line = L"*** Server shutting down";
- SendChatMessage(PEER_ID_INEXISTENT, line);
- }
+ // Send shutdown message
+ SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
{
JMutexAutoLock envlock(m_env_mutex);
- /*
- Execute script shutdown hooks
- */
+ // Execute script shutdown hooks
m_script->on_shutdown();
- }
- {
- JMutexAutoLock envlock(m_env_mutex);
-
- /*
- Save players
- */
infostream<<"Server: Saving players"<<std::endl;
- m_env->serializePlayers(m_path_world);
+ m_env->saveLoadedPlayers();
- /*
- Save environment metadata
- */
infostream<<"Server: Saving environment metadata"<<std::endl;
- m_env->saveMeta(m_path_world);
+ m_env->saveMeta();
}
- /*
- Stop threads
- */
+ // Stop threads
stop();
delete m_thread;
delete m_script;
// Delete detached inventories
- {
- for(std::map<std::string, Inventory*>::iterator
- i = m_detached_inventories.begin();
- i != m_detached_inventories.end(); i++){
- delete i->second;
- }
+ for (std::map<std::string, Inventory*>::iterator
+ i = m_detached_inventories.begin();
+ i != m_detached_inventories.end(); i++) {
+ delete i->second;
}
}
void Server::start(Address bind_addr)
{
DSTACK(__FUNCTION_NAME);
+
+ m_bind_addr = bind_addr;
+
infostream<<"Starting server on "
<< bind_addr.serializeString() <<"..."<<std::endl;
m_env->step(dtime);
}
- const float map_timer_and_unload_dtime = 2.92;
+ static const float map_timer_and_unload_dtime = 2.92;
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
{
JMutexAutoLock lock(m_env_mutex);
/*
Send player breath if changed
*/
- if(playersao->m_breath_not_sent){
+ if(playersao->m_breath_not_sent) {
SendPlayerBreath(*i);
}
/*
Set the modified blocks unsent for all the clients
*/
- if(modified_blocks.size() > 0)
+ if(!modified_blocks.empty())
{
SetBlocksNotSent(modified_blocks);
}
{
float &counter = m_masterserver_timer;
if(!isSingleplayer() && (!counter || counter >= 300.0) &&
- g_settings->getBool("server_announce") == true)
+ g_settings->getBool("server_announce"))
{
- ServerList::sendAnnounce(!counter ? "start" : "update",
- m_clients.getPlayerNames(),
- m_uptime.get(),
- m_env->getGameTime(),
- m_lag,
- m_gamespec.id,
- m_mods);
+ ServerList::sendAnnounce(counter ? "update" : "start",
+ m_bind_addr.getPort(),
+ m_clients.getPlayerNames(),
+ m_uptime.get(),
+ m_env->getGameTime(),
+ m_lag,
+ m_gamespec.id,
+ m_emerge->params.mg_name,
+ m_mods);
counter = 0.01;
}
counter += dtime;
// Radius inside which objects are active
s16 radius = g_settings->getS16("active_object_send_range_blocks");
+ s16 player_radius = g_settings->getS16("player_transfer_distance");
+
+ if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
+ !g_settings->getBool("unlimited_player_transfer_distance"))
+ player_radius = radius;
+
radius *= MAP_BLOCKSIZE;
+ player_radius *= MAP_BLOCKSIZE;
for(std::map<u16, RemoteClient*>::iterator
i = clients.begin();
// If definitions and textures have not been sent, don't
// send objects either
- if (client->getState() < DefinitionsSent)
+ if (client->getState() < CS_DefinitionsSent)
continue;
Player *player = m_env->getPlayer(client->peer_id);
std::set<u16> removed_objects;
std::set<u16> added_objects;
- m_env->getRemovedActiveObjects(pos, radius,
+ m_env->getRemovedActiveObjects(pos, radius, player_radius,
client->m_known_objects, removed_objects);
- m_env->getAddedActiveObjects(pos, radius,
+ m_env->getAddedActiveObjects(pos, radius, player_radius,
client->m_known_objects, added_objects);
// Ignore if nothing happened
- if(removed_objects.size() == 0 && added_objects.size() == 0)
+ if(removed_objects.empty() && added_objects.empty())
{
//infostream<<"active objects: none changed"<<std::endl;
continue;
/*
Set blocks not sent to far players
*/
- if(far_players.size() > 0)
+ if(!far_players.empty())
{
// Convert list format to that wanted by SetBlocksNotSent
std::map<v3s16, MapBlock*> modified_blocks2;
ScopeProfiler sp(g_profiler, "Server: saving stuff");
- //Ban stuff
- if(m_banmanager->isModified())
+ // Save ban file
+ if (m_banmanager->isModified()) {
m_banmanager->save();
+ }
// Save changed parts of map
m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
// Save players
- m_env->serializePlayers(m_path_world);
+ m_env->saveLoadedPlayers();
// Save environment metadata
- m_env->saveMeta(m_path_world);
+ m_env->saveMeta();
}
}
}
"InvalidIncomingDataException: what()="
<<e.what()<<std::endl;
}
+ catch(SerializationError &e) {
+ infostream<<"Server::Receive(): "
+ "SerializationError: what()="
+ <<e.what()<<std::endl;
+ }
+ catch(ClientStateError &e)
+ {
+ errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
+ DenyAccess(peer_id, L"Your client sent something server didn't expect."
+ L"Try reconnecting or updating your client");
+ }
catch(con::PeerNotFoundException &e)
{
- //NOTE: This is not needed anymore
+ // Do nothing
+ }
+}
- // The peer has been disconnected.
- // Find the associated player and remove it.
+PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
+{
+ std::string playername = "";
+ PlayerSAO *playersao = NULL;
+ m_clients.Lock();
+ try {
+ RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
+ if (client != NULL) {
+ playername = client->getName();
+ playersao = emergePlayer(playername.c_str(), peer_id);
+ }
+ } catch (std::exception &e) {
+ m_clients.Unlock();
+ throw;
+ }
+ m_clients.Unlock();
- /*JMutexAutoLock envlock(m_env_mutex);
+ RemotePlayer *player =
+ static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
- infostream<<"ServerThread: peer_id="<<peer_id
- <<" has apparently closed connection. "
- <<"Removing player."<<std::endl;
+ // If failed, cancel
+ if((playersao == NULL) || (player == NULL))
+ {
+ if(player && player->peer_id != 0){
+ errorstream<<"Server: "<<playername<<": Failed to emerge player"
+ <<" (player allocated to an another client)"<<std::endl;
+ DenyAccess(peer_id, L"Another client is connected with this "
+ L"name. If your client closed unexpectedly, try again in "
+ L"a minute.");
+ } else {
+ errorstream<<"Server: "<<playername<<": Failed to emerge player"
+ <<std::endl;
+ DenyAccess(peer_id, L"Could not allocate player.");
+ }
+ return NULL;
+ }
+
+ /*
+ Send complete position information
+ */
+ SendMovePlayer(peer_id);
+
+ // Send privileges
+ SendPlayerPrivileges(peer_id);
+
+ // Send inventory formspec
+ SendPlayerInventoryFormspec(peer_id);
+
+ // Send inventory
+ UpdateCrafting(peer_id);
+ SendInventory(peer_id);
+
+ // Send HP
+ if(g_settings->getBool("enable_damage"))
+ SendPlayerHP(peer_id);
+
+ // Send Breath
+ SendPlayerBreath(peer_id);
- m_env->removePlayer(peer_id);*/
+ // Show death screen if necessary
+ if(player->hp == 0)
+ SendDeathscreen(peer_id, false, v3f(0,0,0));
+
+ // Note things in chat if not in simple singleplayer mode
+ if(!m_simple_singleplayer_mode)
+ {
+ // Send information about server to player in chat
+ SendChatMessage(peer_id, getStatusString());
+
+ // Send information about joining in chat
+ {
+ std::wstring name = L"unknown";
+ Player *player = m_env->getPlayer(peer_id);
+ if(player != NULL)
+ name = narrow_to_wide(player->getName());
+
+ std::wstring message;
+ message += L"*** ";
+ message += name;
+ message += L" joined the game.";
+ SendChatMessage(PEER_ID_INEXISTENT,message);
+ }
}
+ Address addr = getPeerAddress(player->peer_id);
+ std::string ip_str = addr.serializeString();
+ actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
+ /*
+ Print out action
+ */
+ {
+ std::vector<std::string> names = m_clients.getPlayerNames();
+
+ actionstream<<player->getName() <<" joins game. List of players: ";
+
+ for (std::vector<std::string>::iterator i = names.begin();
+ i != names.end(); i++)
+ {
+ actionstream << *i << " ";
+ }
+
+ actionstream << player->getName() <<std::endl;
+ }
+ return playersao;
}
void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
catch(con::PeerNotFoundException &e)
{
- errorstream<<"Server::ProcessData(): Cancelling: peer "
+ /*
+ * no peer for this packet found
+ * most common reason is peer timeout, e.g. peer didn't
+ * respond for some time, your server was overloaded or
+ * things like that.
+ */
+ infostream<<"Server::ProcessData(): Cancelling: peer "
<<peer_id<<" not found"<<std::endl;
return;
}
if(datasize < 2+1+PLAYERNAME_SIZE)
return;
- RemoteClient* client = getClient(peer_id,Created);
+ RemoteClient* client = getClient(peer_id, CS_Created);
// If net_proto_version is set, this client has already been handled
- if(client->getState() > Created)
+ if(client->getState() > CS_Created)
{
verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
<<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
u8 client_max = data[2];
u8 our_max = SER_FMT_VER_HIGHEST_READ;
// Use the highest version supported by both
- u8 deployed = std::min(client_max, our_max);
+ int deployed = std::min(client_max, our_max);
// If it's lower than the lowest supported, give up.
if(deployed < SER_FMT_VER_LOWEST)
deployed = SER_FMT_VER_INVALID;
/*
Set up player
*/
-
- // Get player name
char playername[PLAYERNAME_SIZE];
- for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
- {
- playername[i] = data[3+i];
+ unsigned int playername_length = 0;
+ for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
+ playername[playername_length] = data[3+playername_length];
+ if (data[3+playername_length] == 0)
+ break;
+ }
+
+ if (playername_length == PLAYERNAME_SIZE) {
+ actionstream<<"Server: Player with name exceeding max length "
+ <<"tried to connect from "<<addr_s<<std::endl;
+ DenyAccess(peer_id, L"Name too long");
+ return;
}
- playername[PLAYERNAME_SIZE-1] = 0;
+
if(playername[0]=='\0')
{
<<"tried to connect from "<<addr_s<<" "
<<"but it was disallowed for the following reason: "
<<reason<<std::endl;
- DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
+ DenyAccess(peer_id, narrow_to_wide(reason));
return;
}
}
// Enforce user limit.
// Don't enforce for users that have some admin right
- if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
+ if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
!checkPriv(playername, "server") &&
!checkPriv(playername, "ban") &&
!checkPriv(playername, "privs") &&
// Send as reliable
m_clients.send(peer_id, 0, reply, true);
- m_clients.event(peer_id, Init);
+ m_clients.event(peer_id, CSE_Init);
}
return;
verbosestream<<"Server: Got TOSERVER_INIT2 from "
<<peer_id<<std::endl;
- m_clients.event(peer_id, GotInit2);
+ m_clients.event(peer_id, CSE_GotInit2);
u16 protocol_version = m_clients.getProtocolVersion(peer_id);
+
+ ///// begin compatibility code
+ PlayerSAO* playersao = NULL;
+ if (protocol_version <= 22) {
+ playersao = StageTwoClientInit(peer_id);
+
+ if (playersao == NULL) {
+ errorstream
+ << "TOSERVER_INIT2 stage 2 client init failed for peer "
+ << peer_id << std::endl;
+ return;
+ }
+ }
+ ///// end compatibility code
+
/*
Send some initialization data
*/
// Send node definitions
SendNodeDef(peer_id, m_nodedef, protocol_version);
- m_clients.event(peer_id, SetDefinitionsSent);
+ m_clients.event(peer_id, CSE_SetDefinitionsSent);
// Send media announcement
sendMediaAnnouncement(peer_id);
float time_speed = g_settings->getFloat("time_speed");
SendTimeOfDay(peer_id, time, time_speed);
+ ///// begin compatibility code
+ if (protocol_version <= 22) {
+ m_clients.event(peer_id, CSE_SetClientReady);
+ m_script->on_joinplayer(playersao);
+ }
+ ///// end compatibility code
+
// Warnings about protocol version can be issued here
if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
{
return;
}
- u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
+ u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
+ u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
if(peer_ser_ver == SER_FMT_VER_INVALID)
{
return;
}
else if(command == TOSERVER_RECEIVED_MEDIA) {
- std::string playername = "";
- PlayerSAO *playersao = NULL;
- m_clients.Lock();
- RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,DefinitionsSent);
- if (client != NULL) {
- playername = client->getName();
- playersao = emergePlayer(playername.c_str(), peer_id);
+ return;
+ }
+ else if(command == TOSERVER_CLIENT_READY) {
+ // clients <= protocol version 22 did not send ready message,
+ // they're already initialized
+ if (peer_proto_ver <= 22) {
+ infostream << "Client sent message not expected by a "
+ << "client using protocol version <= 22,"
+ << "disconnecing peer_id: " << peer_id << std::endl;
+ m_con.DisconnectPeer(peer_id);
+ return;
}
- m_clients.Unlock();
- RemotePlayer *player =
- static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
+ PlayerSAO* playersao = StageTwoClientInit(peer_id);
- // If failed, cancel
- if((playersao == NULL) || (player == NULL))
- {
- if(player && player->peer_id != 0){
- errorstream<<"Server: "<<playername<<": Failed to emerge player"
- <<" (player allocated to an another client)"<<std::endl;
- DenyAccess(peer_id, L"Another client is connected with this "
- L"name. If your client closed unexpectedly, try again in "
- L"a minute.");
- } else {
- errorstream<<"Server: "<<playername<<": Failed to emerge player"
- <<std::endl;
- DenyAccess(peer_id, L"Could not allocate player.");
- }
+ if (playersao == NULL) {
+ errorstream
+ << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
+ << peer_id << std::endl;
+ m_con.DisconnectPeer(peer_id);
return;
}
- /*
- Send complete position information
- */
- SendMovePlayer(peer_id);
-
- // Send privileges
- SendPlayerPrivileges(peer_id);
-
- // Send inventory formspec
- SendPlayerInventoryFormspec(peer_id);
-
- // Send inventory
- UpdateCrafting(peer_id);
- SendInventory(peer_id);
-
- // Send HP
- if(g_settings->getBool("enable_damage"))
- SendPlayerHP(peer_id);
-
- // Send Breath
- SendPlayerBreath(peer_id);
-
- // Show death screen if necessary
- if(player->hp == 0)
- SendDeathscreen(peer_id, false, v3f(0,0,0));
-
- // Note things in chat if not in simple singleplayer mode
- if(!m_simple_singleplayer_mode)
- {
- // Send information about server to player in chat
- SendChatMessage(peer_id, getStatusString());
- // Send information about joining in chat
- {
- std::wstring name = L"unknown";
- Player *player = m_env->getPlayer(peer_id);
- if(player != NULL)
- name = narrow_to_wide(player->getName());
-
- std::wstring message;
- message += L"*** ";
- message += name;
- message += L" joined the game.";
- SendChatMessage(PEER_ID_INEXISTENT,message);
- }
+ if(datasize < 2+8) {
+ errorstream
+ << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
+ << peer_id << std::endl;
+ m_con.DisconnectPeer(peer_id);
+ return;
}
- actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. " << std::endl;
- /*
- Print out action
- */
- {
- std::vector<std::string> names = m_clients.getPlayerNames();
-
- actionstream<<player->getName()<<" ["<<addr_s<<"] "
- <<"joins game. List of players: ";
-
- for (std::vector<std::string>::iterator i = names.begin();
- i != names.end(); i++)
- {
- actionstream << *i << " ";
- }
-
- actionstream<<std::endl;
- }
+ m_clients.setClientVersion(
+ peer_id,
+ data[2], data[3], data[4],
+ std::string((char*) &data[8],(u16) data[6]));
- m_clients.event(peer_id,SetMediaSent);
+ m_clients.event(peer_id, CSE_SetClientReady);
m_script->on_joinplayer(playersao);
- return;
+
}
else if(command == TOSERVER_GOTBLOCKS)
{
return;
}
- if (m_clients.getClientState(peer_id) < Active)
+ if (m_clients.getClientState(peer_id) < CS_Active)
{
if (command == TOSERVER_PLAYERPOS) return;
}
Player *player = m_env->getPlayer(peer_id);
- if(player == NULL){
+ if(player == NULL) {
errorstream<<"Server::ProcessData(): Cancelling: "
"No player for peer_id="<<peer_id
- <<std::endl;
+ << " disconnecting peer!" <<std::endl;
+ m_con.DisconnectPeer(peer_id);
return;
}
PlayerSAO *playersao = player->getPlayerSAO();
- if(playersao == NULL){
+ if(playersao == NULL) {
errorstream<<"Server::ProcessData(): Cancelling: "
"No player object for peer_id="<<peer_id
- <<std::endl;
+ << " disconnecting peer!" <<std::endl;
+ m_con.DisconnectPeer(peer_id);
return;
}
std::istringstream is(datastring, std::ios_base::binary);
u16 breath = readU16(is);
playersao->setBreath(breath);
+ m_script->player_event(playersao,"breath_changed");
}
else if(command == TOSERVER_PASSWORD)
{
somebody is cheating, by checking the timing.
*/
MapNode n(CONTENT_IGNORE);
- try
- {
- n = m_env->getMap().getNode(p_under);
- }
- catch(InvalidPositionException &e)
- {
+ bool pos_ok;
+ n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
+ if (pos_ok)
+ n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
+
+ if (!pos_ok) {
infostream<<"Server: Not punching: Node not found."
<<" Adding block to emerge queue."
<<std::endl;
m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
}
+
if(n.getContent() != CONTENT_IGNORE)
m_script->node_on_punch(p_under, n, playersao, pointed);
// Cheat prevention
// Only digging of nodes
if(pointed.type == POINTEDTHING_NODE)
{
- MapNode n(CONTENT_IGNORE);
- try
- {
- n = m_env->getMap().getNode(p_under);
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Not finishing digging: Node not found."
- <<" Adding block to emerge queue."
- <<std::endl;
+ bool pos_ok;
+ MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
+ if (!pos_ok) {
+ infostream << "Server: Not finishing digging: Node not found."
+ << " Adding block to emerge queue."
+ << std::endl;
m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
}
if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
m_script->node_on_dig(p_under, n, playersao);
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
+ RemoteClient *client = getClient(peer_id);
// Send unusual result (that is, node not being removed)
if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
{
// Re-send block to revert change on client-side
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
client->SetBlockNotSent(blockpos);
}
+ else {
+ client->ResendBlockIfOnWire(blockpos);
+ }
}
} // action == 2
// 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));
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
+ v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
+ if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
client->SetBlockNotSent(blockpos);
- v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
- if(blockpos2 != blockpos){
+ if(blockpos2 != blockpos) {
client->SetBlockNotSent(blockpos2);
}
}
+ else {
+ client->ResendBlockIfOnWire(blockpos);
+ if(blockpos2 != blockpos) {
+ client->ResendBlockIfOnWire(blockpos2);
+ }
+ }
} // action == 3
/*
}
} // action == 4
-
+
/*
Catch invalid actions
continue;
ServerPlayingSound &psound = i->second;
psound.clients.erase(peer_id);
- if(psound.clients.size() == 0)
+ if(psound.clients.empty())
m_playing_sounds.erase(i++);
}
}
verbosestream<<"Server::deletingPeer(): peer->id="
<<peer->id<<", timeout="<<timeout<<std::endl;
- m_clients.event(peer->id,Disconnect);
+ m_clients.event(peer->id, CSE_Disconnect);
con::PeerChange c;
c.type = con::PEER_REMOVED;
c.peer_id = peer->id;
m_peer_change_queue.push_back(c);
}
+bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
+{
+ *retval = m_con.getPeerStat(peer_id,type);
+ if (*retval == -1) return false;
+ return true;
+}
+
+bool Server::getClientInfo(
+ u16 peer_id,
+ ClientState* state,
+ u32* uptime,
+ u8* ser_vers,
+ u16* prot_vers,
+ u8* major,
+ u8* minor,
+ u8* patch,
+ std::string* vers_string
+ )
+{
+ *state = m_clients.getClientState(peer_id);
+ m_clients.Lock();
+ RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
+
+ if (client == NULL) {
+ m_clients.Unlock();
+ return false;
+ }
+
+ *uptime = client->uptime();
+ *ser_vers = client->serialization_version;
+ *prot_vers = client->net_proto_version;
+
+ *major = client->getMajor();
+ *minor = client->getMinor();
+ *patch = client->getPatch();
+ *vers_string = client->getPatch();
+
+ m_clients.Unlock();
+
+ return true;
+}
+
void Server::handlePeerChanges()
{
while(m_peer_change_queue.size() > 0)
}
}
-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);
std::ostringstream os(std::ios_base::binary);
u8 buf[12];
+
// Write command
writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
os.write((char*)buf, 2);
- os<<serializeLongString(formspec);
+ os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
os<<serializeString(formname);
// Make data buffer
writeV2F1000(os, form->align);
writeV2F1000(os, form->offset);
writeV3F1000(os, form->world_pos);
+ writeV2S32(os,form->size);
// Make data buffer
std::string s = os.str();
case HUD_STAT_WORLD_POS:
writeV3F1000(os, *(v3f *)value);
break;
+ case HUD_STAT_SIZE:
+ writeV2S32(os,*(v2s32 *)value);
+ break;
case HUD_STAT_NUMBER:
case HUD_STAT_ITEM:
case HUD_STAT_DIR:
// Write command
writeU16(os, TOCLIENT_HUD_SET_FLAGS);
+
+ //////////////////////////// compatibility code to be removed //////////////
+ flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
+ ////////////////////////////////////////////////////////////////////////////
writeU32(os, flags);
writeU32(os, mask);
assert(playersao);
playersao->m_hp_not_sent = false;
SendHP(peer_id, playersao->getHP());
+ m_script->player_event(playersao,"health_changed");
// Send to other clients
std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
playersao->m_breath_not_sent = false;
+ m_script->player_event(playersao,"breath_changed");
SendBreath(peer_id, playersao->getBreath());
}
m_clients.send(peer_id, 0, data, true);
}
+void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
+{
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
+ writeV2S32(os, animation_frames[0]);
+ writeV2S32(os, animation_frames[1]);
+ writeV2S32(os, animation_frames[2]);
+ writeV2S32(os, animation_frames[3]);
+ writeF1000(os, animation_speed);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+}
+
+void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
+{
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOCLIENT_EYE_OFFSET);
+ writeV3F1000(os, first);
+ writeV3F1000(os, third);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+}
void Server::SendPlayerPrivileges(u16 peer_id)
{
Player *player = m_env->getPlayer(peer_id);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
- os<<serializeLongString(player->inventory_formspec);
+ os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
// Make data buffer
std::string s = os.str();
dst_clients.push_back(*i);
}
}
- if(dst_clients.size() == 0)
+ if(dst_clients.empty())
return -1;
// Create the sound
i = clients.begin();
i != clients.end(); ++i)
{
- RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
+ RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
if (client == NULL)
- return;
+ continue;
total_sending += client->SendingCount();
client->GetNextBlocks(m_env,m_emerge, dtime, queue);
continue;
}
- RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
+ RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
if(!client)
continue;
std::string name;
std::string sha1_digest;
- SendableMediaAnnouncement(const std::string name_="",
- const std::string sha1_digest_=""):
+ SendableMediaAnnouncement(const std::string &name_="",
+ const std::string &sha1_digest_=""):
name(name_),
sha1_digest(sha1_digest_)
{}
std::string path;
std::string data;
- SendableMedia(const std::string &name_="", const std::string path_="",
- const std::string &data_=""):
+ SendableMedia(const std::string &name_="", const std::string &path_="",
+ const std::string &data_=""):
name(name_),
path(path_),
data(data_)
DSTACK(__FUNCTION_NAME);
SendAccessDenied(peer_id, reason);
- m_clients.event(peer_id,SetDenied);
+ m_clients.event(peer_id, CSE_SetDenied);
m_con.DisconnectPeer(peer_id);
}
{
ServerPlayingSound &psound = i->second;
psound.clients.erase(peer_id);
- if(psound.clients.size() == 0)
+ if(psound.clients.empty())
m_playing_sounds.erase(i++);
else
i++;
name = narrow_to_wide(player->getName());
// Add name to information string
if(!first)
- os<<L",";
+ os<<L", ";
else
first = false;
os<<name;
return m_banmanager->getBanDescription(ip_or_name);
}
-void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
+void Server::notifyPlayer(const char *name, const std::wstring &msg)
{
Player *player = m_env->getPlayer(name);
if(!player)
if (player->peer_id == PEER_ID_INEXISTENT)
return;
- if (prepend)
- SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
- else
- SendChatMessage(player->peer_id, msg);
+ SendChatMessage(player->peer_id, msg);
}
bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
if (!player)
return -1;
- u32 id = player->getFreeHudID();
- if (id < player->hud.size())
- player->hud[id] = form;
- else
- player->hud.push_back(form);
-
+ u32 id = player->addHud(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])
+ if (!player)
return false;
- delete player->hud[id];
- player->hud[id] = NULL;
-
+ HudElement* todel = player->removeHud(id);
+
+ if (!todel)
+ return false;
+
+ delete todel;
+
SendHUDRemove(player->peer_id, id);
return true;
}
return false;
SendHUDSetFlags(player->peer_id, flags, mask);
+ player->hud_flags = flags;
+
+ PlayerSAO* playersao = player->getPlayerSAO();
+
+ if (playersao == NULL)
+ return false;
+
+ m_script->player_event(playersao, "hud_changed");
return true;
}
SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
}
+bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
+{
+ if (!player)
+ return false;
+
+ SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
+ return true;
+}
+
+bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
+{
+ if (!player)
+ return false;
+
+ SendEyeOffset(player->peer_id, first, third);
+ return true;
+}
+
bool Server::setSky(Player *player, const video::SColor &bgcolor,
const std::string &type, const std::vector<std::string> ¶ms)
{
return true;
}
-void Server::notifyPlayers(const std::wstring msg)
+void Server::notifyPlayers(const std::wstring &msg)
{
SendChatMessage(PEER_ID_INEXISTENT,msg);
}
{
infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
ServerMap *map = (ServerMap*)(&m_env->getMap());
- // Disable rollback report sink while reverting
- BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
// Fail if no actions to handle
if(actions.empty()){
{
return NULL;
}
+scene::ISceneManager* Server::getSceneManager()
+{
+ return NULL;
+}
+
u16 Server::allocateUnknownNodeId(const std::string &name)
{
return m_nodedef->allocateDummy(name);
{
return m_event;
}
-IRollbackReportSink* Server::getRollbackReportSink()
-{
- if(!m_enable_rollback_recording)
- return NULL;
- if(!m_rollback_sink_enabled)
- return NULL;
- return m_rollback;
-}
IWritableItemDefManager* Server::getWritableItemDefManager()
{
return NULL;
}
- /*
- Create a new player if it doesn't exist yet
- */
- if(player == NULL)
- {
- newplayer = true;
- player = new RemotePlayer(this);
- player->updateName(name);
+ // Load player if it isn't already loaded
+ if (!player) {
+ player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
+ }
- /* Set player position */
+ // Create player if it doesn't exist
+ if (!player) {
+ newplayer = true;
+ player = new RemotePlayer(this, name);
+ // Set player position
infostream<<"Server: Finding spawn place for player \""
<<name<<"\""<<std::endl;
v3f pos = findSpawnPos(m_env->getServerMap());
player->setPosition(pos);
- /* Add player to environment */
+ // Make sure the player is saved
+ player->setModified(true);
+
+ // Add player to environment
m_env->addPlayer(player);
}
- /*
- Create a new player active object
- */
+ // Create a new player active object
PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
getPlayerEffectivePrivs(player->getName()),
isSingleplayer());
/* Clean up old HUD elements from previous sessions */
- player->hud.clear();
+ player->clearHud();
/* Add object to environment */
m_env->addActiveObject(playersao);
/* Run scripts */
- if(newplayer)
+ if (newplayer) {
m_script->on_newplayer(playersao);
+ }
return playersao;
}
{
infostream<<"Dedicated server quitting"<<std::endl;
#if USE_CURL
- if(g_settings->getBool("server_announce") == true)
- ServerList::sendAnnounce("delete");
+ if(g_settings->getBool("server_announce"))
+ ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
#endif
break;
}