continued.
[oweals/minetest.git] / src / mapblock.cpp
index 7e23d295b07ec8933901bdbd2e519f63b75d0202..90ff05bd1468434066d23e51baa06dfe69b73ed6 100644 (file)
@@ -34,25 +34,26 @@ MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
                m_pos(pos),
                changed(true),
                is_underground(false),
-               m_mesh_expired(false),
                m_day_night_differs(false),
                m_objects(this)
 {
        data = NULL;
        if(dummy == false)
                reallocate();
+       
+       m_spawn_timer = -10000;
 
+#ifndef SERVER
+       m_mesh_expired = false;
        mesh_mutex.Init();
-
        mesh = NULL;
-       /*for(s32 i=0; i<DAYNIGHT_CACHE_COUNT; i++)
-       {
-               mesh[i] = NULL;
-       }*/
+       m_temp_mods_mutex.Init();
+#endif
 }
 
 MapBlock::~MapBlock()
 {
+#ifndef SERVER
        {
                JMutexAutoLock lock(mesh_mutex);
                
@@ -61,15 +62,8 @@ MapBlock::~MapBlock()
                        mesh->drop();
                        mesh = NULL;
                }
-               /*for(s32 i=0; i<DAYNIGHT_CACHE_COUNT; i++)
-               {
-                       if(mesh[i] != NULL)
-                       {
-                               mesh[i]->drop();
-                               mesh[i] = NULL;
-                       }
-               }*/
        }
+#endif
 
        if(data)
                delete[] data;
@@ -136,6 +130,52 @@ MapNode MapBlock::getNodeParentNoEx(v3s16 p)
        }
 }
 
+/*
+       Parameters must consist of air and !air.
+       Order doesn't matter.
+
+       If either of the nodes doesn't exist, light is 0.
+       
+       parameters:
+               daynight_ratio: 0...1000
+               n: getNodeParent(p)
+               n2: getNodeParent(p + face_dir)
+               face_dir: axis oriented unit vector from p to p2
+*/
+u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
+               v3s16 face_dir)
+{
+       try{
+               u8 light;
+               u8 l1 = n.getLightBlend(daynight_ratio);
+               u8 l2 = n2.getLightBlend(daynight_ratio);
+               if(l1 > l2)
+                       light = l1;
+               else
+                       light = l2;
+
+               // Make some nice difference to different sides
+
+               /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
+                       light = diminish_light(diminish_light(light));
+               else if(face_dir.X == -1 || face_dir.Z == -1)
+                       light = diminish_light(light);*/
+
+               if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
+                       light = diminish_light(diminish_light(light));
+               else if(face_dir.Z == 1 || face_dir.Z == -1)
+                       light = diminish_light(light);
+
+               return light;
+       }
+       catch(InvalidPositionException &e)
+       {
+               return 0;
+       }
+}
+
+#ifndef SERVER
+
 void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
                v3s16 dir, v3f scale, v3f posRelative_f,
                core::array<FastFace> &dest)
@@ -200,8 +240,8 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
 
        v3f zerovector = v3f(0,0,0);
        
-       u8 li = decode_light(light);
-       //u8 li = 150;
+       //u8 li = decode_light(light);
+       u8 li = light;
 
        u8 alpha = 255;
 
@@ -229,50 +269,6 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
        //return f;
 }
        
-/*
-       Parameters must consist of air and !air.
-       Order doesn't matter.
-
-       If either of the nodes doesn't exist, light is 0.
-       
-       parameters:
-               daynight_ratio: 0...1000
-               n: getNodeParent(p)
-               n2: getNodeParent(p + face_dir)
-               face_dir: axis oriented unit vector from p to p2
-*/
-u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
-               v3s16 face_dir)
-{
-       try{
-               u8 light;
-               u8 l1 = n.getLightBlend(daynight_ratio);
-               u8 l2 = n2.getLightBlend(daynight_ratio);
-               if(l1 > l2)
-                       light = l1;
-               else
-                       light = l2;
-
-               // Make some nice difference to different sides
-
-               /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
-                       light = diminish_light(diminish_light(light));
-               else if(face_dir.X == -1 || face_dir.Z == -1)
-                       light = diminish_light(light);*/
-
-               if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
-                       light = diminish_light(diminish_light(light));
-               else if(face_dir.Z == 1 || face_dir.Z == -1)
-                       light = diminish_light(light);
-
-               return light;
-       }
-       catch(InvalidPositionException &e)
-       {
-               return 0;
-       }
-}
-
 /*
        Gets node tile from any place relative to block.
        Returns TILE_NODE if doesn't exist or should not be drawn.
@@ -307,6 +303,8 @@ TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir)
                }
                if(mod.type == NODEMOD_CRACK)
                {
+                       spec.feature = TILEFEAT_CRACK;
+                       spec.param.crack.progression = mod.param;
                }
        }
        
@@ -440,14 +438,14 @@ void MapBlock::updateFastFaceRow(
                                // If node at sp (tile0) is more solid
                                if(mf == 1)
                                {
-                                       makeFastFace(tile0, light,
+                                       makeFastFace(tile0, decode_light(light),
                                                        sp, face_dir, scale,
                                                        posRelative_f, dest);
                                }
                                // If node at sp is less solid (mf == 2)
                                else
                                {
-                                       makeFastFace(tile1, light,
+                                       makeFastFace(tile1, decode_light(light),
                                                        sp+face_dir_f, -face_dir, scale,
                                                        posRelative_f, dest);
                                }
@@ -587,47 +585,52 @@ void MapBlock::updateMesh(u32 daynight_ratio)
 
                NOTE: This is the slowest part of this method.
        */
+       
+       {
+               // Lock this, as m_temp_mods will be used directly
+               JMutexAutoLock lock(m_temp_mods_mutex);
 
-       /*
-               Go through every y,z and get top faces in rows of x+
-       */
-       for(s16 y=0; y<MAP_BLOCKSIZE; y++){
-               for(s16 z=0; z<MAP_BLOCKSIZE; z++){
-                       updateFastFaceRow(daynight_ratio, posRelative_f,
-                                       v3s16(0,y,z), MAP_BLOCKSIZE,
-                                       v3s16(1,0,0), //dir
-                                       v3f  (1,0,0),
-                                       v3s16(0,1,0), //face dir
-                                       v3f  (0,1,0),
-                                       fastfaces_new);
-               }
-       }
-       /*
-               Go through every x,y and get right faces in rows of z+
-       */
-       for(s16 x=0; x<MAP_BLOCKSIZE; x++){
+               /*
+                       Go through every y,z and get top faces in rows of x+
+               */
                for(s16 y=0; y<MAP_BLOCKSIZE; y++){
-                       updateFastFaceRow(daynight_ratio, posRelative_f,
-                                       v3s16(x,y,0), MAP_BLOCKSIZE,
-                                       v3s16(0,0,1),
-                                       v3f  (0,0,1),
-                                       v3s16(1,0,0),
-                                       v3f  (1,0,0),
-                                       fastfaces_new);
+                       for(s16 z=0; z<MAP_BLOCKSIZE; z++){
+                               updateFastFaceRow(daynight_ratio, posRelative_f,
+                                               v3s16(0,y,z), MAP_BLOCKSIZE,
+                                               v3s16(1,0,0), //dir
+                                               v3f  (1,0,0),
+                                               v3s16(0,1,0), //face dir
+                                               v3f  (0,1,0),
+                                               fastfaces_new);
+                       }
                }
-       }
-       /*
-               Go through every y,z and get back faces in rows of x+
-       */
-       for(s16 z=0; z<MAP_BLOCKSIZE; z++){
-               for(s16 y=0; y<MAP_BLOCKSIZE; y++){
-                       updateFastFaceRow(daynight_ratio, posRelative_f,
-                                       v3s16(0,y,z), MAP_BLOCKSIZE,
-                                       v3s16(1,0,0),
-                                       v3f  (1,0,0),
-                                       v3s16(0,0,1),
-                                       v3f  (0,0,1),
-                                       fastfaces_new);
+               /*
+                       Go through every x,y and get right faces in rows of z+
+               */
+               for(s16 x=0; x<MAP_BLOCKSIZE; x++){
+                       for(s16 y=0; y<MAP_BLOCKSIZE; y++){
+                               updateFastFaceRow(daynight_ratio, posRelative_f,
+                                               v3s16(x,y,0), MAP_BLOCKSIZE,
+                                               v3s16(0,0,1),
+                                               v3f  (0,0,1),
+                                               v3s16(1,0,0),
+                                               v3f  (1,0,0),
+                                               fastfaces_new);
+                       }
+               }
+               /*
+                       Go through every y,z and get back faces in rows of x+
+               */
+               for(s16 z=0; z<MAP_BLOCKSIZE; z++){
+                       for(s16 y=0; y<MAP_BLOCKSIZE; y++){
+                               updateFastFaceRow(daynight_ratio, posRelative_f,
+                                               v3s16(0,y,z), MAP_BLOCKSIZE,
+                                               v3s16(1,0,0),
+                                               v3f  (1,0,0),
+                                               v3s16(0,0,1),
+                                               v3f  (0,0,1),
+                                               fastfaces_new);
+                       }
                }
        }
 
@@ -653,12 +656,31 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                        
                        if(f.tile.feature == TILEFEAT_NONE)
                        {
-                               collector.append(g_tile_materials[f.tile.id], f.vertices, 4,
+                               collector.append(tile_material_get(f.tile.id), f.vertices, 4,
                                                indices, 6);
                        }
+                       else if(f.tile.feature == TILEFEAT_CRACK)
+                       {
+                               const char *path = tile_texture_path_get(f.tile.id);
+
+                               u16 progression = f.tile.param.crack.progression;
+
+                               std::string name = (std::string)path + "_cracked_"
+                                               + (char)('0' + progression);
+
+                               TextureMod *mod = new CrackTextureMod(progression);
+
+                               video::ITexture *texture = g_irrlicht->getTexture(
+                                               TextureSpec(name, path, mod));
+
+                               video::SMaterial material = tile_material_get(f.tile.id);
+                               material.setTexture(0, texture);
+
+                               collector.append(material, f.vertices, 4, indices, 6);
+                       }
                        else
                        {
-                               // Not implemented
+                               // No such feature
                                assert(0);
                        }
                }
@@ -666,6 +688,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                collector.fillMesh(mesh_new);
 
                // Use VBO for mesh (this just would set this for ever buffer)
+               // This will lead to infinite memory usage because or irrlicht.
                //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
                
                /*std::cout<<"MapBlock has "<<fastfaces_new->getSize()<<" faces "
@@ -673,19 +696,6 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                                <<" materials (meshbuffers)"<<std::endl;*/
        }
 
-       /*
-               Clear temporary FastFaces
-       */
-
-       /*core::list<FastFace*>::Iterator i;
-       i = fastfaces_new->begin();
-       for(; i != fastfaces_new->end(); i++)
-       {
-               delete *i;
-       }
-       fastfaces_new->clear();
-       delete fastfaces_new;*/
-
        /*
                Add special graphics:
                - torches
@@ -693,14 +703,6 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                TODO: Optimize by using same meshbuffer for same textures
        */
 
-       /*scene::ISceneManager *smgr = NULL;
-       video::IVideoDriver* driver = NULL;
-       if(g_device)
-       {
-               smgr = g_device->getSceneManager();
-               driver = smgr->getVideoDriver();
-       }*/
-                       
        for(s16 z=0; z<MAP_BLOCKSIZE; z++)
        for(s16 y=0; y<MAP_BLOCKSIZE; y++)
        for(s16 x=0; x<MAP_BLOCKSIZE; x++)
@@ -755,16 +757,17 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                                        = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
                        if(dir == v3s16(0,-1,0))
                                buf->getMaterial().setTexture(0,
-                                               g_texturecache.get("torch_on_floor"));
+                                               g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str()));
                        else if(dir == v3s16(0,1,0))
                                buf->getMaterial().setTexture(0,
-                                               g_texturecache.get("torch_on_ceiling"));
+                                               g_irrlicht->getTexture(porting::getDataPath("torch_on_ceiling.png").c_str()));
                        // For backwards compatibility
                        else if(dir == v3s16(0,0,0))
                                buf->getMaterial().setTexture(0,
-                                               g_texturecache.get("torch_on_floor"));
+                                               g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str()));
                        else
-                               buf->getMaterial().setTexture(0, g_texturecache.get("torch"));
+                               buf->getMaterial().setTexture(0, 
+                                               g_irrlicht->getTexture(porting::getDataPath("torch.png").c_str()));
 
                        // Add to mesh
                        mesh_new->addMeshBuffer(buf);
@@ -844,6 +847,8 @@ void MapBlock::updateMesh(u32 daynight_ratio)
        }
 }*/
 
+#endif // !SERVER
+
 /*
        Propagates sunlight down through the block.
        Doesn't modify nodes that are not affected by sunlight.
@@ -856,7 +861,9 @@ void MapBlock::updateMesh(u32 daynight_ratio)
        is_underground is set.
 
        At the moment, all sunlighted nodes are added to light_sources.
-       TODO: This could be optimized.
+       - SUGG: This could be optimized
+
+       Turns sunglighted mud into grass.
 */
 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
 {
@@ -876,10 +883,6 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
                                MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
                                if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
                                {
-                                       /*if(is_underground)
-                                       {
-                                               no_sunlight = true;
-                                       }*/
                                        no_sunlight = true;
                                }
                        }
@@ -887,15 +890,14 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
                        {
                                no_top_block = true;
                                
-                               // TODO: This makes over-ground roofed places sunlighted
+                               // NOTE: This makes over-ground roofed places sunlighted
                                // Assume sunlight, unless is_underground==true
                                if(is_underground)
                                {
                                        no_sunlight = true;
                                }
                                
-                               // TODO: There has to be some way to allow this behaviour
-                               // As of now, it just makes everything dark.
+                               // NOTE: As of now, it just would make everything dark.
                                // No sunlight here
                                //no_sunlight = true;
                        }
@@ -924,7 +926,15 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
 
                                                light_sources.insert(pos_relative + pos, true);
                                        }
-                                       else{
+                                       else
+                                       {
+                                               // Turn mud into grass
+                                               if(n.d == CONTENT_MUD)
+                                               {
+                                                       n.d = CONTENT_GRASS;
+                                               }
+
+                                               // Sunlight goes no further
                                                break;
                                        }
                                }
@@ -996,6 +1006,52 @@ void MapBlock::copyTo(VoxelManipulator &dst)
                core::array<DistanceSortedObject> &dest)
 {
 }*/
+void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
+{
+       /*
+               Step objects
+       */
+       m_objects.step(dtime, server, daynight_ratio);
+       
+       /*
+               Spawn some objects at random.
+
+               Use dayNightDiffed() to approximate being near ground level
+       */
+       if(m_spawn_timer < -999)
+       {
+               m_spawn_timer = 60;
+       }
+       if(dayNightDiffed() == true && getObjectCount() == 0)
+       {
+               m_spawn_timer -= dtime;
+               if(m_spawn_timer <= 0.0)
+               {
+                       m_spawn_timer += myrand() % 300;
+                       
+                       v2s16 p2d(
+                               (myrand()%(MAP_BLOCKSIZE-1))+0,
+                               (myrand()%(MAP_BLOCKSIZE-1))+0
+                       );
+
+                       s16 y = getGroundLevel(p2d);
+                       
+                       if(y >= 0)
+                       {
+                               v3s16 p(p2d.X, y+1, p2d.Y);
+
+                               if(getNode(p).d == CONTENT_AIR
+                                               && getNode(p).getLightBlend(daynight_ratio) <= 11)
+                               {
+                                       RatObject *obj = new RatObject(NULL, -1, intToFloat(p));
+                                       addObject(obj);
+                               }
+                       }
+               }
+       }
+
+       setChangedFlag();
+}
 
 
 void MapBlock::updateDayNightDiff()
@@ -1045,6 +1101,31 @@ void MapBlock::updateDayNightDiff()
        m_day_night_differs = differs;
 }
 
+s16 MapBlock::getGroundLevel(v2s16 p2d)
+{
+       if(isDummy())
+               return -3;
+       try
+       {
+               s16 y = MAP_BLOCKSIZE-1;
+               for(; y>=0; y--)
+               {
+                       if(is_ground_content(getNodeRef(p2d.X, y, p2d.Y).d))
+                       {
+                               if(y == MAP_BLOCKSIZE-1)
+                                       return -2;
+                               else
+                                       return y;
+                       }
+               }
+               return -1;
+       }
+       catch(InvalidPositionException &e)
+       {
+               return -3;
+       }
+}
+
 /*
        Serialization
 */