51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <set>
-#include <list>
-#include <map>
#include "environment.h"
#include "filesys.h"
#include "porting.h"
#include "mapblock.h"
#include "serverobject.h"
#include "content_sao.h"
-#include "mapgen.h"
#include "settings.h"
#include "log.h"
#include "profiler.h"
-#include "cpp_api/scriptapi.h"
+#include "scripting_game.h"
#include "nodedef.h"
#include "nodemetadata.h"
#include "main.h" // For g_settings, g_profiler
#endif
#include "daynightratio.h"
#include "map.h"
+#include "emerge.h"
#include "util/serialize.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
return newlist;
}
-void Environment::printPlayers(std::ostream &o)
-{
- o<<"Players in environment:"<<std::endl;
- for(std::list<Player*>::iterator i = m_players.begin();
- i != m_players.end(); i++)
- {
- Player *player = *i;
- o<<"Player peer_id="<<player->peer_id<<std::endl;
- }
-}
-
u32 Environment::getDayNightRatio()
{
bool smooth = g_settings->getBool("enable_shaders");
ServerEnvironment
*/
-ServerEnvironment::ServerEnvironment(ServerMap *map, ScriptApi *scriptIface,
+ServerEnvironment::ServerEnvironment(ServerMap *map,
+ GameScripting *scriptIface,
IGameDef *gamedef, IBackgroundBlockEmerger *emerger):
m_map(map),
m_script(scriptIface),
m_recommended_send_interval(0.1),
m_max_lag_estimate(0.1)
{
+ m_use_weather = g_settings->getBool("weather");
}
ServerEnvironment::~ServerEnvironment()
if(player->checkModified())
{
// Open file and serialize
- std::ofstream os(path.c_str(), std::ios_base::binary);
- if(os.good() == false)
+ std::ostringstream ss(std::ios_base::binary);
+ player->serialize(ss);
+ if(!fs::safeWriteToFile(path, ss.str()))
{
- infostream<<"Failed to overwrite "<<path<<std::endl;
+ infostream<<"Failed to write "<<path<<std::endl;
continue;
}
- player->serialize(os);
saved_players.insert(player);
} else {
saved_players.insert(player);
/*infostream<<"Saving player "<<player->getName()<<" to "
<<path<<std::endl;*/
// Open file and serialize
- std::ofstream os(path.c_str(), std::ios_base::binary);
- if(os.good() == false)
+ std::ostringstream ss(std::ios_base::binary);
+ player->serialize(ss);
+ if(!fs::safeWriteToFile(path, ss.str()))
{
- infostream<<"Failed to overwrite "<<path<<std::endl;
+ infostream<<"Failed to write "<<path<<std::endl;
continue;
}
- player->serialize(os);
saved_players.insert(player);
}
}
std::string path = savedir + "/env_meta.txt";
// Open file and serialize
- std::ofstream os(path.c_str(), std::ios_base::binary);
- if(os.good() == false)
- {
- infostream<<"ServerEnvironment::saveMeta(): Failed to open "
- <<path<<std::endl;
- throw SerializationError("Couldn't save env meta");
- }
+ std::ostringstream ss(std::ios_base::binary);
Settings args;
args.setU64("game_time", m_game_time);
args.setU64("time_of_day", getTimeOfDay());
- args.writeLines(os);
- os<<"EnvArgsEnd\n";
+ args.writeLines(ss);
+ ss<<"EnvArgsEnd\n";
+
+ if(!fs::safeWriteToFile(path, ss.str()))
+ {
+ infostream<<"ServerEnvironment::saveMeta(): Failed to write "
+ <<path<<std::endl;
+ throw SerializationError("Couldn't save env meta");
+ }
}
void ServerEnvironment::loadMeta(const std::string &savedir)
return true;
}
+bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
+{
+ return m_map->addNodeWithEvent(p, n, false);
+}
+
std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
{
std::set<u16> objects;
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
if(block==NULL){
// Block needs to be fetched first
- m_emerger->queueBlockEmerge(p, false);
+ m_emerger->enqueueBlockEmerge(
+ PEER_ID_INEXISTENT, p, false);
m_active_blocks.m_list.erase(p);
continue;
}
ServerActiveObject *object = i->second;
if(object == NULL)
continue;
- // Discard if removed
- if(object->m_removed)
+ // Discard if removed or deactivating
+ if(object->m_removed || object->m_pending_deactivation)
continue;
if(object->unlimitedTransferDistance() == false){
// Discard if too far
continue;
}
- if(object->m_removed)
+ if(object->m_removed || object->m_pending_deactivation)
{
removed_objects.insert(id);
continue;
if(m_active_object_messages.empty())
return ActiveObjectMessage(0);
- return m_active_object_messages.pop_front();
+ ActiveObjectMessage message = m_active_object_messages.front();
+ m_active_object_messages.pop_front();
+ return message;
}
/*
StaticObject s_obj(object->getType(), objectpos, staticdata);
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
- MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
- if(block)
- {
+ MapBlock *block = m_map->emergeBlock(blockpos);
+ if(block){
block->m_static_objects.m_active[object->getId()] = s_obj;
object->m_static_exists = true;
object->m_static_block = blockpos;
if(set_changed)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"addActiveObjectRaw");
- }
- else{
+ } else {
v3s16 p = floatToInt(objectpos, BS);
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"could not find block for storing id="<<object->getId()
+ <<"could not emerge block for storing id="<<object->getId()
<<" statically (pos="<<PP(p)<<")"<<std::endl;
}
}
if (block) {
block->m_static_objects.remove(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
- "removeRemovedObjects");
+ "removeRemovedObjects/remove");
obj->m_static_exists = false;
} else {
- infostream << "failed to emerge block from which "
- "an object to be removed was loaded from. id="<<id<<std::endl;
+ infostream<<"Failed to emerge block from which an object to "
+ <<"be removed was loaded from. id="<<id<<std::endl;
}
}
- // If m_known_by_count > 0, don't actually remove.
+ // If m_known_by_count > 0, don't actually remove. On some future
+ // invocation this will be 0, which is when removal will continue.
if(obj->m_known_by_count > 0)
continue;
-
+
+ /*
+ Move static data from active to stored if not marked as removed
+ */
+ if(obj->m_static_exists && !obj->m_removed){
+ MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
+ if (block) {
+ std::map<u16, StaticObject>::iterator i =
+ block->m_static_objects.m_active.find(id);
+ if(i != block->m_static_objects.m_active.end()){
+ block->m_static_objects.m_stored.push_back(i->second);
+ block->m_static_objects.m_active.erase(id);
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ "removeRemovedObjects/deactivate");
+ }
+ } else {
+ infostream<<"Failed to emerge block from which an object to "
+ <<"be deactivated was loaded from. id="<<id<<std::endl;
+ }
+ }
+
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
<<"activating objects of block "<<PP(block->getPos())
<<" ("<<block->m_static_objects.m_stored.size()
<<" objects)"<<std::endl;
- bool large_amount = (block->m_static_objects.m_stored.size() > 49);
+ bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
if(large_amount){
errorstream<<"suspiciously large amount of objects detected: "
<<block->m_static_objects.m_stored.size()<<" in "
"large amount of objects");
return;
}
- // A list for objects that couldn't be converted to active for some
- // reason. They will be stored back.
+
+ // Activate stored objects
std::list<StaticObject> new_stored;
- // Loop through stored static objects
for(std::list<StaticObject>::iterator
i = block->m_static_objects.m_stored.begin();
i != block->m_static_objects.m_stored.end(); ++i)
StaticObject &s_obj = *i;
block->m_static_objects.m_stored.push_back(s_obj);
}
+
+ // Turn the active counterparts of activated objects not pending for
+ // deactivation
+ for(std::map<u16, StaticObject>::iterator
+ i = block->m_static_objects.m_active.begin();
+ i != block->m_static_objects.m_active.end(); ++i)
+ {
+ u16 id = i->first;
+ ServerActiveObject *object = getActiveObject(id);
+ assert(object);
+ object->m_pending_deactivation = false;
+ }
+
/*
Note: Block hasn't really been modified here.
The objects have just been activated and moved from the stored
// The block in which the object resides in
v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
+ // If object's static data is stored in a deactivated block and object
+ // is actually located in an active block, re-save to the block in
+ // which the object is actually located in.
+ if(!force_delete &&
+ obj->m_static_exists &&
+ !m_active_blocks.contains(obj->m_static_block) &&
+ m_active_blocks.contains(blockpos_o))
+ {
+ v3s16 old_static_block = obj->m_static_block;
+
+ // Save to block where object is located
+ MapBlock *block = m_map->emergeBlock(blockpos_o, false);
+ if(!block){
+ errorstream<<"ServerEnvironment::deactivateFarObjects(): "
+ <<"Could not save object id="<<id
+ <<" to it's current block "<<PP(blockpos_o)
+ <<std::endl;
+ continue;
+ }
+ std::string staticdata_new = obj->getStaticData();
+ StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
+ block->m_static_objects.insert(id, s_obj);
+ obj->m_static_block = blockpos_o;
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ "deactivateFarObjects: Static data moved in");
+
+ // Delete from block where object was located
+ block = m_map->emergeBlock(old_static_block, false);
+ if(!block){
+ errorstream<<"ServerEnvironment::deactivateFarObjects(): "
+ <<"Could not delete object id="<<id
+ <<" from it's previous block "<<PP(old_static_block)
+ <<std::endl;
+ continue;
+ }
+ block->m_static_objects.remove(id);
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ "deactivateFarObjects: Static data moved out");
+ continue;
+ }
+
// If block is active, don't remove
if(!force_delete && m_active_blocks.contains(blockpos_o))
continue;
block = m_map->emergeBlock(blockpos);
} catch(InvalidPositionException &e){
// Handled via NULL pointer
+ // NOTE: emergeBlock's failure is usually determined by it
+ // actually returning NULL
}
if(block)
{
- if(block->m_static_objects.m_stored.size() >= 49){
+ if(block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")){
errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
<<" statically but block "<<PP(blockpos)
<<" already contains "
<<block->m_static_objects.m_stored.size()
- <<" (over 49) objects."
+ <<" objects."
<<" Forcing delete."<<std::endl;
force_delete = true;
} else {
- // If static counterpart already exists, remove it first.
- // This shouldn't happen, but happens rarely for some
- // unknown reason. Unsuccessful attempts have been made to
- // find said reason.
+ // If static counterpart already exists in target block,
+ // remove it first.
+ // This shouldn't happen because the object is removed from
+ // the previous block before this according to
+ // obj->m_static_block, but happens rarely for some unknown
+ // reason. Unsuccessful attempts have been made to find
+ // said reason.
if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
infostream<<"ServerEnv: WARNING: Performing hack #83274"
<<std::endl;
block->m_static_objects.remove(id);
}
- //store static data
- block->m_static_objects.insert(0, s_obj);
+ // Store static data
+ u16 store_id = pending_delete ? id : 0;
+ block->m_static_objects.insert(store_id, s_obj);
// Only mark block as modified if data changed considerably
if(shall_be_written)
v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
MapNode n = m_map->getNodeNoEx(p);
ContentFeatures c = m_gamedef->ndef()->get(n);
- if(c.isLiquid() && c.drowning && lplayer->hp > 0){
+ u8 drowning_damage = c.drowning;
+ if(drowning_damage > 0 && lplayer->hp > 0){
u16 breath = lplayer->getBreath();
if(breath > 10){
breath = 11;
updateLocalPlayerBreath(breath);
}
- if(lplayer->getBreath() == 0){
- damageLocalPlayer(1, true);
+ if(lplayer->getBreath() == 0 && drowning_damage > 0){
+ damageLocalPlayer(drowning_damage, true);
}
}
if(m_breathing_interval.step(dtime, 0.5))
if (!lplayer->hp){
lplayer->setBreath(11);
}
- else if(!c.isLiquid() || !c.drowning){
+ else if(c.drowning == 0){
u16 breath = lplayer->getBreath();
if(breath <= 10){
breath += 1;
ClientEnvEvent ClientEnvironment::getClientEvent()
{
+ ClientEnvEvent event;
if(m_client_event_queue.empty())
- {
- ClientEnvEvent event;
event.type = CEE_NONE;
- return event;
+ else {
+ event = m_client_event_queue.front();
+ m_client_event_queue.pop_front();
}
- return m_client_event_queue.pop_front();
+ return event;
}
#endif // #ifndef SERVER