From c6d54411056da2dd563015c9f90c4c5c0863bc71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Blot?= Date: Sat, 3 Jun 2017 19:57:02 +0200 Subject: [PATCH] Properly remove SAO when worldedges are overtaken (#5889) * LuaEntitySAO: Remove beyond outermost mapchunk edges Based on a commit by, and with help from, nerzhul. Add 2 functions to class Mapgen: A function to calculate actual mapgen edges, called from the Mapgen constructor. A function called indirectly from content_sao.cpp per entity step to check SAO position is within mapgen edges. * Calculate borders from params not mapgen, which is not available everytime --- src/content_sao.cpp | 14 ++++++++++++ src/map.cpp | 8 ++++--- src/map.h | 5 ++--- src/mapgen.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++- src/mapgen.h | 13 +++++++++++- 5 files changed, 84 insertions(+), 8 deletions(-) diff --git a/src/content_sao.cpp b/src/content_sao.cpp index f435fe938..be1c52fe6 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -406,6 +406,20 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) m_env->getScriptIface()->luaentity_Step(m_id, dtime); } + // Remove LuaEntity beyond terrain edges + { + ServerMap *map = dynamic_cast(&m_env->getMap()); + assert(map); + if (!m_pending_deactivation && + map->saoPositionOverLimit(m_base_position)) { + infostream << "Remove SAO " << m_id << "(" << m_init_name + << "), outside of limits" << std::endl; + m_pending_deactivation = true; + m_removed = true; + return; + } + } + if(send_recommended == false) return; diff --git a/src/map.cpp b/src/map.cpp index 641b7d2dd..3b02ac02f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1378,6 +1378,11 @@ s16 ServerMap::getWaterLevel() return getMapgenParams()->water_level; } +bool ServerMap::saoPositionOverLimit(const v3f &p) +{ + return getMapgenParams()->saoPosOverLimit(p); +} + bool ServerMap::blockpos_over_mapgen_limit(v3s16 p) { const s16 mapgen_limit_bp = rangelim( @@ -1838,9 +1843,6 @@ MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d) return block; } -void ServerMap::prepareBlock(MapBlock *block) { -} - // N.B. This requires no synchronization, since data will not be modified unless // the VoxelManipulator being updated belongs to the same thread. void ServerMap::updateVManip(v3s16 pos) diff --git a/src/map.h b/src/map.h index 41a1a246b..4b6e08f96 100644 --- a/src/map.h +++ b/src/map.h @@ -377,6 +377,8 @@ public: */ ServerMapSector *createSector(v2s16 p); + bool saoPositionOverLimit(const v3f &p); + /* Blocks are generated by using these and makeBlock(). */ @@ -409,9 +411,6 @@ public: */ MapBlock *getBlockOrEmerge(v3s16 p3d); - // Carries out any initialization necessary before block is sent - void prepareBlock(MapBlock *block); - // Helper for placing objects on ground level s16 findGroundLevel(v2s16 p2d); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index dfe413a71..1f7f98621 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -317,7 +317,6 @@ void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) heightmap[index] = y; } } - //printf("updateHeightmap: %dus\n", t.stop()); } inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em) @@ -1049,3 +1048,54 @@ void MapgenParams::writeParams(Settings *settings) const if (bparams) bparams->writeParams(settings); } + +// Calculate edges of outermost generated mapchunks (less than +// 'mapgen_limit'), and corresponding exact limits for SAO entities. +void MapgenParams::calcMapgenEdges() +{ + // Central chunk offset, in blocks + s16 ccoff_b = -chunksize / 2; + + // Chunksize, in nodes + s32 csize_n = chunksize * MAP_BLOCKSIZE; + + // Minp/maxp of central chunk, in nodes + s16 ccmin = ccoff_b * MAP_BLOCKSIZE; + s16 ccmax = ccmin + csize_n - 1; + // Fullminp/fullmaxp of central chunk, in nodes + s16 ccfmin = ccmin - MAP_BLOCKSIZE; + s16 ccfmax = ccmax + MAP_BLOCKSIZE; + // Effective mapgen limit, in blocks + // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p) + s16 mapgen_limit_b = rangelim(mapgen_limit, + 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE; + // Effective mapgen limits, in nodes + s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE; + s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1; + // Number of complete chunks from central chunk fullminp/fullmaxp + // to effective mapgen limits. + s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0); + s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0); + // Mapgen edges, in nodes + // These values may be useful later as additional class members + s16 mapgen_edge_min = ccmin - numcmin * csize_n; + s16 mapgen_edge_max = ccmax + numcmax * csize_n; + // SAO position limits, in Irrlicht units + m_sao_limit_min = mapgen_edge_min * BS - 3.0f; + m_sao_limit_max = mapgen_edge_max * BS + 3.0f; +} + + +bool MapgenParams::saoPosOverLimit(const v3f &p) +{ + if (!m_sao_limit_calculated) { + calcMapgenEdges(); + m_sao_limit_calculated = true; + } + return p.X < m_sao_limit_min || + p.X > m_sao_limit_max || + p.Y < m_sao_limit_min || + p.Y > m_sao_limit_max || + p.Z < m_sao_limit_min || + p.Z > m_sao_limit_max; +} diff --git a/src/mapgen.h b/src/mapgen.h index 1efd2bff7..222838011 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -138,7 +138,10 @@ struct MapgenParams { water_level(1), mapgen_limit(MAX_MAP_GENERATION_LIMIT), flags(MG_CAVES | MG_LIGHT | MG_DECORATIONS), - bparams(NULL) + bparams(NULL), + m_sao_limit_min(MAX_MAP_GENERATION_LIMIT * BS), + m_sao_limit_max(MAX_MAP_GENERATION_LIMIT * BS), + m_sao_limit_calculated(false) { } @@ -146,6 +149,14 @@ struct MapgenParams { virtual void readParams(const Settings *settings); virtual void writeParams(Settings *settings) const; + + bool saoPosOverLimit(const v3f &p); +private: + void calcMapgenEdges(); + + float m_sao_limit_min; + float m_sao_limit_max; + bool m_sao_limit_calculated; };