Record MapBlock modification reasons as flags instead of strings

This improves performance of MapBlock::raiseModified by a factor of 6.
Also, clean up mapblock.h a bit and inline small functions.
This commit is contained in:
kwolekr 2015-05-17 22:14:26 -04:00
parent 4c9a8a91c4
commit 46684beec1
6 changed files with 294 additions and 241 deletions

@ -873,7 +873,7 @@ void ServerEnvironment::clearAllObjects()
if(block){
block->m_static_objects.remove(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"clearAllObjects");
MOD_REASON_CLEAR_ALL_OBJECTS);
obj->m_static_exists = false;
}
}
@ -952,7 +952,7 @@ void ServerEnvironment::clearAllObjects()
block->m_static_objects.m_stored.clear();
block->m_static_objects.m_active.clear();
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"clearAllObjects");
MOD_REASON_CLEAR_ALL_OBJECTS);
num_objs_cleared += num_stored + num_active;
num_blocks_cleared++;
}
@ -1139,7 +1139,7 @@ void ServerEnvironment::step(float dtime)
// set block to be saved when it is unloaded
if(block->getTimestamp() > block->getDiskTimestamp() + 60)
block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
"Timestamp older than 60s (step)");
MOD_REASON_BLOCK_EXPIRED);
// Run node timers
std::map<v3s16, NodeTimer> elapsed_timers =
@ -1530,7 +1530,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
if(set_changed)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"addActiveObjectRaw");
MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
} else {
v3s16 p = floatToInt(objectpos, BS);
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
@ -1579,7 +1579,7 @@ void ServerEnvironment::removeRemovedObjects()
if (block) {
block->m_static_objects.remove(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"removeRemovedObjects/remove");
MOD_REASON_REMOVE_OBJECTS_REMOVE);
obj->m_static_exists = false;
} else {
infostream<<"Failed to emerge block from which an object to "
@ -1604,7 +1604,7 @@ void ServerEnvironment::removeRemovedObjects()
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");
MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
}
} else {
infostream<<"Failed to emerge block from which an object to "
@ -1690,8 +1690,7 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
// Clear stored list
block->m_static_objects.m_stored.clear();
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"stored list cleared in activateObjects due to "
"large amount of objects");
MOD_REASON_TOO_MANY_OBJECTS);
return;
}
@ -1812,7 +1811,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
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");
MOD_REASON_STATIC_DATA_ADDED);
// Delete from block where object was located
block = m_map->emergeBlock(old_static_block, false);
@ -1825,7 +1824,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
}
block->m_static_objects.remove(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"deactivateFarObjects: Static data moved out");
MOD_REASON_STATIC_DATA_REMOVED);
continue;
}
@ -1890,8 +1889,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
// Only mark block as modified if data changed considerably
if(shall_be_written)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"deactivateFarObjects: Static data "
"changed considerably");
MOD_REASON_STATIC_DATA_CHANGED);
}
}
@ -1937,8 +1935,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
// Only mark block as modified if data changed considerably
if(shall_be_written)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"deactivateFarObjects: Static data "
"changed considerably");
MOD_REASON_STATIC_DATA_CHANGED);
obj->m_static_exists = true;
obj->m_static_block = block->getPos();

@ -1436,7 +1436,7 @@ void Map::timerUpdate(float dtime, float unload_timeout,
// Save if modified
if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
modprofiler.add(block->getModifiedReason(), 1);
modprofiler.add(block->getModifiedReasonString(), 1);
if (!saveBlock(block))
continue;
saved_blocks_count++;
@ -2412,7 +2412,7 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
Set block as modified
*/
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"finishBlockMake expireDayNightDiff");
MOD_REASON_EXPIRE_DAYNIGHTDIFF);
}
/*
@ -2981,7 +2981,7 @@ void ServerMap::save(ModifiedState save_level)
save_started = true;
}
modprofiler.add(block->getModifiedReason(), 1);
modprofiler.add(block->getModifiedReasonString(), 1);
saveBlock(block);
block_count++;

@ -38,6 +38,30 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
static const char *modified_reason_strings[] = {
"initial",
"reallocate",
"setIsUnderground",
"setLightingExpired",
"setGenerated",
"setNode",
"setNodeNoCheck",
"setTimestamp",
"NodeMetaRef::reportMetadataChange",
"clearAllObjects",
"Timestamp expired (step)",
"addActiveObjectRaw",
"removeRemovedObjects/remove",
"removeRemovedObjects/deactivate",
"Stored list cleared in activateObjects due to overflow",
"deactivateFarObjects: Static data moved in",
"deactivateFarObjects: Static data moved out",
"deactivateFarObjects: Static data changed considerably",
"finishBlockMake: expireDayNightDiff"
"unknown",
};
/*
MapBlock
*/
@ -47,8 +71,7 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
m_pos(pos),
m_gamedef(gamedef),
m_modified(MOD_STATE_WRITE_NEEDED),
m_modified_reason("initial"),
m_modified_reason_too_long(false),
m_modified_reason(MOD_REASON_INITIAL),
is_underground(false),
m_lighting_expired(true),
m_day_night_differs(false),
@ -112,6 +135,27 @@ MapNode MapBlock::getNodeParent(v3s16 p, bool *is_valid_position)
return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
}
std::string MapBlock::getModifiedReasonString()
{
std::string reason;
const u32 ubound = MYMIN(sizeof(m_modified_reason) * CHAR_BIT,
ARRLEN(modified_reason_strings));
for (u32 i = 0; i != ubound; i++) {
if ((m_modified_reason & (1 << i)) == 0)
continue;
reason += modified_reason_strings[i];
reason += ", ";
}
if (reason.length() > 2)
reason.resize(reason.length() - 2);
return reason;
}
/*
Propagates sunlight down through the block.
Doesn't modify nodes that are not affected by sunlight.

@ -97,21 +97,46 @@ public:
};
#endif
/*
MapBlock itself
*/
////
//// MapBlock modified reason flags
////
#define MOD_REASON_INITIAL (1 << 0)
#define MOD_REASON_REALLOCATE (1 << 1)
#define MOD_REASON_SET_IS_UNDERGROUND (1 << 2)
#define MOD_REASON_SET_LIGHTING_EXPIRED (1 << 3)
#define MOD_REASON_SET_GENERATED (1 << 4)
#define MOD_REASON_SET_NODE (1 << 5)
#define MOD_REASON_SET_NODE_NO_CHECK (1 << 6)
#define MOD_REASON_SET_TIMESTAMP (1 << 7)
#define MOD_REASON_REPORT_META_CHANGE (1 << 8)
#define MOD_REASON_CLEAR_ALL_OBJECTS (1 << 9)
#define MOD_REASON_BLOCK_EXPIRED (1 << 10)
#define MOD_REASON_ADD_ACTIVE_OBJECT_RAW (1 << 11)
#define MOD_REASON_REMOVE_OBJECTS_REMOVE (1 << 12)
#define MOD_REASON_REMOVE_OBJECTS_DEACTIVATE (1 << 13)
#define MOD_REASON_TOO_MANY_OBJECTS (1 << 14)
#define MOD_REASON_STATIC_DATA_ADDED (1 << 15)
#define MOD_REASON_STATIC_DATA_REMOVED (1 << 16)
#define MOD_REASON_STATIC_DATA_CHANGED (1 << 17)
#define MOD_REASON_EXPIRE_DAYNIGHTDIFF (1 << 18)
#define MOD_REASON_UNKNOWN (1 << 19)
////
//// MapBlock itself
////
class MapBlock /*: public NodeContainer*/
{
public:
MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy=false);
~MapBlock();
/*virtual u16 nodeContainerId() const
{
return NODECONTAINER_ID_MAPBLOCK;
}*/
Map * getParent()
{
return m_parent;
@ -119,150 +144,125 @@ public:
void reallocate()
{
if(data != NULL)
delete[] data;
u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
data = new MapNode[l];
for(u32 i=0; i<l; i++){
//data[i] = MapNode();
delete[] data;
u32 datasize = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
data = new MapNode[datasize];
for (u32 i = 0; i < datasize; i++)
data[i] = MapNode(CONTENT_IGNORE);
}
raiseModified(MOD_STATE_WRITE_NEEDED, "reallocate");
raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
}
/*
Flags
*/
////
//// Modification tracking methods
////
void raiseModified(u32 mod, u32 reason=MOD_REASON_UNKNOWN)
{
if (mod > m_modified) {
m_modified = mod;
m_modified_reason = reason;
if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD)
m_disk_timestamp = m_timestamp;
} else if (mod == m_modified) {
m_modified_reason |= reason;
}
}
bool isDummy()
inline u32 getModified()
{
return m_modified;
}
inline u32 getModifiedReason()
{
return m_modified_reason;
}
std::string getModifiedReasonString();
inline void resetModified()
{
m_modified = MOD_STATE_CLEAN;
m_modified_reason = 0;
}
////
//// Flags
////
inline bool isDummy()
{
return (data == NULL);
}
void unDummify()
inline void unDummify()
{
assert(isDummy()); // Pre-condition
reallocate();
}
// m_modified methods
void raiseModified(u32 mod, const std::string &reason="unknown")
{
if(mod > m_modified){
m_modified = mod;
m_modified_reason = reason;
m_modified_reason_too_long = false;
if(m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
m_disk_timestamp = m_timestamp;
}
} else if(mod == m_modified){
if(!m_modified_reason_too_long){
if(m_modified_reason.size() < 40)
m_modified_reason += ", " + reason;
else{
m_modified_reason += "...";
m_modified_reason_too_long = true;
}
}
}
}
void raiseModified(u32 mod, const char *reason)
{
if (mod > m_modified){
m_modified = mod;
m_modified_reason = reason;
m_modified_reason_too_long = false;
if (m_modified >= MOD_STATE_WRITE_AT_UNLOAD){
m_disk_timestamp = m_timestamp;
}
}
else if (mod == m_modified){
if (!m_modified_reason_too_long){
if (m_modified_reason.size() < 40)
m_modified_reason += ", " + std::string(reason);
else{
m_modified_reason += "...";
m_modified_reason_too_long = true;
}
}
}
}
u32 getModified()
{
return m_modified;
}
std::string getModifiedReason()
{
return m_modified_reason;
}
void resetModified()
{
m_modified = MOD_STATE_CLEAN;
m_modified_reason = "none";
m_modified_reason_too_long = false;
}
// is_underground getter/setter
bool getIsUnderground()
inline bool getIsUnderground()
{
return is_underground;
}
void setIsUnderground(bool a_is_underground)
inline void setIsUnderground(bool a_is_underground)
{
is_underground = a_is_underground;
raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
}
void setLightingExpired(bool expired)
inline void setLightingExpired(bool expired)
{
if(expired != m_lighting_expired){
if (expired != m_lighting_expired){
m_lighting_expired = expired;
raiseModified(MOD_STATE_WRITE_NEEDED, "setLightingExpired");
raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_EXPIRED);
}
}
bool getLightingExpired()
inline bool getLightingExpired()
{
return m_lighting_expired;
}
bool isGenerated()
inline bool isGenerated()
{
return m_generated;
}
void setGenerated(bool b)
inline void setGenerated(bool b)
{
if(b != m_generated){
raiseModified(MOD_STATE_WRITE_NEEDED, "setGenerated");
if (b != m_generated) {
raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_GENERATED);
m_generated = b;
}
}
bool isValid()
inline bool isValid()
{
if(m_lighting_expired)
if (m_lighting_expired)
return false;
if(data == NULL)
if (data == NULL)
return false;
return true;
}
/*
Position stuff
*/
////
//// Position stuff
////
v3s16 getPos()
inline v3s16 getPos()
{
return m_pos;
}
v3s16 getPosRelative()
inline v3s16 getPosRelative()
{
return m_pos * MAP_BLOCKSIZE;
}
core::aabbox3d<s16> getBox()
inline core::aabbox3d<s16> getBox()
{
return core::aabbox3d<s16>(getPosRelative(),
getPosRelative()
@ -270,140 +270,135 @@ public:
- v3s16(1,1,1));
}
/*
Regular MapNode get-setters
*/
bool isValidPosition(s16 x, s16 y, s16 z)
////
//// Regular MapNode get-setters
////
inline bool isValidPosition(s16 x, s16 y, s16 z)
{
return data != NULL
&& x >= 0 && x < MAP_BLOCKSIZE
&& y >= 0 && y < MAP_BLOCKSIZE
&& z >= 0 && z < MAP_BLOCKSIZE;
&& x >= 0 && x < MAP_BLOCKSIZE
&& y >= 0 && y < MAP_BLOCKSIZE
&& z >= 0 && z < MAP_BLOCKSIZE;
}
bool isValidPosition(v3s16 p)
inline bool isValidPosition(v3s16 p)
{
return isValidPosition(p.X, p.Y, p.Z);
}
MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
inline MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
{
*valid_position = isValidPosition(x, y, z);
if (!*valid_position)
return MapNode(CONTENT_IGNORE);
return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
return data[z * MAP_BLOCKSIZE * MAP_BLOCKSIZE + y * MAP_BLOCKSIZE + x];
}
MapNode getNode(v3s16 p, bool *valid_position)
inline MapNode getNode(v3s16 p, bool *valid_position)
{
return getNode(p.X, p.Y, p.Z, valid_position);
}
MapNode getNodeNoEx(v3s16 p)
inline MapNode getNodeNoEx(v3s16 p)
{
bool is_valid;
MapNode node = getNode(p.X, p.Y, p.Z, &is_valid);
return is_valid ? node : MapNode(CONTENT_IGNORE);
}
void setNode(s16 x, s16 y, s16 z, MapNode & n)
inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
{
if(data == NULL)
if (!isValidPosition(x, y, z))
throw InvalidPositionException();
if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
raiseModified(MOD_STATE_WRITE_NEEDED, "setNode");
data[z * zstride + y * ystride + x] = n;
raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE);
}
void setNode(v3s16 p, MapNode & n)
inline void setNode(v3s16 p, MapNode & n)
{
setNode(p.X, p.Y, p.Z, n);
}
/*
Non-checking variants of the above
*/
////
//// Non-checking variants of the above
////
MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
inline MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
{
*valid_position = data != NULL;
if(!valid_position)
if (!valid_position)
return MapNode(CONTENT_IGNORE);
return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
return data[z * zstride + y * ystride + x];
}
MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
inline MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
{
return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
}
void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
{
if(data == NULL)
if (data == NULL)
throw InvalidPositionException();
data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
raiseModified(MOD_STATE_WRITE_NEEDED, "setNodeNoCheck");
data[z * zstride + y * ystride + x] = n;
raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_NODE_NO_CHECK);
}
void setNodeNoCheck(v3s16 p, MapNode & n)
inline void setNodeNoCheck(v3s16 p, MapNode & n)
{
setNodeNoCheck(p.X, p.Y, p.Z, n);
}
/*
These functions consult the parent container if the position
is not valid on this MapBlock.
*/
// These functions consult the parent container if the position
// is not valid on this MapBlock.
bool isValidPositionParent(v3s16 p);
MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
void setNodeParent(v3s16 p, MapNode & n);
void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
inline void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
{
for(u16 z=0; z<d; z++)
for(u16 y=0; y<h; y++)
for(u16 x=0; x<w; x++)
setNode(x0+x, y0+y, z0+z, node);
for (u16 z = 0; z < d; z++)
for (u16 y = 0; y < h; y++)
for (u16 x = 0; x < w; x++)
setNode(x0 + x, y0 + y, z0 + z, node);
}
// See comments in mapblock.cpp
bool propagateSunlight(std::set<v3s16> & light_sources,
bool remove_light=false, bool *black_air_left=NULL);
bool propagateSunlight(std::set<v3s16> &light_sources,
bool remove_light=false, bool *black_air_left=NULL);
// Copies data to VoxelManipulator to getPosRelative()
void copyTo(VoxelManipulator &dst);
// Copies data from VoxelManipulator getPosRelative()
void copyFrom(VoxelManipulator &dst);
/*
Update day-night lighting difference flag.
Sets m_day_night_differs to appropriate value.
These methods don't care about neighboring blocks.
*/
// Update day-night lighting difference flag.
// Sets m_day_night_differs to appropriate value.
// These methods don't care about neighboring blocks.
void actuallyUpdateDayNightDiff();
/*
Call this to schedule what the previous function does to be done
when the value is actually needed.
*/
// Call this to schedule what the previous function does to be done
// when the value is actually needed.
void expireDayNightDiff();
bool getDayNightDiff()
inline bool getDayNightDiff()
{
if(m_day_night_differs_expired)
if (m_day_night_differs_expired)
actuallyUpdateDayNightDiff();
return m_day_night_differs;
}
/*
Miscellaneous stuff
*/
////
//// Miscellaneous stuff
////
/*
Tries to measure ground level.
Return value:
@ -414,84 +409,99 @@ public:
*/
s16 getGroundLevel(v2s16 p2d);
/*
Timestamp (see m_timestamp)
NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
*/
void setTimestamp(u32 time)
////
//// Timestamp (see m_timestamp)
////
// NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
inline void setTimestamp(u32 time)
{
m_timestamp = time;
raiseModified(MOD_STATE_WRITE_AT_UNLOAD, "setTimestamp");
raiseModified(MOD_STATE_WRITE_AT_UNLOAD, MOD_REASON_SET_TIMESTAMP);
}
void setTimestampNoChangedFlag(u32 time)
inline void setTimestampNoChangedFlag(u32 time)
{
m_timestamp = time;
}
u32 getTimestamp()
inline u32 getTimestamp()
{
return m_timestamp;
}
u32 getDiskTimestamp()
inline u32 getDiskTimestamp()
{
return m_disk_timestamp;
}
/*
See m_usage_timer
*/
void resetUsageTimer()
////
//// Usage timer (see m_usage_timer)
////
inline void resetUsageTimer()
{
m_usage_timer = 0;
}
void incrementUsageTimer(float dtime)
inline void incrementUsageTimer(float dtime)
{
m_usage_timer += dtime;
}
float getUsageTimer()
inline float getUsageTimer()
{
return m_usage_timer;
}
/*
See m_refcount
*/
void refGrab()
////
//// Reference counting (see m_refcount)
////
inline void refGrab()
{
m_refcount++;
}
void refDrop()
inline void refDrop()
{
m_refcount--;
}
int refGet()
inline int refGet()
{
return m_refcount;
}
/*
Node Timers
*/
// Get timer
NodeTimer getNodeTimer(v3s16 p){
////
//// Node Timers
////
inline NodeTimer getNodeTimer(v3s16 p)
{
return m_node_timers.get(p);
}
// Deletes timer
void removeNodeTimer(v3s16 p){
inline void removeNodeTimer(v3s16 p)
{
m_node_timers.remove(p);
}
// Deletes old timer and sets a new one
void setNodeTimer(v3s16 p, NodeTimer t){
inline void setNodeTimer(v3s16 p, NodeTimer t)
{
m_node_timers.set(p,t);
}
// Deletes all timers
void clearNodeTimers(){
inline void clearNodeTimers()
{
m_node_timers.clear();
}
/*
Serialization
*/
////
//// Serialization
///
// These don't write or read version by itself
// Set disk to true for on-disk format, false for over-the-network format
// Precondition: version >= SER_FMT_CLIENT_VER_LOWEST
@ -514,16 +524,15 @@ private:
Used only internally, because changes can't be tracked
*/
MapNode & getNodeRef(s16 x, s16 y, s16 z)
inline MapNode &getNodeRef(s16 x, s16 y, s16 z)
{
if(data == NULL)
if (!isValidPosition(x, y, z))
throw InvalidPositionException();
if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
return data[z * zstride + y * ystride + x];
}
MapNode & getNodeRef(v3s16 &p)
inline MapNode &getNodeRef(v3s16 &p)
{
return getNodeRef(p.X, p.Y, p.Z);
}
@ -536,11 +545,14 @@ public:
#ifndef SERVER // Only on client
MapBlockMesh *mesh;
#endif
NodeMetadataList m_node_metadata;
NodeTimerList m_node_timers;
StaticObjectList m_static_objects;
static const u32 ystride = MAP_BLOCKSIZE;
static const u32 zstride = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
private:
/*
Private member variables
@ -552,12 +564,12 @@ private:
v3s16 m_pos;
IGameDef *m_gamedef;
/*
If NULL, block is a dummy block.
Dummy blocks are used for caching not-found-on-disk blocks.
*/
MapNode * data;
MapNode *data;
/*
- On the server, this is used for telling whether the
@ -565,8 +577,7 @@ private:
- On the client, this is used for nothing.
*/
u32 m_modified;
std::string m_modified_reason;
bool m_modified_reason_too_long;
u32 m_modified_reason;
/*
When propagating sunlight and the above block doesn't exist,
@ -586,13 +597,13 @@ private:
If this is true, lighting might be wrong or right.
*/
bool m_lighting_expired;
// Whether day and night lighting differs
bool m_day_night_differs;
bool m_day_night_differs_expired;
bool m_generated;
/*
When block is removed from active blocks, this is set to gametime.
Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.

@ -178,7 +178,7 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam
MapBlock *block = map->getBlockNoCreateNoEx(blockpos);
if (block) {
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"NodeMetaRef::reportMetadataChange");
MOD_REASON_REPORT_META_CHANGE);
}
} catch (InvalidPositionException &e) {
infostream << "RollbackAction::applyRevert(): "

@ -63,9 +63,10 @@ void NodeMetaRef::reportMetadataChange(NodeMetaRef *ref)
ref->m_env->getMap().dispatchEvent(&event);
// Set the block to be saved
MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos);
if(block)
if (block) {
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"NodeMetaRef::reportMetadataChange");
MOD_REASON_REPORT_META_CHANGE);
}
}
// Exported functions