#include "environment.h"
#include "map.h"
#include "jthread/jmutexautolock.h"
-#include "main.h"
#include "constants.h"
#include "voxel.h"
#include "config.h"
m_script = new GameScripting(this);
- std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
+ std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
- if (!m_script->loadScript(scriptpath))
- throw ModError("Failed to load and run " + scriptpath);
+ if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME)) {
+ throw ModError("Failed to load and run " + script_path);
+ }
- // Print 'em
- infostream<<"Server: Loading mods: ";
+ // Print mods
+ infostream << "Server: Loading mods: ";
for(std::vector<ModSpec>::iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
- infostream<<mod.name<<" ";
+ infostream << mod.name << " ";
}
- infostream<<std::endl;
+ infostream << std::endl;
// Load and run "mod" scripts
- for(std::vector<ModSpec>::iterator i = m_mods.begin();
- i != m_mods.end(); i++){
+ for (std::vector<ModSpec>::iterator i = m_mods.begin();
+ i != m_mods.end(); i++) {
const ModSpec &mod = *i;
- std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
- infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
- <<scriptpath<<"\"]"<<std::endl;
- bool success = m_script->loadMod(scriptpath, mod.name);
- if(!success){
- errorstream<<"Server: Failed to load and run "
- <<scriptpath<<std::endl;
- throw ModError("Failed to load and run "+scriptpath);
+ if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
+ errorstream << "Error loading mod \"" << mod.name
+ << "\": mod_name does not follow naming conventions: "
+ << "Only chararacters [a-z0-9_] are allowed." << std::endl;
+ throw ModError("Mod \"" + mod.name + "\" does not follow naming conventions.");
+ }
+ std::string script_path = mod.path + DIR_DELIM "init.lua";
+ infostream << " [" << padStringRight(mod.name, 12) << "] [\""
+ << script_path << "\"]" << std::endl;
+ if (!m_script->loadMod(script_path, mod.name)) {
+ errorstream << "Server: Failed to load and run "
+ << script_path << std::endl;
+ throw ModError("Failed to load and run " + script_path);
}
}
m_nodedef->setNodeRegistrationStatus(true);
// Perform pending node name resolutions
- m_nodedef->runNodeResolverCallbacks();
+ m_nodedef->runNodeResolveCallbacks();
+
+ // init the recipe hashes to speed up crafting
+ m_craftdef->initHashes(this);
// Initialize Environment
m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
DSTACK(__FUNCTION_NAME);
SharedBuffer<u8> data;
u16 peer_id;
- u32 datasize;
try {
- datasize = m_con.Receive(peer_id,data);
- ProcessData(*data, datasize, peer_id);
+ NetworkPacket pkt;
+ m_con.Receive(&pkt);
+ peer_id = pkt.getPeerId();
+ ProcessData(&pkt);
}
catch(con::InvalidIncomingDataException &e) {
infostream<<"Server::Receive(): "
(this->*opHandle.handler)(pkt);
}
-void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
+void Server::ProcessData(NetworkPacket *pkt)
{
DSTACK(__FUNCTION_NAME);
// Environment is locked first.
JMutexAutoLock envlock(m_env_mutex);
ScopeProfiler sp(g_profiler, "Server::ProcessData");
+ u32 peer_id = pkt->getPeerId();
try {
Address address = getPeerAddress(peer_id);
* respond for some time, your server was overloaded or
* things like that.
*/
- infostream << "Server::ProcessData(): Cancelling: peer "
+ infostream << "Server::ProcessData(): Canceling: peer "
<< peer_id << " not found" << std::endl;
return;
}
try {
- if(datasize < 2)
- return;
-
- NetworkPacket pkt(data, datasize, peer_id);
-
- ToServerCommand command = (ToServerCommand) pkt.getCommand();
+ ToServerCommand command = (ToServerCommand) pkt->getCommand();
// Command must be handled into ToServerCommandHandler
if (command >= TOSERVER_NUM_MSG_TYPES) {
}
if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
- handleCommand(&pkt);
+ handleCommand(pkt);
return;
}
/* Handle commands related to client startup */
if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
- handleCommand(&pkt);
+ handleCommand(pkt);
return;
}
return;
}
- handleCommand(&pkt);
- }
- catch(SendFailedException &e) {
+ handleCommand(pkt);
+ } catch (SendFailedException &e) {
errorstream << "Server::ProcessData(): SendFailedException: "
<< "what=" << e.what()
<< std::endl;
+ } catch (PacketError &e) {
+ actionstream << "Server::ProcessData(): PacketError: "
+ << "what=" << e.what()
+ << std::endl;
}
}
Send(&pkt);
}
-void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
+void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
{
DSTACK(__FUNCTION_NAME);
{
DSTACK(__FUNCTION_NAME);
PlayerSAO *playersao = getPlayerSAO(peer_id);
- assert(playersao);
+ // In some rare case, if the player is disconnected
+ // while Lua call l_punch, for example, this can be NULL
+ if (!playersao)
+ return;
+
SendHP(peer_id, playersao->getHP());
m_script->player_event(playersao,"health_changed");
u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
{
- NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, peer_id);
+ NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
pkt.putRawString(datas.c_str(), datas.size());
Send(&pkt);
return pkt.getSize();
void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
{
NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
- 0, peer_id);
+ datas.size(), peer_id);
pkt.putRawString(datas.c_str(), datas.size());
m_clients.send(pkt.getPeerId(),
- clientCommandFactoryTable[pkt.getCommand()].channel,
+ reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
&pkt, reliable);
}
bool repositioned = m_script->on_respawnplayer(playersao);
if(!repositioned){
- v3f pos = findSpawnPos(m_env->getServerMap());
+ v3f pos = findSpawnPos();
// setPos will send the new position to client
playersao->setPos(pos);
}
}
+void Server::DenySudoAccess(u16 peer_id)
+{
+ DSTACK(__FUNCTION_NAME);
-void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
+ NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
+ Send(&pkt);
+}
+
+void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
{
DSTACK(__FUNCTION_NAME);
m_con.DisconnectPeer(peer_id);
}
+void Server::acceptAuth(u16 peer_id, bool forSudoMode)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ if (!forSudoMode) {
+ RemoteClient* client = getClient(peer_id, CS_Invalid);
+
+ NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
+
+ // Right now, the auth mechs don't change between login and sudo mode.
+ u32 sudo_auth_mechs = client->allowed_auth_mechs;
+ client->allowed_sudo_mechs = sudo_auth_mechs;
+
+ resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
+ << g_settings->getFloat("dedicated_server_step")
+ << sudo_auth_mechs;
+
+ Send(&resp_pkt);
+ m_clients.event(peer_id, CSE_AuthAccept);
+ } else {
+ NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
+
+ // We only support SRP right now
+ u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
+
+ resp_pkt << sudo_auth_mechs;
+ Send(&resp_pkt);
+ m_clients.event(peer_id, CSE_SudoSuccess);
+ }
+}
+
void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
{
DSTACK(__FUNCTION_NAME);
std::wostringstream os(std::ios_base::binary);
os<<L"# Server: ";
// Version
- os<<L"version="<<narrow_to_wide(minetest_version_simple);
+ os<<L"version="<<narrow_to_wide(g_version_string);
// Uptime
os<<L", uptime="<<m_uptime.get();
// Max lag estimate
return m_craftdef;
}
-const ModSpec* Server::getModSpec(const std::string &modname)
+const ModSpec* Server::getModSpec(const std::string &modname) const
{
- for(std::vector<ModSpec>::iterator i = m_mods.begin();
+ for(std::vector<ModSpec>::const_iterator i = m_mods.begin();
i != m_mods.end(); i++){
const ModSpec &mod = *i;
if(mod.name == modname)
return porting::path_share + DIR_DELIM + "builtin";
}
-v3f findSpawnPos(ServerMap &map)
+v3f Server::findSpawnPos()
{
- //return v3f(50,50,50)*BS;
-
- v3s16 nodepos;
+ ServerMap &map = m_env->getServerMap();
+ v3f nodeposf;
+ if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
+ return nodeposf * BS;
+ }
-#if 0
- nodepos = v2s16(0,0);
- groundheight = 20;
-#endif
+ // Default position is static_spawnpoint
+ // We will return it if we don't found a good place
+ v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
-#if 1
s16 water_level = map.getWaterLevel();
+ bool is_good = false;
+
// Try to find a good place a few times
- for(s32 i=0; i<1000; i++)
- {
+ for(s32 i = 0; i < 1000 && !is_good; i++) {
s32 range = 1 + i;
// We're going to try to throw the player to this position
v2s16 nodepos2d = v2s16(
continue;
nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
- bool is_good = false;
+
s32 air_count = 0;
for (s32 i = 0; i < 10; i++) {
v3s16 blockpos = getNodeBlockPos(nodepos);
}
nodepos.Y++;
}
- if(is_good){
- // Found a good place
- //infostream<<"Searched through "<<i<<" places."<<std::endl;
- break;
- }
}
-#endif
return intToFloat(nodepos, BS);
}
// Set player position
infostream<<"Server: Finding spawn place for player \""
<<name<<"\""<<std::endl;
- v3f pos = findSpawnPos(m_env->getServerMap());
+ v3f pos = findSpawnPos();
player->setPosition(pos);
// Make sure the player is saved