#include "materials.h"
#include "mineral.h"
#include "config.h"
+#include "servercommand.h"
+#include "filesys.h"
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
*/
if(stepped_blocks.find(p) == NULL)
{
- block->stepObjects(dtime, true, server->getDayNightRatio());
+ block->stepObjects(dtime, true, server->m_env.getDayNightRatio());
stepped_blocks.insert(p, true);
block->setChangedFlag();
}
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
m_thread(this),
m_emergethread(this),
- m_time_of_day(9000),
m_time_counter(0),
m_time_of_day_send_timer(0),
m_uptime(0),
m_con_mutex.Init();
m_step_dtime_mutex.Init();
m_step_dtime = 0.0;
-
+
+ // Register us to receive map edit events
m_env.getMap().addEventReceiver(this);
+ // If file exists, load environment metadata
+ if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
+ {
+ dstream<<"Server: Loading environment metadata"<<std::endl;
+ m_env.loadMeta(m_mapsavedir);
+ }
+
// Load players
+ dstream<<"Server: Loading players"<<std::endl;
m_env.deSerializePlayers(m_mapsavedir);
}
*/
dstream<<"Server: Saving players"<<std::endl;
m_env.serializePlayers(m_mapsavedir);
+
+ /*
+ Save environment metadata
+ */
+ dstream<<"Server: Saving environment metadata"<<std::endl;
+ m_env.saveMeta(m_mapsavedir);
/*
Stop threads
}
/*
- Update m_time_of_day
+ Update m_time_of_day and overall game time
*/
{
+ JMutexAutoLock envlock(m_env_mutex);
+
m_time_counter += dtime;
f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
u32 units = (u32)(m_time_counter*speed);
m_time_counter -= (f32)units / speed;
- m_time_of_day.set((m_time_of_day.get() + units) % 24000);
+
+ m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
//dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
//Player *player = m_env.getPlayer(client->peer_id);
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
- m_time_of_day.get());
+ m_env.getTimeOfDay());
// Send as reliable
m_con.Send(client->peer_id, 0, data, true);
}
// Save players
m_env.serializePlayers(m_mapsavedir);
+
+ // Save environment metadata
+ m_env.saveMeta(m_mapsavedir);
}
}
}
// [0] u16 TOSERVER_INIT
// [2] u8 SER_FMT_VER_HIGHEST
// [3] u8[20] player_name
+ // [23] u8[28] password <--- can be sent without this, from old versions
- if(datasize < 3)
+ if(datasize < 2+1+PLAYERNAME_SIZE)
return;
derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
*/
// Get player name
- const u32 playername_size = 20;
- char playername[playername_size];
- for(u32 i=0; i<playername_size-1; i++)
+ char playername[PLAYERNAME_SIZE];
+ for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
{
playername[i] = data[3+i];
}
- playername[playername_size-1] = 0;
-
+ playername[PLAYERNAME_SIZE-1] = 0;
+
+ // Get password
+ char password[PASSWORD_SIZE];
+ if(datasize == 2+1+PLAYERNAME_SIZE)
+ {
+ // old version - assume blank password
+ password[0] = 0;
+ }
+ else
+ {
+ for(u32 i=0; i<PASSWORD_SIZE-1; i++)
+ {
+ password[i] = data[23+i];
+ }
+ password[PASSWORD_SIZE-1] = 0;
+ }
+ Player *checkplayer = m_env.getPlayer(playername);
+ if(checkplayer != NULL && strcmp(checkplayer->getPassword(),password))
+ {
+ derr_server<<DTIME<<"Server: peer_id="<<peer_id
+ <<": supplied invalid password for "
+ <<playername<<std::endl;
+ SendAccessDenied(m_con, peer_id);
+ return;
+ }
+
// Get player
- Player *player = emergePlayer(playername, "", peer_id);
- //Player *player = m_env.getPlayer(peer_id);
+ Player *player = emergePlayer(playername, password, peer_id);
+
/*{
// DEBUG: Test serialization
// Send time of day
{
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
- m_time_of_day.get());
+ m_env.getTimeOfDay());
m_con.Send(peer->id, 0, data, true);
}
if(datasize < 13)
return;
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
+
/*
[0] u16 command
[2] u8 button (0=left, 1=right)
if(datasize < 7)
return;
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
+
/*
length: 7
[0] u16 command
// Mandatory parameter; actually used for nothing
core::map<v3s16, MapBlock*> modified_blocks;
- u8 material;
+ u8 material = CONTENT_IGNORE;
u8 mineral = MINERAL_NONE;
bool cannot_remove_node = false;
cannot_remove_node = true;
}
+ // Make sure the player is allowed to do it
+ if((player->privs & PRIV_BUILD) == 0)
+ cannot_remove_node = true;
+
/*
If node can't be removed, set block to be re-sent to
client and quit.
try{
// Don't add a node if this is not a free space
MapNode n2 = m_env.getMap().getNode(p_over);
- if(content_buildable_to(n2.d) == false)
+ if(content_buildable_to(n2.d) == false
+ || (player->privs & PRIV_BUILD) ==0)
{
// Client probably has wrong data.
// Set block not sent, so that client will get
#endif
else if(command == TOSERVER_SIGNTEXT)
{
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
/*
u16 command
v3s16 blockpos
}
else if(command == TOSERVER_SIGNNODETEXT)
{
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
/*
u16 command
v3s16 p
// Whether to send to other players
bool send_to_others = false;
+ // Local player gets all privileges regardless of
+ // what's set on their account.
+ u64 privs = player->privs;
+ if(g_settings.get("name") == player->getName())
+ privs = PRIV_ALL;
+
// Parse commands
std::wstring commandprefix = L"/#";
if(message.substr(0, commandprefix.size()) == commandprefix)
line += L"Server: ";
message = message.substr(commandprefix.size());
- // Get player name as narrow string
- std::string name_s = player->getName();
- // Convert message to narrow string
- std::string message_s = wide_to_narrow(message);
- // Operator is the single name defined in config.
- std::string operator_name = g_settings.get("name");
- bool is_operator = (operator_name != "" &&
- wide_to_narrow(name) == operator_name);
- bool valid_command = false;
- if(message_s == "help")
- {
- line += L"-!- Available commands: ";
- line += L"status ";
- if(is_operator)
- {
- line += L"shutdown setting time ";
- }
- else
- {
- }
- send_to_sender = true;
- valid_command = true;
- }
- else if(message_s == "status")
- {
- line = getStatusString();
- send_to_sender = true;
- valid_command = true;
- }
- else if(is_operator)
+
+ ServerCommandContext *ctx = new ServerCommandContext(
+ str_split(message, L' '),
+ this,
+ &m_env,
+ player,
+ privs);
+
+ line += processServerCommand(ctx);
+ send_to_sender = ctx->flags & 1;
+ send_to_others = ctx->flags & 2;
+ delete ctx;
+
+ }
+ else
+ {
+ if(privs & PRIV_SHOUT)
{
- if(message_s == "shutdown")
- {
- dstream<<DTIME<<" Server: Operator requested shutdown."
- <<std::endl;
- m_shutdown_requested.set(true);
-
- line += L"*** Server shutting down (operator request)";
- send_to_sender = true;
- valid_command = true;
- }
- else if(message_s.substr(0,8) == "setting ")
- {
- std::string confline = message_s.substr(8);
- g_settings.parseConfigLine(confline);
- line += L"-!- Setting changed.";
- send_to_sender = true;
- valid_command = true;
- }
- else if(message_s.substr(0,5) == "time ")
- {
- u32 time = stoi(message_s.substr(5));
- m_time_of_day.set(time);
- m_time_of_day_send_timer = 0;
- line += L"-!- time_of_day changed.";
- send_to_sender = true;
- valid_command = true;
- }
+ line += L"<";
+ line += name;
+ line += L"> ";
+ line += message;
+ send_to_others = true;
}
-
- if(valid_command == false)
+ else
{
- line += L"-!- Invalid command: " + message;
+ line += L"Server: You are not allowed to shout";
send_to_sender = true;
}
}
- else
- {
- line += L"<";
- /*if(is_operator)
- line += L"@";*/
- line += name;
- line += L"> ";
- line += message;
- send_to_others = true;
- }
if(line != L"")
{
SendPlayerHP(player);
}
+ else if(command == TOSERVER_PASSWORD)
+ {
+ /*
+ [0] u16 TOSERVER_PASSWORD
+ [2] u8[28] old password
+ [30] u8[28] new password
+ */
+
+ if(datasize != 2+PASSWORD_SIZE*2)
+ return;
+ char password[PASSWORD_SIZE];
+ for(u32 i=0; i<PASSWORD_SIZE-1; i++)
+ password[i] = data[2+i];
+ password[PASSWORD_SIZE-1] = 0;
+ if(strcmp(player->getPassword(),password))
+ {
+ // Wrong old password supplied!!
+ SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
+ return;
+ }
+ for(u32 i=0; i<PASSWORD_SIZE-1; i++)
+ password[i] = data[30+i];
+ player->updatePassword(password);
+ SendChatMessage(peer_id, L"Password change successful");
+ }
else
{
derr_server<<"WARNING: Server::ProcessData(): Ignoring "
con.Send(peer_id, 0, data, true);
}
+void Server::SendAccessDenied(con::Connection &con, u16 peer_id)
+{
+ DSTACK(__FUNCTION_NAME);
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOCLIENT_ACCESS_DENIED);
+
+ // 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);
+}
+
/*
Non-static send methods
*/
}
}
+ // Fence
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
+ specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
+ specs[5] = ItemSpec(ITEM_CRAFT, "Stick");
+ specs[6] = ItemSpec(ITEM_CRAFT, "Stick");
+ specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+ specs[8] = ItemSpec(ITEM_CRAFT, "Stick");
+ if(checkItemCombination(items, specs))
+ {
+ rlist->addItem(new MaterialItem(CONTENT_FENCE, 2));
+ found = true;
+ }
+ }
+
// Sign
if(!found)
{
found = true;
}
}
+
+ // Sandstone
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND);
+ specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND);
+ specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND);
+ specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND);
+ if(checkItemCombination(items, specs))
+ {
+ rlist->addItem(new MaterialItem(CONTENT_SANDSTONE, 1));
+ found = true;
+ }
+ }
}
} // if creative_mode == false
CONTENT_MUD,
CONTENT_STONE,
CONTENT_SAND,
+ CONTENT_SANDSTONE,
CONTENT_TREE,
CONTENT_LEAVES,
+ CONTENT_GLASS,
+ CONTENT_FENCE,
CONTENT_MESE,
CONTENT_WATERSOURCE,
CONTENT_CLOUD,
), BS);
}
-Player *Server::emergePlayer(const char *name, const char *password,
- u16 peer_id)
+Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
{
/*
Try to get an existing player
//player->peer_id = PEER_ID_INEXISTENT;
player->peer_id = peer_id;
player->updateName(name);
+ player->updatePassword(password);
+
+ if(g_settings.exists("default_privs"))
+ player->privs = g_settings.getU64("default_privs");
/*
Set player position