]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/mapblock.h
Increase performance of getLight() by at least 2x
[dragonfireclient.git] / src / mapblock.h
index 5b27d01c3327397c4f6bf52517dec94f926eb50f..fa56f331865385e4e276caba9e98982085059e74 100644 (file)
@@ -1,18 +1,18 @@
 /*
-Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GNU Lesser General Public License for more details.
 
-You should have received a copy of the GNU General Public License along
+You should have received a copy of the GNU Lesser General Public License along
 with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
@@ -20,26 +20,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef MAPBLOCK_HEADER
 #define MAPBLOCK_HEADER
 
-#include <jmutex.h>
-#include <jmutexautolock.h>
-#include <exception>
+#include <set>
 #include "debug.h"
-#include "common_irrlicht.h"
+#include "irr_v3d.h"
 #include "mapnode.h"
 #include "exceptions.h"
-#include "serialization.h"
 #include "constants.h"
-#include "voxel.h"
 #include "staticobject.h"
-#include "mapblock_nodemod.h"
-#ifndef SERVER
-       #include "mapblock_mesh.h"
-#endif
+#include "nodemetadata.h"
+#include "nodetimer.h"
+#include "modifiedstate.h"
+#include "util/numeric.h" // getContainerPos
 
 class Map;
 class NodeMetadataList;
 class IGameDef;
-class IWritableNodeDefManager;
+class MapBlockMesh;
+class VoxelManipulator;
 
 #define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
 
@@ -53,19 +50,6 @@ enum{
        FACE_LEFT
 };*/
 
-enum ModifiedState
-{
-       // Has not been modified.
-       MOD_STATE_CLEAN = 0,
-       MOD_RESERVED1 = 1,
-       // Has been modified, and will be saved when being unloaded.
-       MOD_STATE_WRITE_AT_UNLOAD = 2,
-       MOD_RESERVED3 = 3,
-       // Has been modified, and will be saved as soon as possible.
-       MOD_STATE_WRITE_NEEDED = 4,
-       MOD_RESERVED5 = 5,
-};
-
 // NOTE: If this is enabled, set MapBlock to be initialized with
 //       CONTENT_IGNORE.
 /*enum BlockGenerationStatus
@@ -167,6 +151,10 @@ class MapBlock /*: public NodeContainer*/
                        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)
@@ -204,18 +192,6 @@ class MapBlock /*: public NodeContainer*/
                raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
        }
 
-#ifndef SERVER
-       void setMeshExpired(bool expired)
-       {
-               m_mesh_expired = expired;
-       }
-       
-       bool getMeshExpired()
-       {
-               return m_mesh_expired;
-       }
-#endif
-
        void setLightingExpired(bool expired)
        {
                if(expired != m_lighting_expired){
@@ -275,37 +251,39 @@ class MapBlock /*: public NodeContainer*/
                Regular MapNode get-setters
        */
        
+       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;
+       }
+
        bool isValidPosition(v3s16 p)
        {
-               if(data == NULL)
-                       return false;
-               return (p.X >= 0 && p.X < MAP_BLOCKSIZE
-                               && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
-                               && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
+               return isValidPosition(p.X, p.Y, p.Z);
        }
 
-       MapNode getNode(s16 x, s16 y, s16 z)
+       MapNode getNode(s16 x, s16 y, s16 z, bool *valid_position)
        {
-               if(data == NULL)
-                       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();
+               *valid_position = isValidPosition(x, y, z);
+
+               if (!*valid_position)
+                       return MapNode(CONTENT_IGNORE);
+
                return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
        }
        
-       MapNode getNode(v3s16 p)
+       MapNode getNode(v3s16 p, bool *valid_position)
        {
-               return getNode(p.X, p.Y, p.Z);
+               return getNode(p.X, p.Y, p.Z, valid_position);
        }
        
        MapNode getNodeNoEx(v3s16 p)
        {
-               try{
-                       return getNode(p.X, p.Y, p.Z);
-               }catch(InvalidPositionException &e){
-                       return MapNode(CONTENT_IGNORE);
-               }
+               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)
@@ -328,16 +306,18 @@ class MapBlock /*: public NodeContainer*/
                Non-checking variants of the above
        */
 
-       MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
+       MapNode getNodeNoCheck(s16 x, s16 y, s16 z, bool *valid_position)
        {
-               if(data == NULL)
-                       throw InvalidPositionException();
+               *valid_position = data != NULL;
+               if(!valid_position)
+                       return MapNode(CONTENT_IGNORE);
+
                return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
        }
        
-       MapNode getNodeNoCheck(v3s16 p)
+       MapNode getNodeNoCheck(v3s16 p, bool *valid_position)
        {
-               return getNodeNoCheck(p.X, p.Y, p.Z);
+               return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
        }
        
        void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
@@ -358,9 +338,8 @@ class MapBlock /*: public NodeContainer*/
                is not valid on this MapBlock.
        */
        bool isValidPositionParent(v3s16 p);
-       MapNode getNodeParent(v3s16 p);
+       MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
        void setNodeParent(v3s16 p, MapNode & n);
-       MapNode getNodeParentNoEx(v3s16 p);
 
        void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
        {
@@ -370,46 +349,8 @@ class MapBlock /*: public NodeContainer*/
                                        setNode(x0+x, y0+y, z0+z, node);
        }
 
-       /*
-               Graphics-related methods
-       */
-       
-       /*// A quick version with nodes passed as parameters
-       u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
-                       v3s16 face_dir);*/
-       /*// A more convenient version
-       u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
-       {
-               return getFaceLight(daynight_ratio,
-                               getNodeParentNoEx(p),
-                               getNodeParentNoEx(p + face_dir),
-                               face_dir);
-       }*/
-       u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
-                       INodeDefManager *nodemgr)
-       {
-               return getFaceLight(daynight_ratio,
-                               getNodeParentNoEx(p),
-                               getNodeParentNoEx(p + face_dir),
-                               face_dir, nodemgr);
-       }
-       
-#ifndef SERVER // Only on client
-
-#if 1
-       /*
-               Thread-safely updates the whole mesh of the mapblock.
-               NOTE: Prefer generating the mesh separately and then using
-               replaceMesh().
-       */
-       void updateMesh(u32 daynight_ratio);
-#endif
-       // Replace the mesh with a new one
-       void replaceMesh(scene::SMesh *mesh_new);
-#endif
-       
        // See comments in mapblock.cpp
-       bool propagateSunlight(core::map<v3s16, bool> & light_sources,
+       bool propagateSunlight(std::set<v3s16> & light_sources,
                        bool remove_light=false, bool *black_air_left=NULL);
        
        // Copies data to VoxelManipulator to getPosRelative()
@@ -417,64 +358,22 @@ class MapBlock /*: public NodeContainer*/
        // Copies data from VoxelManipulator getPosRelative()
        void copyFrom(VoxelManipulator &dst);
 
-#ifndef SERVER // Only on client
-       /*
-               Methods for setting temporary modifications to nodes for
-               drawing
-
-               returns true if the mod was different last time
-       */
-       bool setTempMod(v3s16 p, const NodeMod &mod)
-       {
-               /*dstream<<"setTempMod called on block"
-                               <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                               <<", mod.type="<<mod.type
-                               <<", mod.param="<<mod.param
-                               <<std::endl;*/
-               JMutexAutoLock lock(m_temp_mods_mutex);
-
-               return m_temp_mods.set(p, mod);
-       }
-       // Returns true if there was one
-       bool getTempMod(v3s16 p, NodeMod *mod)
-       {
-               JMutexAutoLock lock(m_temp_mods_mutex);
-
-               return m_temp_mods.get(p, mod);
-       }
-       bool clearTempMod(v3s16 p)
-       {
-               JMutexAutoLock lock(m_temp_mods_mutex);
-
-               return m_temp_mods.clear(p);
-       }
-       bool clearTempMods()
-       {
-               JMutexAutoLock lock(m_temp_mods_mutex);
-               
-               return m_temp_mods.clear();
-       }
-       void copyTempMods(NodeModMap &dst)
-       {
-               JMutexAutoLock lock(m_temp_mods_mutex);
-               m_temp_mods.copy(dst);
-       }
-#endif
-
        /*
                Update day-night lighting difference flag.
-               
                Sets m_day_night_differs to appropriate value.
-               
                These methods don't care about neighboring blocks.
-               It means that to know if a block really doesn't need a mesh
-               update between day and night, the neighboring blocks have
-               to be taken into account. Use Map::dayNightDiffed().
        */
-       void updateDayNightDiff();
+       void actuallyUpdateDayNightDiff();
+       /*
+               Call this to schedule what the previous function does to be done
+               when the value is actually needed.
+       */
+       void expireDayNightDiff();
 
-       bool dayNightDiffed()
+       bool getDayNightDiff()
        {
+               if(m_day_night_differs_expired)
+                       actuallyUpdateDayNightDiff();
                return m_day_night_differs;
        }
 
@@ -509,6 +408,10 @@ class MapBlock /*: public NodeContainer*/
        {
                return m_timestamp;
        }
+       u32 getDiskTimestamp()
+       {
+               return m_disk_timestamp;
+       }
        
        /*
                See m_usage_timer
@@ -526,25 +429,63 @@ class MapBlock /*: public NodeContainer*/
                return m_usage_timer;
        }
 
+       /*
+               See m_refcount
+       */
+       void refGrab()
+       {
+               m_refcount++;
+       }
+       void refDrop()
+       {
+               m_refcount--;
+       }
+       int refGet()
+       {
+               return m_refcount;
+       }
+       
+       /*
+               Node Timers
+       */
+       // Get timer
+       NodeTimer getNodeTimer(v3s16 p){ 
+               return m_node_timers.get(p);
+       }
+       // Deletes timer
+       void removeNodeTimer(v3s16 p){
+               m_node_timers.remove(p);
+       }
+       // Deletes old timer and sets a new one
+       void setNodeTimer(v3s16 p, NodeTimer t){
+               m_node_timers.set(p,t);
+       }
+       // Deletes all timers
+       void clearNodeTimers(){
+               m_node_timers.clear();
+       }
+
        /*
                Serialization
        */
        
        // These don't write or read version by itself
-       void serialize(std::ostream &os, u8 version);
-       void deSerialize(std::istream &is, u8 version);
+       // Set disk to true for on-disk format, false for over-the-network format
+       void serialize(std::ostream &os, u8 version, bool disk);
+       // If disk == true: In addition to doing other things, will add
+       // unknown blocks from id-name mapping to wndef
+       void deSerialize(std::istream &is, u8 version, bool disk);
 
-       // Used after the basic ones when writing on disk (serverside)
-       void serializeDiskExtra(std::ostream &os, u8 version);
-       // In addition to doing other things, will add unknown blocks from
-       // id-name mapping to wndef
-       void deSerializeDiskExtra(std::istream &is, u8 version);
+       void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
+       void deSerializeNetworkSpecific(std::istream &is);
 
 private:
        /*
                Private methods
        */
 
+       void deSerialize_pre22(std::istream &is, u8 version, bool disk);
+
        /*
                Used only internally, because changes can't be tracked
        */
@@ -569,13 +510,13 @@ class MapBlock /*: public NodeContainer*/
        */
 
 #ifndef SERVER // Only on client
-       scene::SMesh *mesh;
-       JMutex mesh_mutex;
+       MapBlockMesh *mesh;
 #endif
        
-       NodeMetadataList *m_node_metadata;
+       NodeMetadataList m_node_metadata;
+       NodeTimerList m_node_timers;
        StaticObjectList m_static_objects;
-       
+
 private:
        /*
                Private member variables
@@ -624,34 +565,29 @@ class MapBlock /*: public NodeContainer*/
        
        // Whether day and night lighting differs
        bool m_day_night_differs;
+       bool m_day_night_differs_expired;
 
        bool m_generated;
        
-#ifndef SERVER // Only on client
-       /*
-               Set to true if the mesh has been ordered to be updated
-               sometime in the background.
-               In practice this is set when the day/night lighting switches.
-       */
-       bool m_mesh_expired;
-       
-       // Temporary modifications to nodes
-       // These are only used when drawing
-       NodeModMap m_temp_mods;
-       JMutex m_temp_mods_mutex;
-#endif
-       
        /*
                When block is removed from active blocks, this is set to gametime.
                Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
        */
        u32 m_timestamp;
+       // The on-disk (or to-be on-disk) timestamp value
+       u32 m_disk_timestamp;
 
        /*
                When the block is accessed, this is set to 0.
                Map will unload the block when this reaches a timeout.
        */
        float m_usage_timer;
+
+       /*
+               Reference count; currently used for determining if this block is in
+               the list of blocks to be drawn.
+       */
+       int m_refcount;
 };
 
 inline bool blockpos_over_limit(v3s16 p)