#include "environment.h"
#include "map.h"
#include "jthread/jmutexautolock.h"
-#include "main.h"
#include "constants.h"
#include "voxel.h"
#include "config.h"
infostream<<"- game: "<<m_gamespec.path<<std::endl;
// Create world if it doesn't exist
- if(!initializeWorld(m_path_world, m_gamespec.id))
+ if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
throw ServerError("Failed to initialize world");
// Create server thread
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);
}
// Throw if fatal error occurred in thread
std::string async_err = m_async_fatal_error.get();
- if(async_err != ""){
- throw ServerError(async_err);
+ if(async_err != "") {
+ if (m_simple_singleplayer_mode) {
+ throw ServerError(async_err);
+ }
+ else {
+ errorstream << "UNRECOVERABLE error occurred. Stopping server. "
+ << "Please fix the following error:" << std::endl
+ << async_err << std::endl;
+ FATAL_ERROR(async_err.c_str());
+ }
}
}
}
if(unreliable_data.size() > 0) {
- SendActiveObjectMessages(client->peer_id, unreliable_data);
+ SendActiveObjectMessages(client->peer_id, unreliable_data, false);
}
}
m_clients.Unlock();
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);
+ handleCommand(pkt);
}
catch(SendFailedException &e) {
errorstream << "Server::ProcessData(): SendFailedException: "
}
return NULL;
}
-void Server::setInventoryModified(const InventoryLocation &loc)
+void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
{
switch(loc.type){
case InventoryLocation::UNDEFINED:
break;
case InventoryLocation::PLAYER:
{
+ if (!playerSend)
+ return;
+
Player *player = m_env->getPlayer(loc.name.c_str());
if(!player)
return;
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)
+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());
- Send(&pkt);
+
+ m_clients.send(pkt.getPeerId(),
+ reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
+ &pkt, reliable);
+
}
s32 Server::playSound(const SimpleSoundSpec &spec,
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::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
+void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_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 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