From 3b0bff2f743a3abf100368f94efafa7c2843a9b7 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 21 Dec 2010 02:25:47 +0200 Subject: [PATCH] Cracking blocks while digging --- data/crack.png | Bin 0 -> 1039 bytes src/client.cpp | 88 ++++------------------ src/client.h | 25 +++++-- src/constants.h | 6 -- src/defaultsettings.cpp | 2 + src/irrlichtwrapper.cpp | 71 ++++++++++++++---- src/irrlichtwrapper.h | 12 ++- src/main.cpp | 161 +++++++++++----------------------------- src/map.cpp | 30 +++++--- src/map.h | 12 ++- src/mapblock.cpp | 50 ++++++------- src/mapblock.h | 10 ++- src/server.cpp | 12 ++- src/tile.cpp | 7 ++ src/tile.h | 2 + src/utility.h | 33 ++------ 16 files changed, 232 insertions(+), 289 deletions(-) create mode 100644 data/crack.png diff --git a/data/crack.png b/data/crack.png new file mode 100644 index 0000000000000000000000000000000000000000..e39b74da01343f285f9874e1ed00e3dd0a4314ea GIT binary patch literal 1039 zcmZuvO-L0$5S}tLOhxe^2qh1;2+Ocbf<tfbgb^iy68%s^Lgg(2D^ntIoA(6q`C8cB*=1(GpV`(>#rD+X>|_8)#j@ZY z+tY0pFHf{JvuXMUKmvryD@*O@qtiz>ZzmraswyJPOhkz2oKpY+U;qL@0B2QkSE?Wa z%s>Q);Qp7SpaR0c1cZRjUWzM=hxa1NEJTb*&Ut1f5=6F`ND;*XM77nZdKDEGCMG0w z=)?;vlMpgGa_pIuP|&d>PpFpR(4&jit1d!Ak%fT7JdbJq%)uI$2(sbFo9Df#vWOKT zk!7$di6FDZq-yV5fU34SAIIK{S5_fmWHP?&l~hpJbdXn6F@5OObVsUV!OWS3cxK={ zq&0UA)u{*mpkk}!C(?wo`5nW(6km#ZcWbwp`WIbST6e~CK zN7xG~qgdw<$aKd3287uD7)ekDA+U50qQC;g_HD%jt5E<0ijI-orOPZB#$ZWh)zJ5S zC242#Q&vnI-_ZH2e=0w1jBY&{y^EI%A8g&-(%yG(WpK^&r1syR0}s!49IgG9H_(`p zdH73FOW;KDk<_a>9j&1kO(V5=gQq78UlnXR6y6o=+?!o+u;K0BljDO^_meNRJ$gNM z{pXL8uI}vI=5Trcn~QbzYbO#n*3|S~**U)I_Ky6zr0LDS(%&^?1m5?JZpq2G`LS)d zx+nbjL+?zuJFRLayt-&Kx9m remove_queue; - core::map::Iterator i; - i = m_fetchblock_history.getIterator(); - for(; i.atEnd() == false; i++) - { - float value = i.getNode()->getValue(); - value += dtime; - i.getNode()->setValue(value); - if(value >= 60.0) - remove_queue.push_back(i.getNode()->getKey()); - } - core::list::Iterator j; - j = remove_queue.begin(); - for(; j != remove_queue.end(); j++) - { - m_fetchblock_history.remove(*j); - } - } -#endif - /*{ JMutexAutoLock lock(m_step_dtime_mutex); m_step_dtime += dtime; }*/ - - /* - BEGIN TEST CODE - */ - - /* - END OF TEST CODE - */ } float Client::asyncStep() @@ -975,7 +940,11 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) if(abs_to_delete.find(p) != NULL) abs_to_delete.remove(p); - // Update objects of block + /* + Update objects of block + + NOTE: Be sure this is done in the main thread. + */ block->updateObjects(is, m_server_ser_ver, m_device->getSceneManager()); } @@ -1482,11 +1451,11 @@ void Client::addNodeFromInventory(v3s16 nodepos, u16 i) } #endif -void Client::pressGround(u8 button, v3s16 nodepos_undersurface, +void Client::groundAction(u8 action, v3s16 nodepos_undersurface, v3s16 nodepos_oversurface, u16 item) { if(connectedAndInitialized() == false){ - dout_client< data(datasize); writeU16(&data[0], TOSERVER_GROUND_ACTION); - writeU8(&data[2], button); + writeU8(&data[2], action); writeV3S16(&data[3], nodepos_undersurface); writeV3S16(&data[9], nodepos_oversurface); writeU16(&data[15], item); @@ -1540,37 +1509,6 @@ void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item) Send(0, data, true); } -void Client::stopDigging() -{ - if(connectedAndInitialized() == false){ - dout_client< data(datasize); - writeU16(&data[0], TOSERVER_GROUND_ACTION); - writeU8(&data[2], 2); - writeV3S16(&data[3], v3s16(0,0,0)); - writeV3S16(&data[9], v3s16(0,0,0)); - writeU16(&data[15], 0); - Send(0, data, true); -} - void Client::sendSignText(v3s16 blockpos, s16 id, std::string text) { /* @@ -1671,17 +1609,23 @@ MapNode Client::getNode(v3s16 p) return m_env.getMap().getNode(p); } +/*void Client::getNode(v3s16 p, MapNode n) +{ + JMutexAutoLock envlock(m_env_mutex); + m_env.getMap().setNode(p, n); +}*/ + /*f32 Client::getGroundHeight(v2s16 p) { JMutexAutoLock envlock(m_env_mutex); return m_env.getMap().getGroundHeight(p); }*/ -bool Client::isNodeUnderground(v3s16 p) +/*bool Client::isNodeUnderground(v3s16 p) { JMutexAutoLock envlock(m_env_mutex); return m_env.getMap().isNodeUnderground(p); -} +}*/ /*Player * Client::getLocalPlayer() { diff --git a/src/client.h b/src/client.h index a1ee3f76..a3d43997 100644 --- a/src/client.h +++ b/src/client.h @@ -185,12 +185,9 @@ public: // Pops out a packet from the packet queue IncomingPacket getPacket(); - /*void removeNode(v3s16 nodepos); - void addNodeFromInventory(v3s16 nodepos, u16 i);*/ - void pressGround(u8 button, v3s16 nodepos_undersurface, + void groundAction(u8 action, v3s16 nodepos_undersurface, v3s16 nodepos_oversurface, u16 item); void clickObject(u8 button, v3s16 blockpos, s16 id, u16 item); - void stopDigging(); void sendSignText(v3s16 blockpos, s16 id, std::string text); @@ -198,10 +195,13 @@ public: // Returns InvalidPositionException if not found MapNode getNode(v3s16 p); + // Returns InvalidPositionException if not found + //void setNode(v3s16 p, MapNode n); + // Returns InvalidPositionException if not found //f32 getGroundHeight(v2s16 p); // Returns InvalidPositionException if not found - bool isNodeUnderground(v3s16 p); + //bool isNodeUnderground(v3s16 p); // Note: The players should not be exposed outside // Return value is valid until client is destroyed @@ -236,6 +236,21 @@ public: //void updateSomeExpiredMeshes(); + void setTempMod(v3s16 p, NodeMod mod) + { + JMutexAutoLock envlock(m_env_mutex); + assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); + v3s16 blockpos = ((ClientMap&)m_env.getMap()).setTempMod(p, mod); + m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio()); + } + void clearTempMod(v3s16 p) + { + JMutexAutoLock envlock(m_env_mutex); + assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); + v3s16 blockpos = ((ClientMap&)m_env.getMap()).clearTempMod(p); + m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio()); + } + private: // Virtual methods from con::PeerHandler diff --git a/src/constants.h b/src/constants.h index c3fca432..7668c745 100644 --- a/src/constants.h +++ b/src/constants.h @@ -39,12 +39,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PI 3.14159 -//#define SERVERMAP_DELETE_UNUSED_SECTORS_TIMEOUT (60*10) -#define SERVERMAP_DELETE_UNUSED_SECTORS_TIMEOUT (60) -#define SERVER_MAP_SAVE_INTERVAL (60) -/*#define SERVERMAP_DELETE_UNUSED_SECTORS_TIMEOUT (10) -#define SERVER_MAP_SAVE_INTERVAL (10)*/ - // This is the same as in minecraft and everything else #define FOV_ANGLE (PI/2.5) diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 04cdf16b..6888fa49 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -56,5 +56,7 @@ void set_default_settings() g_settings.setDefault("max_block_generate_distance", "4"); g_settings.setDefault("time_send_interval", "20"); g_settings.setDefault("time_speed", "360"); + g_settings.setDefault("server_unload_unused_sectors_timeout", "60"); + g_settings.setDefault("server_map_save_interval", "60"); } diff --git a/src/irrlichtwrapper.cpp b/src/irrlichtwrapper.cpp index 69b08a6d..51511eb3 100644 --- a/src/irrlichtwrapper.cpp +++ b/src/irrlichtwrapper.cpp @@ -17,7 +17,8 @@ void IrrlichtWrapper::Run() GetRequest request = m_get_texture_queue.pop(); - dstream<<"got request with key.name="<getTexture(spec.path.c_str()); } - return driver->getTexture(spec.path.c_str()); + + dstream<<"IrrlichtWrapper::getTextureDirect: Loading and modifying " + "texture "<getTexture(spec.path.c_str()); + video::ITexture *result = spec.mod->make(base, spec.name.c_str(), driver); + + delete spec.mod; + + return result; } video::ITexture * CrackTextureMod::make(video::ITexture *original, - video::IVideoDriver* driver) + const char *newname, video::IVideoDriver* driver) { - //TODO - dstream<<__FUNCTION_NAME< dim(16, 16); + core::position2d pos_base(0, 0); + core::position2d pos_other(0, 16 * progression); + + video::IImage *baseimage = driver->createImage(original, pos_base, dim); + assert(baseimage); + + video::ITexture *other = driver->getTexture("../data/crack.png"); + // We have to get the whole texture because getting a smaller area + // messes the whole thing. It is probably a bug in Irrlicht. + video::IImage *otherimage = driver->createImage( + other, core::position2d(0,0), other->getSize()); + + assert(otherimage); + + /*core::rect clip_rect(v2s32(0,0), dim); + otherimage->copyToWithAlpha(baseimage, v2s32(0,0), + core::rect(pos_other, dim), + video::SColor(255,255,255,255), + &clip_rect);*/ + + otherimage->copyToWithAlpha(baseimage, v2s32(0,0), + core::rect(pos_other, dim), + video::SColor(255,255,255,255), + NULL); + + otherimage->drop(); + + video::ITexture *newtexture = driver->addTexture(newname, baseimage); + + baseimage->drop(); + + return newtexture; } #if 0 diff --git a/src/irrlichtwrapper.h b/src/irrlichtwrapper.h index a78edfe7..981e3377 100644 --- a/src/irrlichtwrapper.h +++ b/src/irrlichtwrapper.h @@ -48,6 +48,9 @@ public: void set(std::string name, video::ITexture *texture) { + if(texture == NULL) + return; + JMutexAutoLock lock(m_mutex); m_textures[name] = texture; @@ -78,7 +81,7 @@ struct TextureMod Shall not modify or delete the original texture. */ virtual video::ITexture * make(video::ITexture *original, - video::IVideoDriver* driver) = 0; + const char *newname, video::IVideoDriver* driver) = 0; }; struct CrackTextureMod: public TextureMod @@ -89,7 +92,7 @@ struct CrackTextureMod: public TextureMod } virtual video::ITexture * make(video::ITexture *original, - video::IVideoDriver* driver); + const char *newname, video::IVideoDriver* driver); u16 progression; }; @@ -149,10 +152,11 @@ public: These are called from other threads */ - // Not exactly thread-safe but this needs to be fast + // Not exactly thread-safe but this needs to be fast. + // getTimer()->getRealTime() only reads one variable anyway. u32 getTime() { - return m_device->getTimer()->getTime(); + return m_device->getTimer()->getRealTime(); } video::ITexture* getTexture(TextureSpec spec); diff --git a/src/main.cpp b/src/main.cpp index 56e72572..6b545596 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -179,12 +179,6 @@ TODO: TOSERVER_LEAVE Doing now: ====================================================================== -TODO: Node cracking animation when digging - - TODO: A way to generate new textures by combining textures - - TODO: Mesh update to fetch cracked faces from the former - -TODO: A thread-safe wrapper for irrlicht for threads, to get rid of - g_device ====================================================================== @@ -1164,7 +1158,7 @@ int main(int argc, char *argv[]) < res_count || r0 == 0) - r0 = 2; - - { - u16 i = r0-1; - std::cout<<"-> "; - std::cout<<(i+1)<<": "<(screenW, screenH), 16, fullscreen, false, false, &receiver); - // With vsync - /*device = createDevice(driverType, - core::dimension2d(screenW, screenH), - 16, fullscreen, false, true, &receiver);*/ if (device == 0) return 1; // could not create selected driver. @@ -1380,10 +1306,10 @@ int main(int argc, char *argv[]) */ video::IVideoDriver* driver = device->getVideoDriver(); - // These make the textures not to show at all - //driver->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT); - //driver->setTextureCreationFlag(video::ETCF_OPTIMIZED_FOR_SPEED ); + /* + This changes the minimum allowed number of vertices in a VBO + */ //driver->setMinHardwareBufferVertexCount(1); scene::ISceneManager* smgr = device->getSceneManager(); @@ -2147,48 +2073,69 @@ int main(int argc, char *argv[]) } // regular block } // for coords - /*static v3s16 oldnodepos; - static bool oldnodefound = false;*/ - if(nodefound) { - //std::cout<getLeftClicked()) + if(g_input->getLeftReleased()) + { + client.clearTempMod(nodepos); + dig_time = 0.0; + } if(g_input->getLeftClicked() || (g_input->getLeftState() && nodepos != nodepos_old)) { std::cout<getLeftClicked()) + { + client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0)); } + if(g_input->getLeftState()) + { + dig_time += dtime; + + float dig_time_complete = 0.5; + MapNode n = client.getNode(nodepos); + if(n.d == CONTENT_STONE) + dig_time_complete = 1.5; + + u16 dig_index = (u16)(3.99*dig_time/dig_time_complete); + if(dig_time > 0.2) + { + //dstream<<"dig_index="<getRightClicked()) - /*if(g_input->getRightClicked() || - (g_input->getRightState() && nodepos != nodepos_old))*/ { std::cout<setText(L""); } - /*oldnodefound = nodefound; - oldnodepos = nodepos;*/ - } // selected_object == NULL g_input->resetLeftClicked(); @@ -2197,7 +2144,7 @@ int main(int argc, char *argv[]) if(g_input->getLeftReleased()) { std::cout<getRightReleased()) { @@ -2214,26 +2161,6 @@ int main(int argc, char *argv[]) camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y); - // Background color is choosen based on whether the player is - // much beyond the initial ground level - /*video::SColor bgcolor; - v3s16 p0 = Map::floatToInt(player_position); - // Does this make short random delays? - // NOTE: no need for this, sky doesn't show underground with - // enough range - bool is_underground = client.isNodeUnderground(p0); - //bool is_underground = false; - if(is_underground == false) - bgcolor = video::SColor(255,90,140,200); - else - bgcolor = video::SColor(255,0,0,0);*/ - - //video::SColor bgcolor = video::SColor(255,90,140,200); - //video::SColor bgcolor = skycolor; - - //s32 daynight_i = client.getDayNightIndex(); - //video::SColor bgcolor = skycolor[daynight_i]; - u32 daynight_ratio = client.getDayNightRatio(); video::SColor bgcolor = video::SColor( 255, diff --git a/src/map.cpp b/src/map.cpp index 13db9265..2a517c54 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1622,6 +1622,7 @@ MapBlock * ServerMap::emergeBlock( } //dstream<<"Not found on disk, generating."<setTempMod(relpos, mod); + return blockpos; +} +v3s16 ClientMap::clearTempMod(v3s16 p) +{ + v3s16 blockpos = getNodeBlockPos(p); + MapBlock * blockref = getBlockNoCreate(blockpos); + v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; + + blockref->clearTempMod(relpos); + return blockpos; } void ClientMap::PrintInfo(std::ostream &out) diff --git a/src/map.h b/src/map.h index 05984b1a..3b34cd89 100644 --- a/src/map.h +++ b/src/map.h @@ -35,7 +35,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common_irrlicht.h" #include "heightmap.h" -#include "loadstatus.h" #include "mapnode.h" #include "mapblock.h" #include "mapsector.h" @@ -593,8 +592,15 @@ public: void renderMap(video::IVideoDriver* driver, s32 pass); - // Update master heightmap mesh - void updateMesh(); + /* + Methods for setting temporary modifications to nodes for + drawing. + Return value is position of changed block. + */ + v3s16 setTempMod(v3s16 p, NodeMod mod); + v3s16 clearTempMod(v3s16 p); + // Efficient implementation needs a cache of TempMods + //void clearTempMods(); // For debug printing virtual void PrintInfo(std::ostream &out); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index af08cada..e2262544 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -300,6 +300,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; } } @@ -646,14 +648,31 @@ void MapBlock::updateMesh(u32 daynight_ratio) if(f.tile.feature == TILEFEAT_NONE) { - /*collector.append(g_tile_materials[f.tile.id], f.vertices, 4, - indices, 6);*/ 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); } } @@ -668,19 +687,6 @@ void MapBlock::updateMesh(u32 daynight_ratio) <<" materials (meshbuffers)"<::Iterator i; - i = fastfaces_new->begin(); - for(; i != fastfaces_new->end(); i++) - { - delete *i; - } - fastfaces_new->clear(); - delete fastfaces_new;*/ - /* Add special graphics: - torches @@ -688,14 +694,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; zgetMaterial().setTexture(0, g_irrlicht->getTexture("../data/torch_on_floor.png")); - //g_texturecache.get("torch_on_floor")); else if(dir == v3s16(0,1,0)) buf->getMaterial().setTexture(0, g_irrlicht->getTexture("../data/torch_on_ceiling.png")); - //g_texturecache.get("torch_on_ceiling")); // For backwards compatibility else if(dir == v3s16(0,0,0)) buf->getMaterial().setTexture(0, g_irrlicht->getTexture("../data/torch_on_floor.png")); - //g_texturecache.get("torch_on_floor")); else buf->getMaterial().setTexture(0, g_irrlicht->getTexture("../data/torch.png")); - //buf->getMaterial().setTexture(0, g_texturecache.get("torch")); // Add to mesh mesh_new->addMeshBuffer(buf); diff --git a/src/mapblock.h b/src/mapblock.h index 2bdf639b..b5126b82 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -59,9 +59,10 @@ enum NodeModType struct NodeMod { - NodeMod() + NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0) { - type = NODEMOD_NONE; + type = a_type; + param = a_param; } enum NodeModType type; u16 param; @@ -393,6 +394,11 @@ public: */ void setTempMod(v3s16 p, NodeMod mod) { + /*dstream<<"setTempMod called on block" + <<" ("< 0) + { + dout_server<<"Server: Unloaded "< 0) { - if(m_list.size() == 1) - m_is_empty_mutex.Lock(); - typename core::list::Iterator begin = m_list.begin(); T t = *begin; m_list.erase(begin); return t; } - if(wait_if_empty == false) - throw ItemNotFoundException("MutexedQueue: item not found"); + if(wait_time_ms >= wait_time_max_ms) + throw ItemNotFoundException("MutexedQueue: queue is empty"); } - - // To wait for an empty list, we're gonna hang on this mutex - m_is_empty_mutex.Lock(); - m_is_empty_mutex.Unlock(); - // Then loop to the beginning and hopefully return something + // Wait a while before trying again + sleep_ms(10); + wait_time_ms += 10; } } @@ -1134,11 +1127,6 @@ public: return m_mutex; } - JMutex & getIsEmptyMutex() - { - return m_is_empty_mutex; - } - core::list & getList() { return m_list; @@ -1146,8 +1134,6 @@ public: protected: JMutex m_mutex; - // This is locked always when the list is empty - JMutex m_is_empty_mutex; core::list m_list; }; @@ -1262,9 +1248,6 @@ public: request.dest = dest; m_queue.getList().push_back(request); - - if(m_queue.getList().size() == 1) - m_queue.getIsEmptyMutex().Unlock(); } GetRequest pop(bool wait_if_empty=false) -- 2.30.2