#include "constants.h"
#include "voxel.h"
#include "config.h"
-#include "servercommand.h"
#include "filesys.h"
#include "mapblock.h"
#include "serverobject.h"
#include "util/pointedthing.h"
#include "util/mathconstants.h"
#include "rollback.h"
+#include "util/serialize.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
m_nearest_unsent_reset_timer += dtime;
if(m_nothing_to_send_pause_timer >= 0)
- {
return;
- }
+
+ Player *player = server->m_env->getPlayer(peer_id);
+ // This can happen sometimes; clients and players are not in perfect sync.
+ if(player == NULL)
+ return;
// Won't send anything if already sending
if(m_blocks_sending.size() >= g_settings->getU16
//TimeTaker timer("RemoteClient::GetNextBlocks");
- Player *player = server->m_env->getPlayer(peer_id);
-
- assert(player != NULL);
-
v3f playerpos = player->getPosition();
v3f playerspeed = player->getSpeed();
v3f playerspeeddir(0,0,0);
m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
m_rollback(NULL),
m_rollback_sink_enabled(true),
+ m_enable_rollback_recording(false),
m_lua(NULL),
m_itemdef(createItemDefManager()),
m_nodedef(createNodeDefManager()),
{}
}
}
-
+
+ {
+ JMutexAutoLock envlock(m_env_mutex);
+ JMutexAutoLock conlock(m_con_mutex);
+
+ /*
+ Execute script shutdown hooks
+ */
+ scriptapi_on_shutdown(m_lua);
+ }
+
{
JMutexAutoLock envlock(m_env_mutex);
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
- /*// Delete player
- // NOTE: These are removed by env destructor
- {
- u16 peer_id = i.getNode()->getKey();
- JMutexAutoLock envlock(m_env_mutex);
- m_env->removePlayer(peer_id);
- }*/
-
// Delete client
delete i.getNode()->getValue();
}
/*
Send player inventories and HPs if necessary
*/
- if(playersao->m_teleported){
+ if(playersao->m_moved){
SendMovePlayer(client->peer_id);
- playersao->m_teleported = false;
+ playersao->m_moved = false;
}
if(playersao->m_inventory_not_sent){
UpdateCrafting(client->peer_id);
if(obj)
data_buffer.append(serializeLongString(
- obj->getClientInitializationData()));
+ obj->getClientInitializationData(client->net_proto_version)));
else
data_buffer.append(serializeLongString(""));
counter = 0.0;
m_emergethread.trigger();
+
+ // Update m_enable_rollback_recording here too
+ m_enable_rollback_recording =
+ g_settings->getBool("enable_rollback_recording");
}
}
Read and check network protocol version
*/
- u16 net_proto_version = 0;
+ u16 min_net_proto_version = 0;
if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
+ min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
+
+ // Use same version as minimum and maximum if maximum version field
+ // doesn't exist (backwards compatibility)
+ u16 max_net_proto_version = min_net_proto_version;
+ if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
+ max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
+
+ // Start with client's maximum version
+ u16 net_proto_version = max_net_proto_version;
+
+ // Figure out a working version if it is possible at all
+ if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
+ min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
{
- net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
+ // If maximum is larger than our maximum, go with our maximum
+ if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
+ net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
+ // Else go with client's maximum
+ else
+ net_proto_version = max_net_proto_version;
}
+ verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
+ <<min_net_proto_version<<", max: "<<max_net_proto_version
+ <<", chosen: "<<net_proto_version<<std::endl;
+
getClient(peer_id)->net_proto_version = net_proto_version;
- if(net_proto_version == 0)
+ if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
+ net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
{
- actionstream<<"Server: An old tried to connect from "<<addr_s
+ actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
<<std::endl;
SendAccessDenied(m_con, peer_id, std::wstring(
L"Your client's version is not supported.\n"
L"Server version is ")
- + narrow_to_wide(VERSION_STRING) + L"."
+ + narrow_to_wide(VERSION_STRING) + L",\n"
+ + L"server's PROTOCOL_VERSION is "
+ + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
+ + L"..."
+ + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
+ + L", client's PROTOCOL_VERSION is "
+ + narrow_to_wide(itos(min_net_proto_version))
+ + L"..."
+ + narrow_to_wide(itos(max_net_proto_version))
);
return;
}
if(g_settings->getBool("strict_protocol_version_checking"))
{
- if(net_proto_version != PROTOCOL_VERSION)
+ if(net_proto_version != LATEST_PROTOCOL_VERSION)
{
- actionstream<<"Server: A mismatched client tried to connect"
- <<" from "<<addr_s<<std::endl;
+ actionstream<<"Server: A mismatched (strict) client tried to "
+ <<"connect from "<<addr_s<<std::endl;
SendAccessDenied(m_con, peer_id, std::wstring(
L"Your client's version is not supported.\n"
L"Server version is ")
+ narrow_to_wide(VERSION_STRING) + L",\n"
- + L"server's PROTOCOL_VERSION is "
- + narrow_to_wide(itos(PROTOCOL_VERSION))
+ + L"server's PROTOCOL_VERSION (strict) is "
+ + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
+ L", client's PROTOCOL_VERSION is "
- + narrow_to_wide(itos(net_proto_version))
+ + narrow_to_wide(itos(min_net_proto_version))
+ + L"..."
+ + narrow_to_wide(itos(max_net_proto_version))
);
return;
}
Answer with a TOCLIENT_INIT
*/
{
- SharedBuffer<u8> reply(2+1+6+8);
+ SharedBuffer<u8> reply(2+1+6+8+4);
writeU16(&reply[0], TOCLIENT_INIT);
writeU8(&reply[2], deployed);
writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
+ writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
// Send as reliable
m_con.Send(peer_id, 0, reply, true);
return;
}
- getClient(peer_id)->serialization_version
- = getClient(peer_id)->pending_serialization_version;
+ RemoteClient *client = getClient(peer_id);
+ client->serialization_version =
+ getClient(peer_id)->pending_serialization_version;
/*
Send some initialization data
SendItemDef(m_con, peer_id, m_itemdef);
// Send node definitions
- SendNodeDef(m_con, peer_id, m_nodedef);
+ SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
// Send media announcement
sendMediaAnnouncement(peer_id);
}
// Warnings about protocol version can be issued here
- if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
+ if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
{
- SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER!");
+ SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
+ L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
}
/*
v3s32 ss = readV3S32(&data[start+2+12]);
f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
+ u32 keyPressed = 0;
+ if(datasize >= 2+12+12+4+4+4)
+ keyPressed = (u32)readU32(&data[2+12+12+4+4]);
v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
pitch = wrapDegrees(pitch);
player->setSpeed(speed);
player->setPitch(pitch);
player->setYaw(yaw);
+ player->keyPressed=keyPressed;
+ player->control.up = (bool)(keyPressed&1);
+ player->control.down = (bool)(keyPressed&2);
+ player->control.left = (bool)(keyPressed&4);
+ player->control.right = (bool)(keyPressed&8);
+ player->control.jump = (bool)(keyPressed&16);
+ player->control.aux1 = (bool)(keyPressed&32);
+ player->control.sneak = (bool)(keyPressed&64);
+ player->control.LMB = (bool)(keyPressed&128);
+ player->control.RMB = (bool)(keyPressed&256);
/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
message += (wchar_t)readU16(buf);
}
+ // If something goes wrong, this player is to blame
+ RollbackScopeActor rollback_scope(m_rollback,
+ std::string("player:")+player->getName());
+
// Get player name of this client
std::wstring name = narrow_to_wide(player->getName());
// Whether to send to other players
bool send_to_others = false;
- // Parse commands
+ // Commands are implemented in Lua, so only catch invalid
+ // commands that were not "eaten" and send an error back
if(message[0] == L'/')
{
- size_t strip_size = 1;
- if (message[1] == L'#') // support old-style commans
- ++strip_size;
- message = message.substr(strip_size);
-
- WStrfnd f1(message);
- f1.next(L" "); // Skip over /#whatever
- std::wstring paramstring = f1.next(L"");
-
- ServerCommandContext *ctx = new ServerCommandContext(
- str_split(message, L' '),
- paramstring,
- this,
- m_env,
- player);
-
- std::wstring reply(processServerCommand(ctx));
- send_to_sender = ctx->flags & SEND_TO_SENDER;
- send_to_others = ctx->flags & SEND_TO_OTHERS;
-
- if (ctx->flags & SEND_NO_PREFIX)
- line += reply;
+ message = message.substr(1);
+ send_to_sender = true;
+ if(message.length() == 0)
+ line += L"-!- Empty command";
else
- line += L"Server: " + reply;
-
- delete ctx;
-
+ line += L"-!- Invalid command: " + str_split(message, L' ')[0];
}
else
{
// (definitions and files)
getClient(peer_id)->definitions_sent = true;
}
+ else if(command == TOSERVER_RECEIVED_MEDIA) {
+ getClient(peer_id)->definitions_sent = true;
+ }
else if(command == TOSERVER_INTERACT)
{
std::string datastring((char*)&data[2], datasize-2);
}
} // action == 4
+
/*
Catch invalid actions
}
void Server::SendNodeDef(con::Connection &con, u16 peer_id,
- INodeDefManager *nodedef)
+ INodeDefManager *nodedef, u16 protocol_version)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
*/
writeU16(os, TOCLIENT_NODEDEF);
std::ostringstream tmp_os(std::ios::binary);
- nodedef->serialize(tmp_os);
+ nodedef->serialize(tmp_os, protocol_version);
std::ostringstream tmp_os2(std::ios::binary);
compressZlib(tmp_os.str(), tmp_os2);
os<<serializeLongString(tmp_os2.str());
paths.push_back(mod.path + DIR_DELIM + "textures");
paths.push_back(mod.path + DIR_DELIM + "sounds");
paths.push_back(mod.path + DIR_DELIM + "media");
+ paths.push_back(mod.path + DIR_DELIM + "models");
}
std::string path_all = "textures";
paths.push_back(path_all + DIR_DELIM + "all");
".png", ".jpg", ".bmp", ".tga",
".pcx", ".ppm", ".psd", ".wal", ".rgb",
".ogg",
+ ".x", ".b3d", ".md2", ".obj",
NULL
};
if(removeStringEnd(filename, supported_ext) == ""){
os<<serializeString(j->name);
os<<serializeString(j->sha1_digest);
}
+ os<<serializeString(g_settings->get("remote_media"));
// Make data buffer
std::string s = os.str();
// Send as reliable
m_con.Send(peer_id, 0, data, true);
-
}
struct SendableMedia
// Uptime
os<<L", uptime="<<m_uptime.get();
// Information about clients
+ core::map<u16, RemoteClient*>::Iterator i;
+ bool first;
os<<L", clients={";
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
+ for(i = m_clients.getIterator(), first = true;
i.atEnd() == false; i++)
{
// Get client and check that it is valid
if(player != NULL)
name = narrow_to_wide(player->getName());
// Add name to information string
- os<<name<<L",";
+ if(!first)
+ os<<L",";
+ else
+ first = false;
+ os<<name;
}
os<<L"}";
if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
log->push_back(os.str());
}else{
std::ostringstream os;
- os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
+ os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
if(log)
log->push_back(os.str());
{
return NULL;
}
+IShaderSource* Server::getShaderSource()
+{
+ return NULL;
+}
u16 Server::allocateUnknownNodeId(const std::string &name)
{
return m_nodedef->allocateDummy(name);
}
IRollbackReportSink* Server::getRollbackReportSink()
{
+ if(!m_enable_rollback_recording)
+ return NULL;
if(!m_rollback_sink_enabled)
return NULL;
return m_rollback;