#include "threading/mutex_auto_lock.h"
#include "filesys.h"
#include "gameparams.h"
-#include "database-dummy.h"
-#include "database-files.h"
-#include "database-sqlite3.h"
+#include "database/database-dummy.h"
+#include "database/database-files.h"
+#include "database/database-sqlite3.h"
#if USE_POSTGRESQL
-#include "database-postgresql.h"
+#include "database/database-postgresql.h"
#endif
#include <algorithm>
{
// Add the lbm_def to the LBMContentMapping.
// Unknown names get added to the global NameIdMapping.
- INodeDefManager *nodedef = gamedef->ndef();
+ const NodeDefManager *nodedef = gamedef->ndef();
lbm_list.push_back(lbm_def);
}
}
-void ActiveBlockList::update(std::vector<v3s16> &active_positions,
- s16 radius,
+void fillViewConeBlock(v3s16 p0,
+ const s16 r,
+ const v3f camera_pos,
+ const v3f camera_dir,
+ const float camera_fov,
+ std::set<v3s16> &list)
+{
+ v3s16 p;
+ const s16 r_nodes = r * BS * MAP_BLOCKSIZE;
+ for (p.X = p0.X - r; p.X <= p0.X+r; p.X++)
+ for (p.Y = p0.Y - r; p.Y <= p0.Y+r; p.Y++)
+ for (p.Z = p0.Z - r; p.Z <= p0.Z+r; p.Z++) {
+ if (isBlockInSight(p, camera_pos, camera_dir, camera_fov, r_nodes)) {
+ list.insert(p);
+ }
+ }
+}
+
+void ActiveBlockList::update(std::vector<PlayerSAO*> &active_players,
+ s16 active_block_range,
+ s16 active_object_range,
std::set<v3s16> &blocks_removed,
std::set<v3s16> &blocks_added)
{
Create the new list
*/
std::set<v3s16> newlist = m_forceloaded_list;
- for (const v3s16 &active_position : active_positions) {
- fillRadiusBlock(active_position, radius, newlist);
+ m_abm_list = m_forceloaded_list;
+ for (const PlayerSAO *playersao : active_players) {
+ v3s16 pos = getNodeBlockPos(floatToInt(playersao->getBasePosition(), BS));
+ fillRadiusBlock(pos, active_block_range, m_abm_list);
+ fillRadiusBlock(pos, active_block_range, newlist);
+
+ s16 player_ao_range = std::min(active_object_range, playersao->getWantedRange());
+ // only do this if this would add blocks
+ if (player_ao_range > active_block_range) {
+ v3f camera_dir = v3f(0,0,1);
+ camera_dir.rotateYZBy(playersao->getPitch());
+ camera_dir.rotateXZBy(playersao->getYaw());
+ fillViewConeBlock(pos,
+ player_ao_range,
+ playersao->getEyePosition(),
+ camera_dir,
+ playersao->getFov(),
+ newlist);
+ }
}
/*
return *m_map;
}
-RemotePlayer *ServerEnvironment::getPlayer(const u16 peer_id)
+RemotePlayer *ServerEnvironment::getPlayer(const session_t peer_id)
{
for (RemotePlayer *player : m_players) {
- if (player->peer_id == peer_id)
+ if (player->getPeerId() == peer_id)
return player;
}
return NULL;
Exception: there can be multiple players with peer_id=0
*/
// If peer id is non-zero, it has to be unique.
- if (player->peer_id != 0)
- FATAL_ERROR_IF(getPlayer(player->peer_id) != NULL, "Peer id not unique");
+ if (player->getPeerId() != PEER_ID_INEXISTENT)
+ FATAL_ERROR_IF(getPlayer(player->getPeerId()) != NULL, "Peer id not unique");
// Name has to be unique.
FATAL_ERROR_IF(getPlayer(player->getName()) != NULL, "Player name not unique");
// Add.
return m_player_database->removePlayer(name);
}
-bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16 *p)
+bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, v3s16 *p)
{
- float distance = pos1.getDistanceFrom(pos2);
-
- //calculate normalized direction vector
- v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
- (pos2.Y - pos1.Y)/distance,
- (pos2.Z - pos1.Z)/distance);
-
- //find out if there's a node on path between pos1 and pos2
- for (float i = 1; i < distance; i += stepsize) {
- v3s16 pos = floatToInt(v3f(normalized_vector.X * i,
- normalized_vector.Y * i,
- normalized_vector.Z * i) +pos1,BS);
-
- MapNode n = getMap().getNodeNoEx(pos);
-
- if(n.param0 != CONTENT_AIR) {
- if (p) {
- *p = pos;
- }
+ // Iterate trough nodes on the line
+ voxalgo::VoxelLineIterator iterator(pos1 / BS, (pos2 - pos1) / BS);
+ do {
+ MapNode n = getMap().getNodeNoEx(iterator.m_current_node_pos);
+
+ // Return non-air
+ if (n.param0 != CONTENT_AIR) {
+ if (p)
+ *p = iterator.m_current_node_pos;
return false;
}
- }
+ iterator.next();
+ } while (iterator.m_current_index <= iterator.m_last_index);
return true;
}
const std::string &str_reason, bool reconnect)
{
for (RemotePlayer *player : m_players) {
- m_server->DenyAccessVerCompliant(player->peer_id,
+ m_server->DenyAccessVerCompliant(player->getPeerId(),
player->protocol_version, reason, str_reason, reconnect);
}
}
}
PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player,
- u16 peer_id, bool is_singleplayer)
+ session_t peer_id, bool is_singleplayer)
{
PlayerSAO *playersao = new PlayerSAO(this, player, peer_id, is_singleplayer);
// Create player if it doesn't exist
// If the player exists, ensure that they respawn inside legal bounds
// This fixes an assert crash when the player can't be added
// to the environment
- ServerMap &map = getServerMap();
- if (map.getMapgenParams()->saoPosOverLimit(playersao->getBasePosition())) {
+ if (objectpos_over_limit(playersao->getBasePosition())) {
actionstream << "Respawn position for player \""
<< player->getName() << "\" outside limits, resetting" << std::endl;
playersao->setBasePosition(m_server->findSpawnPos());
{
if(dtime_s < 0.001)
return;
- INodeDefManager *ndef = env->getGameDef()->ndef();
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
for (ABMWithState &abmws : abms) {
ActiveBlockModifier *abm = abmws.abm;
float trigger_interval = abm->getTriggerInterval();
elapsed_timer.position));
}
}
-
- /* Handle ActiveBlockModifiers */
- ABMHandler abmhandler(m_abms, dtime_s, this, false);
- abmhandler.apply(block);
}
void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
{
- INodeDefManager *ndef = m_server->ndef();
+ const NodeDefManager *ndef = m_server->ndef();
MapNode n_old = m_map->getNodeNoEx(p);
+ const ContentFeatures &cf_old = ndef->get(n_old);
+
// Call destructor
- if (ndef->get(n_old).has_on_destruct)
+ if (cf_old.has_on_destruct)
m_script->node_on_destruct(p, n_old);
// Replace node
m_map->updateVManip(p);
// Call post-destructor
- if (ndef->get(n_old).has_after_destruct)
+ if (cf_old.has_after_destruct)
m_script->node_after_destruct(p, n_old);
+ // Retrieve node content features
+ // if new node is same as old, reuse old definition to prevent a lookup
+ const ContentFeatures &cf_new = n_old == n ? cf_old : ndef->get(n);
+
// Call constructor
- if (ndef->get(n).has_on_construct)
+ if (cf_new.has_on_construct)
m_script->node_on_construct(p, n);
return true;
bool ServerEnvironment::removeNode(v3s16 p)
{
- INodeDefManager *ndef = m_server->ndef();
+ const NodeDefManager *ndef = m_server->ndef();
MapNode n_old = m_map->getNodeNoEx(p);
// Call destructor
<< "Removing all active objects" << std::endl;
std::vector<u16> objects_to_remove;
for (auto &it : m_active_objects) {
+ u16 id = it.first;
ServerActiveObject* obj = it.second;
if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
continue;
- u16 id = it.first;
+
// Delete static object if block is loaded
- if (obj->m_static_exists) {
- MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
- if (block) {
- block->m_static_objects.remove(id);
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_CLEAR_ALL_OBJECTS);
- obj->m_static_exists = false;
- }
- }
+ deleteStaticFromBlock(obj, id, MOD_REASON_CLEAR_ALL_OBJECTS, true);
+
// If known by some client, don't delete immediately
if (obj->m_known_by_count > 0) {
- obj->m_pending_deactivation = true;
- obj->m_removed = true;
+ obj->m_pending_removal = true;
continue;
}
loadable_blocks = loaded_blocks;
}
- infostream << "ServerEnvironment::clearObjects(): "
+ actionstream << "ServerEnvironment::clearObjects(): "
<< "Now clearing objects in " << loadable_blocks.size()
<< " blocks" << std::endl;
num_blocks_checked % report_interval == 0) {
float percent = 100.0 * (float)num_blocks_checked /
loadable_blocks.size();
- infostream << "ServerEnvironment::clearObjects(): "
+ actionstream << "ServerEnvironment::clearObjects(): "
<< "Cleared " << num_objs_cleared << " objects"
<< " in " << num_blocks_cleared << " blocks ("
<< percent << "%)" << std::endl;
m_last_clear_objects_time = m_game_time;
- infostream << "ServerEnvironment::clearObjects(): "
+ actionstream << "ServerEnvironment::clearObjects(): "
<< "Finished: Cleared " << num_objs_cleared << " objects"
<< " in " << num_blocks_cleared << " blocks" << std::endl;
}
ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
for (RemotePlayer *player : m_players) {
// Ignore disconnected players
- if (player->peer_id == 0)
+ if (player->getPeerId() == PEER_ID_INEXISTENT)
continue;
// Move
/*
Get player block positions
*/
- std::vector<v3s16> players_blockpos;
+ std::vector<PlayerSAO*> players;
for (RemotePlayer *player: m_players) {
// Ignore disconnected players
- if (player->peer_id == 0)
+ if (player->getPeerId() == PEER_ID_INEXISTENT)
continue;
PlayerSAO *playersao = player->getPlayerSAO();
assert(playersao);
- players_blockpos.push_back(
- getNodeBlockPos(floatToInt(playersao->getBasePosition(), BS)));
+ players.push_back(playersao);
}
/*
Update list of active blocks, collecting changes
*/
+ // use active_object_send_range_blocks since that is max distance
+ // for active objects sent the client anyway
+ static thread_local const s16 active_object_range =
+ g_settings->getS16("active_object_send_range_blocks");
static thread_local const s16 active_block_range =
g_settings->getS16("active_block_range");
std::set<v3s16> blocks_removed;
std::set<v3s16> blocks_added;
- m_active_blocks.update(players_blockpos, active_block_range,
+ m_active_blocks.update(players, active_block_range, active_object_range,
blocks_removed, blocks_added);
/*
MapBlock *block = m_map->getBlockOrEmerge(p);
if (!block) {
m_active_blocks.m_list.erase(p);
+ m_active_blocks.m_abm_list.erase(p);
continue;
}
// Initialize handling of ActiveBlockModifiers
ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true);
- for (const v3s16 &p : m_active_blocks.m_list) {
+ for (const v3s16 &p : m_active_blocks.m_abm_list) {
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
if (!block)
continue;
for (auto &ao_it : m_active_objects) {
ServerActiveObject* obj = ao_it.second;
- // Don't step if is to be removed or stored statically
- if(obj->m_removed || obj->m_pending_deactivation)
+ if (obj->isGone())
continue;
+
// Step object
obj->step(dtime, send_recommended);
// Read messages from object
- while(!obj->m_messages_out.empty())
- {
- m_active_object_messages.push(
- obj->m_messages_out.front());
+ while (!obj->m_messages_out.empty()) {
+ m_active_object_messages.push(obj->m_messages_out.front());
obj->m_messages_out.pop();
}
}
*/
if (m_object_management_interval.step(dtime, 0.5)) {
ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
- /*
- Remove objects that satisfy (m_removed && m_known_by_count==0)
- */
removeRemovedObjects();
}
player_radius_f = 0;
/*
Go through the object list,
- - discard m_removed objects,
+ - discard removed/deactivated objects,
- discard objects that are too far away,
- discard objects that are found in current_objects.
- add remaining objects to added_objects
if (object == NULL)
continue;
- // Discard if removed or deactivating
- if(object->m_removed || object->m_pending_deactivation)
+ if (object->isGone())
continue;
f32 distance_f = object->getBasePosition().
/*
Go through current_objects; object is removed if:
- object is not found in m_active_objects (this is actually an
- error condition; objects should be set m_removed=true and removed
- only after all clients have been informed about removal), or
- - object has m_removed=true, or
+ error condition; objects should be removed only after all clients
+ have been informed about removal), or
+ - object is to be removed or deactivated, or
- object is too far away
*/
for (u16 id : current_objects) {
continue;
}
- if (object->m_removed || object->m_pending_deactivation) {
+ if (object->isGone()) {
removed_objects.push(id);
continue;
}
}
/*
- Remove objects that satisfy (m_removed && m_known_by_count==0)
+ Remove objects that satisfy (isGone() && m_known_by_count==0)
*/
void ServerEnvironment::removeRemovedObjects()
{
for (auto &ao_it : m_active_objects) {
u16 id = ao_it.first;
ServerActiveObject* obj = ao_it.second;
+
// This shouldn't happen but check it
- if(obj == NULL)
- {
- infostream<<"NULL object found in ServerEnvironment"
- <<" while finding removed objects. id="<<id<<std::endl;
- // Id to be removed from m_active_objects
+ if (!obj) {
+ errorstream << "ServerEnvironment::removeRemovedObjects(): "
+ << "NULL object found. id=" << id << std::endl;
objects_to_remove.push_back(id);
continue;
}
/*
- We will delete objects that are marked as removed or thatare
- waiting for deletion after deactivation
+ We will handle objects marked for removal or deactivation
*/
- if (!obj->m_removed && !obj->m_pending_deactivation)
+ if (!obj->isGone())
continue;
/*
- Delete static data from block if is marked as removed
+ Delete static data from block if removed
*/
- if(obj->m_static_exists && obj->m_removed)
- {
- MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
- if (block) {
- block->m_static_objects.remove(id);
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_REMOVE_OBJECTS_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;
- }
- }
+ if (obj->m_pending_removal)
+ deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
- // If m_known_by_count > 0, don't actually remove. On some future
+ // If still known by clients, 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
+ Move static data from active to stored if deactivated
*/
- if(obj->m_static_exists && !obj->m_removed){
+ if (!obj->m_pending_removal && obj->m_static_exists) {
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()){
+ 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,
MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
+ } else {
+ warningstream << "ServerEnvironment::removeRemovedObjects(): "
+ << "id=" << id << " m_static_exists=true but "
+ << "static data doesn't actually exist in "
+ << PP(obj->m_static_block) << std::endl;
}
} else {
- infostream<<"Failed to emerge block from which an object to "
- <<"be deactivated was loaded from. id="<<id<<std::endl;
+ infostream << "Failed to emerge block from which an object to "
+ << "be deactivated was loaded from. id=" << id << std::endl;
}
}
if(obj->environmentDeletes())
delete obj;
- // Id to be removed from m_active_objects
objects_to_remove.push_back(id);
}
// Remove references from m_active_objects
// This will also add the object to the active static list
addActiveObjectRaw(obj, false, dtime_s);
}
+
// Clear stored list
block->m_static_objects.m_stored.clear();
// Add leftover failed stuff to stored list
block->m_static_objects.m_stored.push_back(s_obj);
}
- // Turn the active counterparts of activated objects not pending for
- // deactivation
- for (auto &i : block->m_static_objects.m_active) {
- 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
if(!force_delete && !obj->isStaticAllowed())
continue;
- // If pending deactivation, let removeRemovedObjects() do it
- if(!force_delete && obj->m_pending_deactivation)
+ // removeRemovedObjects() is responsible for these
+ if(!force_delete && obj->isGone())
continue;
u16 id = ao_it.first;
!m_active_blocks.contains(obj->m_static_block) &&
m_active_blocks.contains(blockpos_o))
{
- v3s16 old_static_block = obj->m_static_block;
+ // Delete from block where object was located
+ deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);
- // 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(&staticdata_new);
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,
- MOD_REASON_STATIC_DATA_ADDED);
+ // Save to block where object is located
+ saveStaticToBlock(blockpos_o, id, obj, s_obj, MOD_REASON_STATIC_DATA_ADDED);
- // 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,
- MOD_REASON_STATIC_DATA_REMOVED);
continue;
}
- // If block is active, don't remove
+ // If block is still active, don't remove
if(!force_delete && m_active_blocks.contains(blockpos_o))
continue;
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"deactivating object id="<<id<<" on inactive block "
- <<PP(blockpos_o)<<std::endl;
+ verbosestream << "ServerEnvironment::deactivateFarObjects(): "
+ << "deactivating object id=" << id << " on inactive block "
+ << PP(blockpos_o) << std::endl;
// If known by some client, don't immediately delete.
bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
/*
Update the static data
*/
-
if(obj->isStaticAllowed())
{
// Create new static object
bool stays_in_same_block = false;
bool data_changed = true;
+ // Check if static data has changed considerably
if (obj->m_static_exists) {
if (obj->m_static_block == blockpos_o)
stays_in_same_block = true;
(static_old.pos - objectpos).getLength() < save_movem)
data_changed = false;
} else {
- errorstream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"id="<<id<<" m_static_exists=true but "
- <<"static data doesn't actually exist in "
- <<PP(obj->m_static_block)<<std::endl;
+ warningstream << "ServerEnvironment::deactivateFarObjects(): "
+ << "id=" << id << " m_static_exists=true but "
+ << "static data doesn't actually exist in "
+ << PP(obj->m_static_block) << std::endl;
}
}
}
+ /*
+ While changes are always saved, blocks are only marked as modified
+ if the object has moved or different staticdata. (see above)
+ */
bool shall_be_written = (!stays_in_same_block || data_changed);
+ u32 reason = shall_be_written ? MOD_REASON_STATIC_DATA_CHANGED : MOD_REASON_UNKNOWN;
// Delete old static object
- if(obj->m_static_exists)
- {
- MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
- if(block)
- {
- block->m_static_objects.remove(id);
- obj->m_static_exists = false;
- // Only mark block as modified if data changed considerably
- if(shall_be_written)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_STATIC_DATA_CHANGED);
- }
- }
+ deleteStaticFromBlock(obj, id, reason, false);
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
- // Get or generate the block
- MapBlock *block = NULL;
- try{
- 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() >= g_settings->getU16("max_objects_per_block")) {
- warningstream << "ServerEnv: Trying to store id = " << obj->getId()
- << " statically but block " << PP(blockpos)
- << " already contains "
- << block->m_static_objects.m_stored.size()
- << " objects."
- << " Forcing delete." << std::endl;
- force_delete = true;
- } else {
- // 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()){
- warningstream<<"ServerEnv: Performing hack #83274"
- <<std::endl;
- block->m_static_objects.remove(id);
- }
- // 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)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_STATIC_DATA_CHANGED);
-
- obj->m_static_exists = true;
- obj->m_static_block = block->getPos();
- }
- }
- else{
- if(!force_delete){
- v3s16 p = floatToInt(objectpos, BS);
- errorstream<<"ServerEnv: Could not find or generate "
- <<"a block for storing id="<<obj->getId()
- <<" statically (pos="<<PP(p)<<")"<<std::endl;
- continue;
- }
- }
+ u16 store_id = pending_delete ? id : 0;
+ if (!saveStaticToBlock(blockpos, store_id, obj, s_obj, reason))
+ force_delete = true;
}
/*
If known by some client, set pending deactivation.
Otherwise delete it immediately.
*/
-
if(pending_delete && !force_delete)
{
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"object id="<<id<<" is known by clients"
- <<"; not deleting yet"<<std::endl;
+ verbosestream << "ServerEnvironment::deactivateFarObjects(): "
+ << "object id=" << id << " is known by clients"
+ << "; not deleting yet" << std::endl;
obj->m_pending_deactivation = true;
continue;
}
-
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"object id="<<id<<" is not known by clients"
- <<"; deleting"<<std::endl;
+ verbosestream << "ServerEnvironment::deactivateFarObjects(): "
+ << "object id=" << id << " is not known by clients"
+ << "; deleting" << std::endl;
// Tell the object about removal
obj->removingFromEnvironment();
}
}
+void ServerEnvironment::deleteStaticFromBlock(
+ ServerActiveObject *obj, u16 id, u32 mod_reason, bool no_emerge)
+{
+ if (!obj->m_static_exists)
+ return;
+
+ MapBlock *block;
+ if (no_emerge)
+ block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
+ else
+ block = m_map->emergeBlock(obj->m_static_block, false);
+ if (!block) {
+ if (!no_emerge)
+ errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
+ << " when deleting static data of object from it. id=" << id << std::endl;
+ return;
+ }
+
+ block->m_static_objects.remove(id);
+ if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
+ block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);
+
+ obj->m_static_exists = false;
+}
+
+bool ServerEnvironment::saveStaticToBlock(
+ v3s16 blockpos, u16 store_id,
+ ServerActiveObject *obj, const StaticObject &s_obj,
+ u32 mod_reason)
+{
+ MapBlock *block = nullptr;
+ try {
+ 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) {
+ errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
+ << " when saving static data of object to it. id=" << store_id << std::endl;
+ return false;
+ }
+ if (block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")) {
+ warningstream << "ServerEnv: Trying to store id = " << store_id
+ << " statically but block " << PP(blockpos)
+ << " already contains "
+ << block->m_static_objects.m_stored.size()
+ << " objects." << std::endl;
+ return false;
+ }
+
+ block->m_static_objects.insert(store_id, s_obj);
+ if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
+ block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);
+
+ obj->m_static_exists = true;
+ obj->m_static_block = blockpos;
+
+ return true;
+}
+
PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
const std::string &savedir, const Settings &conf)
{