]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/map.cpp
Implement urlencode and urldecode
[dragonfireclient.git] / src / map.cpp
index 7a5296bacdf036dfe79c3c0fc6edda83ba0f1427..55f91c8a6117f8b982e40c9ba6aa4c36750c9883 100644 (file)
@@ -38,6 +38,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "emerge.h"
 #include "mapgen_v6.h"
 #include "biome.h"
+#include "config.h"
+#include "server.h"
 #include "database.h"
 #include "database-dummy.h"
 #include "database-sqlite3.h"
@@ -73,8 +75,6 @@ Map::Map(std::ostream &dout, IGameDef *gamedef):
        m_gamedef(gamedef),
        m_sector_cache(NULL)
 {
-       /*m_sector_mutex.Init();
-       assert(m_sector_mutex.IsInitialized());*/
 }
 
 Map::~Map()
@@ -929,7 +929,8 @@ void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
 /*
 */
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
-               std::map<v3s16, MapBlock*> &modified_blocks)
+               std::map<v3s16, MapBlock*> &modified_blocks,
+               bool remove_metadata)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
@@ -1016,8 +1017,9 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                Remove node metadata
        */
-
-       removeNodeMetadata(p);
+       if (remove_metadata) {
+               removeNodeMetadata(p);
+       }
 
        /*
                Set the node on the map
@@ -1317,17 +1319,17 @@ void Map::removeNodeAndUpdate(v3s16 p,
        }
 }
 
-bool Map::addNodeWithEvent(v3s16 p, MapNode n)
+bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
 {
        MapEditEvent event;
-       event.type = MEET_ADDNODE;
+       event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
        event.p = p;
        event.n = n;
 
        bool succeeded = true;
        try{
                std::map<v3s16, MapBlock*> modified_blocks;
-               addNodeAndUpdate(p, n, modified_blocks);
+               addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
 
                // Copy modified_blocks to event
                for(std::map<v3s16, MapBlock*>::iterator
@@ -1677,7 +1679,7 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
                v3s16 p0 = m_transforming_liquid.pop_front();
                u16 total_level = 0;
                // surrounding flowing liquid nodes
-               NodeNeighbor neighbors[7]; 
+               NodeNeighbor neighbors[7];
                // current level of every block
                s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1};
                 // target levels
@@ -1778,8 +1780,8 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
                        liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE &&
                        total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level-
                        (can_liquid_same_level - relax) &&
-                       can_liquid_same_level >= relax + 1) { 
-                       total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level; 
+                       can_liquid_same_level >= relax + 1) {
+                       total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level;
                }
 
                // prevent lakes in air above unloaded blocks
@@ -1788,9 +1790,9 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
                }
 
                // calculate self level 5 blocks
-               u8 want_level = 
+               u8 want_level =
                          total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level
-                       ? LIQUID_LEVEL_SOURCE 
+                       ? LIQUID_LEVEL_SOURCE
                        : total_level / can_liquid_same_level;
                total_level -= want_level * can_liquid_same_level;
 
@@ -1848,7 +1850,7 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
 
                /*
                if (total_level > 0) //|| flowed != volume)
-                       infostream <<" AFTER level=" << (int)total_level 
+                       infostream <<" AFTER level=" << (int)total_level
                        //<< " flowed="<<flowed<< " volume=" << volume
                        << " wantsame="<<(int)want_level<< " top="
                        << (int)liquid_levels_want[D_TOP]<< " topwas="
@@ -1858,7 +1860,7 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
 
                //u8 changed = 0;
                for (u16 i = 0; i < 7; i++) {
-                       if (liquid_levels_want[i] < 0 || !neighbors[i].l) 
+                       if (liquid_levels_want[i] < 0 || !neighbors[i].l)
                                continue;
                        MapNode & n0 = neighbors[i].n;
                        p0 = neighbors[i].p;
@@ -1905,7 +1907,7 @@ void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
                         */
                        /*
                        if (
-                                new_node_content == n0.getContent() 
+                                new_node_content == n0.getContent()
                                && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
                                 (n0.getLevel(nodemgr) == (u8)new_node_level
                                 //&& ((n0.param2 & LIQUID_FLOW_DOWN_MASK) ==
@@ -2134,6 +2136,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                content_t new_node_content;
                s8 new_node_level = -1;
                s8 max_node_level = -1;
+               u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1);
                if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
                        // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
                        // or the flowing alternative of the first of the surrounding sources (if it's air), so
@@ -2143,6 +2146,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                        // liquid_kind is set properly, see above
                        new_node_content = liquid_kind;
                        max_node_level = new_node_level = LIQUID_LEVEL_MAX;
+                       if (new_node_level < (LIQUID_LEVEL_MAX+1-range))
+                               new_node_content = CONTENT_AIR;
                } else {
                        // no surrounding sources, so get the maximum level that can flow into this node
                        for (u16 i = 0; i < num_flows; i++) {
@@ -2183,8 +2188,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                        } else
                                new_node_level = max_node_level;
 
-                       u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1);
-                       if (new_node_level >= (LIQUID_LEVEL_MAX+1-range))
+                       if (max_node_level >= (LIQUID_LEVEL_MAX+1-range))
                                new_node_content = liquid_kind;
                        else
                                new_node_content = CONTENT_AIR;
@@ -2275,7 +2279,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
        updateLighting(lighting_modified_blocks, modified_blocks);
 }
 
-NodeMetadataMap::getNodeMetadata(v3s16 p)
+NodeMetadata *Map::getNodeMetadata(v3s16 p)
 {
        v3s16 blockpos = getNodeBlockPos(p);
        v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
@@ -2285,8 +2289,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
                                <<std::endl;
                return NULL;
@@ -2295,7 +2298,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p)
        return meta;
 }
 
-void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
+bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
 {
        v3s16 blockpos = getNodeBlockPos(p);
        v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
@@ -2305,13 +2308,13 @@ void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
                                <<std::endl;
-               return;
+               return false;
        }
        block->m_node_metadata.set(p_rel, meta);
+       return true;
 }
 
 void Map::removeNodeMetadata(v3s16 p)
@@ -2338,8 +2341,7 @@ NodeTimer Map::getNodeTimer(v3s16 p)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::getNodeTimer(): Block not found"
                                <<std::endl;
                return NodeTimer();
@@ -2358,8 +2360,7 @@ void Map::setNodeTimer(v3s16 p, NodeTimer t)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::setNodeTimer(): Block not found"
                                <<std::endl;
                return;
@@ -2823,6 +2824,31 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
        /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
                        <<","<<blockpos_requested.Y<<","
                        <<blockpos_requested.Z<<")"<<std::endl;*/
+                       
+       /*
+               Update weather data in blocks
+       */
+       ServerEnvironment *senv = &((Server *)m_gamedef)->getEnv();
+       for(s16 x=blockpos_min.X-extra_borders.X;
+               x<=blockpos_max.X+extra_borders.X; x++)
+       for(s16 z=blockpos_min.Z-extra_borders.Z;
+               z<=blockpos_max.Z+extra_borders.Z; z++)
+       for(s16 y=blockpos_min.Y-extra_borders.Y;
+               y<=blockpos_max.Y+extra_borders.Y; y++)
+       {
+               v3s16 p(x, y, z);
+               MapBlock *block = getBlockNoCreateNoEx(p);
+               block->heat_last_update     = 0;
+               block->humidity_last_update = 0;
+               if (senv->m_use_weather) {
+                       updateBlockHeat(senv, p * MAP_BLOCKSIZE, block);
+                       updateBlockHumidity(senv, p * MAP_BLOCKSIZE, block);
+               } else {
+                       block->heat     = HEAT_UNDEFINED;
+                       block->humidity = HUMIDITY_UNDEFINED;
+               }
+       }
+       
 #if 0
        if(enable_mapgen_debug_info)
        {
@@ -3143,48 +3169,72 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
        return NULL;
 }
 
-s16 ServerMap::findGroundLevel(v2s16 p2d)
+void ServerMap::prepareBlock(MapBlock *block) {
+       ServerEnvironment *senv = &((Server *)m_gamedef)->getEnv();
+
+       // Calculate weather conditions
+       block->heat_last_update     = 0;
+       block->humidity_last_update = 0;
+       if (senv->m_use_weather) {
+               v3s16 p = block->getPos() *  MAP_BLOCKSIZE;
+               updateBlockHeat(senv, p, block);
+               updateBlockHumidity(senv, p, block);
+       } else {
+               block->heat     = HEAT_UNDEFINED;
+               block->humidity = HUMIDITY_UNDEFINED;
+       }
+}
+
+/**
+ * Get the ground level by searching for a non CONTENT_AIR node in a column from top to bottom
+ */
+s16 ServerMap::findGroundLevel(v2s16 p2d, bool cacheBlocks)
 {
-#if 0
-       /*
-               Uh, just do something random...
-       */
-       // Find existing map from top to down
-       s16 max=63;
-       s16 min=-64;
-       v3s16 p(p2d.X, max, p2d.Y);
-       for(; p.Y>min; p.Y--)
-       {
-               MapNode n = getNodeNoEx(p);
-               if(n.getContent() != CONTENT_IGNORE)
-                       break;
+       
+       s16 level;
+
+       // The reference height is the original mapgen height
+       s16 referenceHeight = m_emerge->getGroundLevelAtPoint(p2d);
+       s16 maxSearchHeight =  63 + referenceHeight;
+       s16 minSearchHeight = -63 + referenceHeight;
+       v3s16 probePosition(p2d.X, maxSearchHeight, p2d.Y);
+       v3s16 blockPosition = getNodeBlockPos(probePosition);
+       v3s16 prevBlockPosition = blockPosition;
+
+       // Cache the block to be inspected.
+       if(cacheBlocks) {
+               emergeBlock(blockPosition, true);
        }
-       if(p.Y == min)
-               goto plan_b;
-       // If this node is not air, go to plan b
-       if(getNodeNoEx(p).getContent() != CONTENT_AIR)
-               goto plan_b;
-       // Search existing walkable and return it
-       for(; p.Y>min; p.Y--)
+
+       // Probes the nodes in the given column
+       for(; probePosition.Y > minSearchHeight; probePosition.Y--)
        {
-               MapNode n = getNodeNoEx(p);
-               if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
-                       return p.Y;
-       }
+               if(cacheBlocks) {
+                       // Calculate the block position of the given node
+                       blockPosition = getNodeBlockPos(probePosition); 
+
+                       // If the node is in an different block, cache it
+                       if(blockPosition != prevBlockPosition) {
+                               emergeBlock(blockPosition, true);
+                               prevBlockPosition = blockPosition;
+                       }
+               }
 
-       // Move to plan b
-plan_b:
-#endif
+               MapNode node = getNodeNoEx(probePosition);
+               if (node.getContent() != CONTENT_IGNORE &&
+                   node.getContent() != CONTENT_AIR) {
+                       break;
+               }
+       }
 
-       /*
-               Determine from map generator noise functions
-       */
+       // Could not determine the ground. Use map generator noise functions.
+       if(probePosition.Y == minSearchHeight) {
+               level = referenceHeight; 
+       } else {
+               level = probePosition.Y;
+       }
 
-       s16 level = m_emerge->getGroundLevelAtPoint(p2d);
        return level;
-
-       //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
-       //return (s16)level;
 }
 
 bool ServerMap::loadFromFolders() {
@@ -3371,10 +3421,7 @@ void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
                errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
                                <<"all blocks that are stored in flat files"<<std::endl;
        }
-       core::list<v3s16> dst_;
-       dbase->listAllLoadableBlocks(dst_);
-       for(core::list<v3s16>::Iterator i = dst_.begin(); i != dst_.end(); ++i)
-               dst.push_back(*i);
+       dbase->listAllLoadableBlocks(dst);
 }
 
 void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
@@ -3474,7 +3521,7 @@ void ServerMap::loadMapMeta()
                m_seed = mgparams->seed;
        } else {
                if (params.exists("seed")) {
-                       m_seed = params.getU64("seed");
+                       m_seed = read_seed(params.get("seed").c_str());
                        m_mgparams->seed = m_seed;
                }
        }
@@ -3890,73 +3937,44 @@ void ServerMap::PrintInfo(std::ostream &out)
        out<<"ServerMap: ";
 }
 
-s16 ServerMap::getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block)
+s16 ServerMap::updateBlockHeat(ServerEnvironment *env, v3s16 p, MapBlock *block)
 {
-       if(block == NULL)
-               block = getBlockNoCreateNoEx(getNodeBlockPos(p));
-       if(block != NULL) {
-               if (env->getGameTime() - block->heat_time < 10)
+       u32 gametime = env->getGameTime();
+       
+       if (block) {
+               if (gametime - block->heat_last_update < 10)
                        return block->heat;
+       } else {
+               block = getBlockNoCreateNoEx(getNodeBlockPos(p));
        }
 
-       //variant 1: full random
-       //f32 heat = NoisePerlin3D(m_emerge->biomedef->np_heat, p.X, env->getGameTime()/100, p.Z, m_emerge->params->seed);
-
-       //variant 2: season change based on default heat map
-       const f32 offset = 20; // = m_emerge->biomedef->np_heat->offset
-       const f32 scale  = 20; // = m_emerge->biomedef->np_heat->scale
-       const f32 range  = 20;
-       f32 heat = NoisePerlin2D(m_emerge->biomedef->np_heat, p.X, p.Z,
-                                       m_emerge->params->seed); // 0..50..100
-
-       heat -= m_emerge->biomedef->np_heat->offset; // -50..0..+50
-
-       // normalizing - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50,
-       if(m_emerge->biomedef->np_heat->scale)
-               heat /= m_emerge->biomedef->np_heat->scale / scale; //  -20..0..+20
+       f32 heat = m_emerge->biomedef->calcBlockHeat(p, m_seed,
+                       env->getTimeOfDayF(), gametime * env->getTimeOfDaySpeed());
 
-       f32 seasonv = (f32)env->getGameTime() * env->getTimeOfDaySpeed();
-       seasonv /= 86400 * g_settings->getS16("year_days"); // season change speed
-       seasonv += (f32)p.X / 3000; // you can walk to area with other season
-       seasonv = sin(seasonv * M_PI);
-       heat += (range * (heat < 0 ? 2 : 0.5)) * seasonv; // -60..0..30
-
-       heat += offset; // -40..0..50
-       heat += p.Y / -333; // upper=colder, lower=hotter, 3c per 1000
-
-       // daily change, hotter at sun +4, colder at night -4
-       heat += 8 * (sin(cycle_shift(env->getTimeOfDayF(), -0.25) * M_PI) - 0.5); //-44..20..54
-
-       if(block != NULL) {
+       if(block) {
                block->heat = heat;
-               block->heat_time = env->getGameTime();
+               block->heat_last_update = gametime;
        }
        return heat;
 }
 
-s16 ServerMap::getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block)
+s16 ServerMap::updateBlockHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block)
 {
-       if(block == NULL)
-               block = getBlockNoCreateNoEx(getNodeBlockPos(p));
-       if(block != NULL) {
-               if (env->getGameTime() - block->humidity_time < 10)
+       u32 gametime = env->getGameTime();
+       
+       if (block) {
+               if (gametime - block->humidity_last_update < 10)
                        return block->humidity;
+       } else {
+               block = getBlockNoCreateNoEx(getNodeBlockPos(p));
        }
 
-       f32 humidity = NoisePerlin2D(m_emerge->biomedef->np_humidity, p.X, p.Z, 
-                                               m_emerge->params->seed);
-
-       f32 seasonv = (f32)env->getGameTime() * env->getTimeOfDaySpeed();
-       seasonv /= 86400 * 2; // bad weather change speed (2 days)
-       seasonv += (f32)p.Z / 300;
-       humidity += 30 * sin(seasonv * M_PI);
-
-       humidity += -12 * ( sin(cycle_shift(env->getTimeOfDayF(), -0.1) * M_PI) - 0.5);
-       humidity = rangelim(humidity, 0, 100);
-
-       if(block != NULL) {
+       f32 humidity = m_emerge->biomedef->calcBlockHumidity(p, m_seed,
+                       env->getTimeOfDayF(), gametime * env->getTimeOfDaySpeed());
+                       
+       if(block) {
                block->humidity = humidity;
-               block->humidity_time = env->getGameTime();
+               block->humidity_last_update = gametime;
        }
        return humidity;
 }