From cb130d9158dc4e9c456d088d5e214b7d829ccc3a Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 26 Jun 2011 00:03:58 +0300 Subject: cleaned map stuff --- src/client.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/client.cpp') diff --git a/src/client.cpp b/src/client.cpp index abc056505..f97acfd43 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "main.h" #include #include "porting.h" +#include "mapsector.h" void * MeshUpdateThread::Thread() { @@ -715,15 +716,16 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) //TimeTaker timer("MapBlock deSerialize"); // 0ms - try{ - block = sector->getBlockNoCreate(p.Y); + block = sector->getBlockNoCreateNoEx(p.Y); + if(block) + { /* Update an existing block */ //dstream<<"Updating"<deSerialize(istr, ser_version); } - catch(InvalidPositionException &e) + else { /* Create a new block @@ -952,6 +954,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) } else if(command == TOCLIENT_SECTORMETA) { + dstream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"< Date: Sun, 26 Jun 2011 02:34:36 +0300 Subject: even more code refactoring --- src/client.cpp | 142 ++++++++++++++++++++++++++++++++++++++++++++++--- src/client.h | 118 ++++------------------------------------ src/environment.cpp | 2 +- src/game.cpp | 6 ++- src/main.cpp | 2 - src/map.cpp | 84 +++++++++++++++++++---------- src/map.h | 68 +++-------------------- src/mapblockobject.cpp | 1 + src/mapchunk.h | 6 +++ src/server.cpp | 1 + 10 files changed, 221 insertions(+), 209 deletions(-) (limited to 'src/client.cpp') diff --git a/src/client.cpp b/src/client.cpp index f97acfd43..6d0e6860c 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -5,7 +5,7 @@ Copyright (C) 2010 celeron55, Perttu Ahola 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 -(at your option) any later version. +MeshUpdateQueue::(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 @@ -26,6 +26,104 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "porting.h" #include "mapsector.h" +#include "mapblock_mesh.h" +#include "mapblock.h" + +/* + QueuedMeshUpdate +*/ + +QueuedMeshUpdate::QueuedMeshUpdate(): + p(-1337,-1337,-1337), + data(NULL), + ack_block_to_server(false) +{ +} + +QueuedMeshUpdate::~QueuedMeshUpdate() +{ + if(data) + delete data; +} + +/* + MeshUpdateQueue +*/ + +MeshUpdateQueue::MeshUpdateQueue() +{ + m_mutex.Init(); +} + +MeshUpdateQueue::~MeshUpdateQueue() +{ + JMutexAutoLock lock(m_mutex); + + core::list::Iterator i; + for(i=m_queue.begin(); i!=m_queue.end(); i++) + { + QueuedMeshUpdate *q = *i; + delete q; + } +} + +/* + peer_id=0 adds with nobody to send to +*/ +void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server) +{ + DSTACK(__FUNCTION_NAME); + + assert(data); + + JMutexAutoLock lock(m_mutex); + + /* + Find if block is already in queue. + If it is, update the data and quit. + */ + core::list::Iterator i; + for(i=m_queue.begin(); i!=m_queue.end(); i++) + { + QueuedMeshUpdate *q = *i; + if(q->p == p) + { + if(q->data) + delete q->data; + q->data = data; + if(ack_block_to_server) + q->ack_block_to_server = true; + return; + } + } + + /* + Add the block + */ + QueuedMeshUpdate *q = new QueuedMeshUpdate; + q->p = p; + q->data = data; + q->ack_block_to_server = ack_block_to_server; + m_queue.push_back(q); +} + +// Returned pointer must be deleted +// Returns NULL if queue is empty +QueuedMeshUpdate * MeshUpdateQueue::pop() +{ + JMutexAutoLock lock(m_mutex); + + core::list::Iterator i = m_queue.begin(); + if(i == m_queue.end()) + return NULL; + QueuedMeshUpdate *q = *i; + m_queue.erase(i); + return q; +} + +/* + MeshUpdateThread +*/ void * MeshUpdateThread::Thread() { @@ -1736,7 +1834,7 @@ void Client::addNode(v3s16 p, MapNode n) try { - TimeTaker timer3("Client::addNode(): addNodeAndUpdate"); + //TimeTaker timer3("Client::addNode(): addNodeAndUpdate"); m_env.getMap().addNodeAndUpdate(p, n, modified_blocks); } catch(InvalidPositionException &e) @@ -1964,12 +2062,6 @@ void Client::printDebugInfo(std::ostream &os) <= 0 && m_daynight_i < DAYNIGHT_CACHE_COUNT); - return m_daynight_i; -}*/ - u32 Client::getDayNightRatio() { //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out @@ -1983,6 +2075,40 @@ u16 Client::getHP() return player->hp; } +void Client::setTempMod(v3s16 p, NodeMod mod) +{ + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out + assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); + + core::map affected_blocks; + ((ClientMap&)m_env.getMap()).setTempMod(p, mod, + &affected_blocks); + + for(core::map::Iterator + i = affected_blocks.getIterator(); + i.atEnd() == false; i++) + { + i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio()); + } +} + +void Client::clearTempMod(v3s16 p) +{ + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out + assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); + + core::map affected_blocks; + ((ClientMap&)m_env.getMap()).clearTempMod(p, + &affected_blocks); + + for(core::map::Iterator + i = affected_blocks.getIterator(); + i.atEnd() == false; i++) + { + i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio()); + } +} + void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server) { /*dstream<<"Client::addUpdateMeshTask(): " diff --git a/src/client.h b/src/client.h index a1b1c66b4..442eaef5d 100644 --- a/src/client.h +++ b/src/client.h @@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "clientobject.h" +struct MeshMakeData; + class ClientNotReadyException : public BaseException { public: @@ -43,18 +45,8 @@ struct QueuedMeshUpdate MeshMakeData *data; bool ack_block_to_server; - QueuedMeshUpdate(): - p(-1337,-1337,-1337), - data(NULL), - ack_block_to_server(false) - { - } - - ~QueuedMeshUpdate() - { - if(data) - delete data; - } + QueuedMeshUpdate(); + ~QueuedMeshUpdate(); }; /* @@ -63,76 +55,18 @@ struct QueuedMeshUpdate class MeshUpdateQueue { public: - MeshUpdateQueue() - { - m_mutex.Init(); - } - - ~MeshUpdateQueue() - { - JMutexAutoLock lock(m_mutex); + MeshUpdateQueue(); - core::list::Iterator i; - for(i=m_queue.begin(); i!=m_queue.end(); i++) - { - QueuedMeshUpdate *q = *i; - delete q; - } - } + ~MeshUpdateQueue(); /* peer_id=0 adds with nobody to send to */ - void addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server) - { - DSTACK(__FUNCTION_NAME); - - assert(data); - - JMutexAutoLock lock(m_mutex); - - /* - Find if block is already in queue. - If it is, update the data and quit. - */ - core::list::Iterator i; - for(i=m_queue.begin(); i!=m_queue.end(); i++) - { - QueuedMeshUpdate *q = *i; - if(q->p == p) - { - if(q->data) - delete q->data; - q->data = data; - if(ack_block_to_server) - q->ack_block_to_server = true; - return; - } - } - - /* - Add the block - */ - QueuedMeshUpdate *q = new QueuedMeshUpdate; - q->p = p; - q->data = data; - q->ack_block_to_server = ack_block_to_server; - m_queue.push_back(q); - } + void addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server); // Returned pointer must be deleted // Returns NULL if queue is empty - QueuedMeshUpdate * pop() - { - JMutexAutoLock lock(m_mutex); - - core::list::Iterator i = m_queue.begin(); - if(i == m_queue.end()) - return NULL; - QueuedMeshUpdate *q = *i; - m_queue.erase(i); - return q; - } + QueuedMeshUpdate * pop(); u32 size() { @@ -309,40 +243,8 @@ public: u16 getHP(); - //void updateSomeExpiredMeshes(); - - void setTempMod(v3s16 p, NodeMod mod) - { - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); - - core::map affected_blocks; - ((ClientMap&)m_env.getMap()).setTempMod(p, mod, - &affected_blocks); - - for(core::map::Iterator - i = affected_blocks.getIterator(); - i.atEnd() == false; i++) - { - i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio()); - } - } - void clearTempMod(v3s16 p) - { - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); - - core::map affected_blocks; - ((ClientMap&)m_env.getMap()).clearTempMod(p, - &affected_blocks); - - for(core::map::Iterator - i = affected_blocks.getIterator(); - i.atEnd() == false; i++) - { - i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio()); - } - } + void setTempMod(v3s16 p, NodeMod mod); + void clearTempMod(v3s16 p); float getAvgRtt() { diff --git a/src/environment.cpp b/src/environment.cpp index cd255341f..6a7c8478e 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" #include "collision.h" #include "content_mapnode.h" - +#include "mapblock.h" Environment::Environment(): m_time_of_day(9000) diff --git a/src/game.cpp b/src/game.cpp index f3fac0c84..337879cb8 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -30,8 +30,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clouds.h" #include "keycode.h" #include "farmesh.h" +#include "mapblock.h" -// TODO: Move content-aware stuff to separate file +/* + TODO: Move content-aware stuff to separate file by adding properties + and virtual interfaces +*/ #include "content_mapnode.h" #include "content_nodemeta.h" diff --git a/src/main.cpp b/src/main.cpp index 41da310f4..9c7cf2e28 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -238,8 +238,6 @@ FIXME: The new optimized map sending doesn't sometimes send enough blocks from big caves and such FIXME: Block send distance configuration does not take effect for some reason -TODO: Map saving should be done by EmergeThread - SUGG: Map unloading based on sector reference is not very good, it keeps unnecessary stuff in memory. I guess. Investigate this. diff --git a/src/map.cpp b/src/map.cpp index d8cc34ca7..3164028b7 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serverobject.h" #include "content_mapnode.h" #include "mapgen.h" +#include "nodemetadata.h" extern "C" { #include "sqlite3.h" @@ -141,19 +142,6 @@ MapBlock * Map::getBlockNoCreate(v3s16 p3d) return block; } - -/*MapBlock * Map::getBlockCreate(v3s16 p3d) -{ - v2s16 p2d(p3d.X, p3d.Z); - MapSector * sector = getSectorCreate(p2d); - assert(sector); - MapBlock *block = sector->getBlockNoCreate(p3d.Y); - if(block) - return block; - block = sector->createBlankBlock(p3d.Y); - return block; -}*/ - bool Map::isNodeUnderground(v3s16 p) { v3s16 blockpos = getNodeBlockPos(p); @@ -167,6 +155,45 @@ bool Map::isNodeUnderground(v3s16 p) } } +bool Map::isValidPosition(v3s16 p) +{ + v3s16 blockpos = getNodeBlockPos(p); + MapBlock *block = getBlockNoCreate(blockpos); + return (block != NULL); +} + +// Returns a CONTENT_IGNORE node if not found +MapNode Map::getNodeNoEx(v3s16 p) +{ + v3s16 blockpos = getNodeBlockPos(p); + MapBlock *block = getBlockNoCreateNoEx(blockpos); + if(block == NULL) + return MapNode(CONTENT_IGNORE); + v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; + return block->getNodeNoCheck(relpos); +} + +// throws InvalidPositionException if not found +MapNode Map::getNode(v3s16 p) +{ + v3s16 blockpos = getNodeBlockPos(p); + MapBlock *block = getBlockNoCreateNoEx(blockpos); + if(block == NULL) + throw InvalidPositionException(); + v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; + return block->getNodeNoCheck(relpos); +} + +// throws InvalidPositionException if not found +void Map::setNode(v3s16 p, MapNode & n) +{ + v3s16 blockpos = getNodeBlockPos(p); + MapBlock *block = getBlockNoCreate(blockpos); + v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; + block->setNodeNoCheck(relpos, n); +} + + /* Goes recursively through the neighbours of the node. @@ -2096,22 +2123,25 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, /* Update lighting */ - - core::map lighting_update_blocks; - // Center block - lighting_update_blocks.insert(block->getPos(), block); -#if 0 - // All modified blocks - for(core::map::Iterator - i = changed_blocks.getIterator(); - i.atEnd() == false; i++) { - lighting_update_blocks.insert(i.getNode()->getKey(), - i.getNode()->getValue()); + TimeTaker t("finishBlockMake lighting update"); + + core::map lighting_update_blocks; + // Center block + lighting_update_blocks.insert(block->getPos(), block); + #if 0 + // All modified blocks + for(core::map::Iterator + i = changed_blocks.getIterator(); + i.atEnd() == false; i++) + { + lighting_update_blocks.insert(i.getNode()->getKey(), + i.getNode()->getValue()); + } + #endif + updateLighting(lighting_update_blocks, changed_blocks); } -#endif - updateLighting(lighting_update_blocks, changed_blocks); - + /* Add random objects to block */ diff --git a/src/map.h b/src/map.h index 406b1bc84..c64f8cbdb 100644 --- a/src/map.h +++ b/src/map.h @@ -25,27 +25,17 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include -#ifdef _WIN32 - #include - #define sleep_s(x) Sleep((x*1000)) -#else - #include - #define sleep_s(x) sleep(x) -#endif - #include "common_irrlicht.h" #include "mapnode.h" -#include "mapblock.h" +#include "mapblock_nodemod.h" #include "constants.h" #include "voxel.h" -#include "mapchunk.h" -#include "nodemetadata.h" class MapSector; class ServerMapSector; class ClientMapSector; - class MapBlock; +class NodeMetadata; namespace mapgen{ struct BlockMakeData; @@ -161,66 +151,20 @@ public: MapBlock * getBlockNoCreate(v3s16 p); // Returns NULL if not found MapBlock * getBlockNoCreateNoEx(v3s16 p); - // Gets an existing block or creates an empty one - //MapBlock * getBlockCreate(v3s16 p); // Returns InvalidPositionException if not found bool isNodeUnderground(v3s16 p); - // virtual from NodeContainer - bool isValidPosition(v3s16 p) - { - v3s16 blockpos = getNodeBlockPos(p); - MapBlock *blockref; - try{ - blockref = getBlockNoCreate(blockpos); - } - catch(InvalidPositionException &e) - { - return false; - } - return true; - /*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; - bool is_valid = blockref->isValidPosition(relpos); - return is_valid;*/ - } + bool isValidPosition(v3s16 p); - // virtual from NodeContainer // throws InvalidPositionException if not found - MapNode getNode(v3s16 p) - { - v3s16 blockpos = getNodeBlockPos(p); - MapBlock * blockref = getBlockNoCreate(blockpos); - v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; + MapNode getNode(v3s16 p); - return blockref->getNodeNoCheck(relpos); - } - - // virtual from NodeContainer // throws InvalidPositionException if not found - void setNode(v3s16 p, MapNode & n) - { - v3s16 blockpos = getNodeBlockPos(p); - MapBlock * blockref = getBlockNoCreate(blockpos); - v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; - blockref->setNodeNoCheck(relpos, n); - } + void setNode(v3s16 p, MapNode & n); // Returns a CONTENT_IGNORE node if not found - MapNode getNodeNoEx(v3s16 p) - { - try{ - v3s16 blockpos = getNodeBlockPos(p); - MapBlock * blockref = getBlockNoCreate(blockpos); - v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; - - return blockref->getNodeNoCheck(relpos); - } - catch(InvalidPositionException &e) - { - return MapNode(CONTENT_IGNORE); - } - } + MapNode getNodeNoEx(v3s16 p); void unspreadLight(enum LightBank bank, core::map & from_nodes, diff --git a/src/mapblockobject.cpp b/src/mapblockobject.cpp index 51ac4c66b..ab1c20267 100644 --- a/src/mapblockobject.cpp +++ b/src/mapblockobject.cpp @@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map.h" #include "inventory.h" #include "utility.h" +#include "mapblock.h" /* MapBlockObject diff --git a/src/mapchunk.h b/src/mapchunk.h index 9860abad0..98df7ce66 100644 --- a/src/mapchunk.h +++ b/src/mapchunk.h @@ -20,6 +20,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef MAPCHUNK_HEADER #define MAPCHUNK_HEADER +/* + TODO: Remove +*/ + +#if 0 /* MapChunk contains map-generation-time metadata for an area of some MapSectors. (something like 16x16) @@ -66,6 +71,7 @@ private: u8 m_generation_level; bool m_modified; }; +#endif #endif diff --git a/src/server.cpp b/src/server.cpp index cf8b57773..671c3bd4e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_mapnode.h" #include "content_craft.h" #include "content_nodemeta.h" +#include "mapblock.h" #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) -- cgit v1.2.3 From c1ceabef717d4461cab8832fe75068c7c14cb9b5 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 26 Jun 2011 03:14:52 +0300 Subject: added and commented out some debug output --- src/client.cpp | 104 ++++++++++++++++++++++++------------------------ src/defaultsettings.cpp | 2 + src/game.cpp | 15 +++++++ src/server.cpp | 64 ++++++++++++++++++----------- 4 files changed, 111 insertions(+), 74 deletions(-) (limited to 'src/client.cpp') diff --git a/src/client.cpp b/src/client.cpp index 6d0e6860c..248cd8a4c 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -135,6 +135,15 @@ void * MeshUpdateThread::Thread() while(getRun()) { + /*// Wait for output queue to flush. + // Allow 2 in queue, this makes less frametime jitter. + // Umm actually, there is no much difference + if(m_queue_out.size() >= 2) + { + sleep_ms(3); + continue; + }*/ + QueuedMeshUpdate *q = m_queue_in.pop(); if(q == NULL) { @@ -794,56 +803,43 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) MapSector *sector; MapBlock *block; - { //envlock - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - - v2s16 p2d(p.X, p.Z); - sector = m_env.getMap().emergeSector(p2d); - - v2s16 sp = sector->getPos(); - if(sp != p2d) - { - dstream<<"ERROR: Got sector with getPos()=" - <<"("<getPos() == p2d); + v2s16 p2d(p.X, p.Z); + sector = m_env.getMap().emergeSector(p2d); + + assert(sector->getPos() == p2d); - //TimeTaker timer("MapBlock deSerialize"); - // 0ms - - block = sector->getBlockNoCreateNoEx(p.Y); - if(block) - { - /* - Update an existing block - */ - //dstream<<"Updating"<deSerialize(istr, ser_version); - } - else - { - /* - Create a new block - */ - //dstream<<"Creating new"<deSerialize(istr, ser_version); - sector->insertBlock(block); - - //DEBUG - /*NodeMod mod; - mod.type = NODEMOD_CHANGECONTENT; - mod.param = CONTENT_MESE; - block->setTempMod(v3s16(8,10,8), mod); - block->setTempMod(v3s16(8,9,8), mod); - block->setTempMod(v3s16(8,8,8), mod); - block->setTempMod(v3s16(8,7,8), mod); - block->setTempMod(v3s16(8,6,8), mod);*/ - } - } //envlock + //TimeTaker timer("MapBlock deSerialize"); + // 0ms + + block = sector->getBlockNoCreateNoEx(p.Y); + if(block) + { + /* + Update an existing block + */ + //dstream<<"Updating"<deSerialize(istr, ser_version); + } + else + { + /* + Create a new block + */ + //dstream<<"Creating new"<deSerialize(istr, ser_version); + sector->insertBlock(block); + + //DEBUG + /*NodeMod mod; + mod.type = NODEMOD_CHANGECONTENT; + mod.param = CONTENT_MESE; + block->setTempMod(v3s16(8,10,8), mod); + block->setTempMod(v3s16(8,9,8), mod); + block->setTempMod(v3s16(8,8,8), mod); + block->setTempMod(v3s16(8,7,8), mod); + block->setTempMod(v3s16(8,6,8), mod);*/ + } #if 0 /* @@ -876,6 +872,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) /* Add it to mesh update queue and set it to be acknowledged after update. */ + //std::cerr<<"Adding mesh update task for received block"<fill(getDayNightRatio(), b); } @@ -2153,6 +2151,10 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server) } #endif + /* + Mark mesh as non-expired at this point so that it can already + be marked as expired again if the data changes + */ b->setMeshExpired(false); } diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 74d323237..84fac75ec 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -42,6 +42,7 @@ void set_default_settings() g_settings.setDefault("keymap_rangeselect", "KEY_KEY_R"); g_settings.setDefault("keymap_freemove", "KEY_KEY_K"); g_settings.setDefault("keymap_fastmove", "KEY_KEY_J"); + g_settings.setDefault("keymap_frametime_graph", "KEY_F1"); // Some (temporary) keys for debugging g_settings.setDefault("keymap_special1", "KEY_KEY_E"); g_settings.setDefault("keymap_print_debug_stacks", "KEY_KEY_P"); @@ -83,6 +84,7 @@ void set_default_settings() g_settings.setDefault("objectdata_interval", "0.2"); g_settings.setDefault("active_object_range", "2"); //g_settings.setDefault("max_simultaneous_block_sends_per_client", "1"); + // This causes frametime jitter on client side, or does it? g_settings.setDefault("max_simultaneous_block_sends_per_client", "2"); g_settings.setDefault("max_simultaneous_block_sends_server_total", "8"); g_settings.setDefault("max_block_send_distance", "8"); diff --git a/src/game.cpp b/src/game.cpp index 337879cb8..aa1cf4a70 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -940,6 +940,8 @@ void the_game( while(device->run() && kill == false) { + //std::cerr<<"frame"<disconnect_requested) { g_gamecallback->disconnect_requested = false; @@ -1221,6 +1223,19 @@ void the_game( chat_lines.push_back(ChatLine(L"fast_move enabled")); } } + else if(input->wasKeyDown(getKeySetting("keymap_frametime_graph"))) + { + if(g_settings.getBool("frametime_graph")) + { + g_settings.set("frametime_graph","false"); + chat_lines.push_back(ChatLine(L"frametime_graph disabled")); + } + else + { + g_settings.set("frametime_graph","true"); + chat_lines.push_back(ChatLine(L"frametime_graph enabled")); + } + } // Item selection with mouse wheel { diff --git a/src/server.cpp b/src/server.cpp index 671c3bd4e..16346b870 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1657,7 +1657,13 @@ void Server::AsyncRunStep() */ { // Don't send too many at a time - u32 count = 0; + //u32 count = 0; + + // Single change sending is disabled if queue size is not small + bool disable_single_change_sending = false; + if(m_unsent_map_edit_queue.size() >= 4) + disable_single_change_sending = true; + while(m_unsent_map_edit_queue.size() != 0) { MapEditEvent* event = m_unsent_map_edit_queue.pop_front(); @@ -1670,14 +1676,22 @@ void Server::AsyncRunStep() if(event->type == MEET_ADDNODE) { dstream<<"Server: MEET_ADDNODE"<p, event->n, event->already_known_by_peer, - &far_players, 30); + if(disable_single_change_sending) + sendAddNode(event->p, event->n, event->already_known_by_peer, + &far_players, 5); + else + sendAddNode(event->p, event->n, event->already_known_by_peer, + &far_players, 30); } else if(event->type == MEET_REMOVENODE) { dstream<<"Server: MEET_REMOVENODE"<p, event->already_known_by_peer, - &far_players, 30); + if(disable_single_change_sending) + sendRemoveNode(event->p, event->already_known_by_peer, + &far_players, 5); + else + sendRemoveNode(event->p, event->already_known_by_peer, + &far_players, 30); } else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED) { @@ -1698,31 +1712,35 @@ void Server::AsyncRunStep() /* Set blocks not sent to far players */ - core::map modified_blocks2; - for(core::map::Iterator - i = event->modified_blocks.getIterator(); - i.atEnd()==false; i++) + if(far_players.size() > 0) { - v3s16 p = i.getNode()->getKey(); - modified_blocks2.insert(p, m_env.getMap().getBlockNoCreateNoEx(p)); - } - for(core::list::Iterator - i = far_players.begin(); - i != far_players.end(); i++) - { - u16 peer_id = *i; - RemoteClient *client = getClient(peer_id); - if(client==NULL) - continue; - client->SetBlocksNotSent(modified_blocks2); + core::map modified_blocks2; + for(core::map::Iterator + i = event->modified_blocks.getIterator(); + i.atEnd()==false; i++) + { + v3s16 p = i.getNode()->getKey(); + modified_blocks2.insert(p, + m_env.getMap().getBlockNoCreateNoEx(p)); + } + for(core::list::Iterator + i = far_players.begin(); + i != far_players.end(); i++) + { + u16 peer_id = *i; + RemoteClient *client = getClient(peer_id); + if(client==NULL) + continue; + client->SetBlocksNotSent(modified_blocks2); + } } delete event; - // Don't send too many at a time + /*// Don't send too many at a time count++; if(count >= 1 && m_unsent_map_edit_queue.size() < 100) - break; + break;*/ } } -- cgit v1.2.3 From 3fccc67eb7c530c280e9b496e22288ffa772152d Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 26 Jun 2011 21:53:11 +0300 Subject: fixed block unloading from memory (a better fix coming next) --- src/client.cpp | 10 +++--- src/defaultsettings.cpp | 1 + src/environment.cpp | 3 ++ src/map.cpp | 95 ++++++++++++++++++++----------------------------- src/map.h | 15 +++++--- src/mapblock.cpp | 2 +- src/mapgen.cpp | 2 +- src/server.cpp | 16 +++++---- 8 files changed, 70 insertions(+), 74 deletions(-) (limited to 'src/client.cpp') diff --git a/src/client.cpp b/src/client.cpp index 248cd8a4c..449b0c2f2 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -333,16 +333,16 @@ void Client::step(float dtime) true, &deleted_blocks);*/ // Delete whole sectors - u32 num = m_env.getMap().unloadUnusedData + m_env.getMap().unloadUnusedData (delete_unused_sectors_timeout, - false, &deleted_blocks); + &deleted_blocks); - if(num > 0) + if(deleted_blocks.size() > 0) { /*dstream<getBlockNoCreateNoEx(p); if(block==NULL) continue; + + // Reset block usage timer + block->resetUsageTimer(); // Set current time as timestamp block->setTimestampNoChangedFlag(m_game_time); diff --git a/src/map.cpp b/src/map.cpp index 5bf278667..2cf7bb2e5 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1388,8 +1388,6 @@ bool Map::dayNightDiffed(v3s16 blockpos) */ void Map::timerUpdate(float dtime) { - //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out - core::map::Iterator si; si = m_sectors.getIterator(); @@ -1407,38 +1405,27 @@ void Map::timerUpdate(float dtime) } } -void Map::deleteSectors(core::list &list, bool only_blocks) +void Map::deleteSectors(core::list &list) { core::list::Iterator j; for(j=list.begin(); j!=list.end(); j++) { MapSector *sector = m_sectors[*j]; - if(only_blocks) - { - sector->deleteBlocks(); - } - else - { - /* - If sector is in sector cache, remove it from there - */ - if(m_sector_cache == sector) - { - m_sector_cache = NULL; - } - /* - Remove from map and delete - */ - m_sectors.remove(*j); - delete sector; - } + // If sector is in sector cache, remove it from there + if(m_sector_cache == sector) + m_sector_cache = NULL; + // Remove from map and delete + m_sectors.remove(*j); + delete sector; } } -u32 Map::unloadUnusedData(float timeout, bool only_blocks, +void Map::unloadUnusedData(float timeout, core::list *deleted_blocks) { core::list sector_deletion_queue; + u32 deleted_blocks_count = 0; + u32 saved_blocks_count = 0; core::map::Iterator si = m_sectors.getIterator(); for(; si.atEnd() == false; si++) @@ -1453,14 +1440,18 @@ u32 Map::unloadUnusedData(float timeout, bool only_blocks, i != blocks.end(); i++) { MapBlock *block = (*i); - + if(block->getUsageTimer() > timeout) { // Save if modified if(block->getModified() != MOD_STATE_CLEAN) + { saveBlock(block); + saved_blocks_count++; + } // Delete from memory sector->deleteBlock(block); + deleted_blocks_count++; } else { @@ -1474,36 +1465,14 @@ u32 Map::unloadUnusedData(float timeout, bool only_blocks, } } -#if 0 - core::map::Iterator i = m_sectors.getIterator(); - for(; i.atEnd() == false; i++) - { - MapSector *sector = i.getNode()->getValue(); - /* - Delete sector from memory if it hasn't been used in a long time - */ - if(sector->usage_timer > timeout) - { - sector_deletion_queue.push_back(i.getNode()->getKey()); + deleteSectors(sector_deletion_queue); - if(deleted_blocks != NULL) - { - // Collect positions of blocks of sector - MapSector *sector = i.getNode()->getValue(); - core::list blocks; - sector->getBlocks(blocks); - for(core::list::Iterator i = blocks.begin(); - i != blocks.end(); i++) - { - deleted_blocks->push_back((*i)->getPos()); - } - } - } - } -#endif + dstream<<"Map: Unloaded "<vmanip.print(dstream);*/ @@ -2095,10 +2066,11 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, //TimeTaker timer("finishBlockMake() blitBackAll"); data->vmanip->blitBackAll(&changed_blocks); } -#if 1 - dstream<<"finishBlockMake: changed_blocks.size()=" - < &list, bool only_blocks); + // If deleted sector is in sector cache, clears cache + void deleteSectors(core::list &list); - // Returns count of deleted sectors - u32 unloadUnusedData(float timeout, bool only_blocks=false, + /* + Unload unused data + = flush changed to disk and delete from memory, if usage timer of + block is more than timeout + */ + void unloadUnusedData(float timeout, core::list *deleted_blocks=NULL); // For debug printing diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 7036cd035..c125e67c8 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -38,7 +38,7 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, bool dummy): m_generated(false), m_objects(this), m_timestamp(BLOCK_TIMESTAMP_UNDEFINED), - m_usage_timer(BLOCK_TIMESTAMP_UNDEFINED) + m_usage_timer(0) { data = NULL; if(dummy == false) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index e481ee30c..4a2a39aec 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1389,7 +1389,7 @@ void make_block(BlockMakeData *data) /* Create a block-specific seed */ - u32 blockseed = (data->seed%0x100000000) + full_node_min.Z*38134234 + u32 blockseed = (u32)(data->seed%0x100000000) + full_node_min.Z*38134234 + full_node_min.Y*42123 + full_node_min.X*23; /* diff --git a/src/server.cpp b/src/server.cpp index 2ee94f345..b65f0bdb5 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1831,17 +1831,21 @@ void Server::AsyncRunStep() JMutexAutoLock lock(m_env_mutex); if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true) { + // Unload unused data (delete from memory) + m_env.getMap().unloadUnusedData( + g_settings.getFloat("server_unload_unused_sectors_timeout")); + /*u32 deleted_count = m_env.getMap().unloadUnusedData( + g_settings.getFloat("server_unload_unused_sectors_timeout")); + */ + // Save only changed parts m_env.getMap().save(true); - // Delete unused sectors - u32 deleted_count = m_env.getMap().unloadUnusedData( - g_settings.getFloat("server_unload_unused_sectors_timeout")); - if(deleted_count > 0) + /*if(deleted_count > 0) { dout_server<<"Server: Unloaded "< Date: Mon, 27 Jun 2011 00:27:17 +0300 Subject: map unloading is now a whole lot better --- minetest.conf.example | 8 +++- src/client.cpp | 96 ++++++++++++++++++++++++++++++------- src/client.h | 3 +- src/clientserver.h | 2 +- src/defaultsettings.cpp | 4 +- src/environment.cpp | 15 +----- src/main.cpp | 124 +++++++++++++++++------------------------------- src/map.cpp | 99 +++++++++++++++++++++++++++----------- src/map.h | 15 ++++-- src/server.cpp | 115 ++++++++++++++++++++++---------------------- src/server.h | 1 + 11 files changed, 272 insertions(+), 210 deletions(-) (limited to 'src/client.cpp') diff --git a/minetest.conf.example b/minetest.conf.example index 6e8a82bac..f94c8dee5 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -9,6 +9,10 @@ # # Further documentation: # http://celeron.55.lt/~celeron55/minetest/wiki/doku.php +# +# NOTE: This file might not be up-to-date, refer to the +# defaultsettings.cpp file for an up-to-date list: +# https://bitbucket.org/celeron55/minetest/src/tip/src/defaultsettings.cpp # # Client side stuff @@ -92,7 +96,7 @@ #random_input = false # Timeout for client to remove unused map data from memory -#client_delete_unused_sectors_timeout = 1200 +#client_unload_unused_data_timeout = 1200 # # Server side stuff @@ -140,6 +144,6 @@ #time_speed = 1440 #time_send_interval = 5 -#server_unload_unused_sectors_timeout = 60 +#server_unload_unused_data_timeout = 60 #server_map_save_interval = 60 diff --git a/src/client.cpp b/src/client.cpp index 449b0c2f2..585fce11c 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -199,7 +199,7 @@ Client::Client( m_access_denied(false) { m_packetcounter_timer = 0.0; - m_delete_unused_sectors_timer = 0.0; + //m_delete_unused_sectors_timer = 0.0; m_connection_reinit_timer = 0.0; m_avg_rtt_timer = 0.0; m_playerpos_send_timer = 0.0; @@ -303,7 +303,11 @@ void Client::step(float dtime) m_packetcounter.clear(); } } + + // Get connection status + bool connected = connectedAndInitialized(); +#if 0 { /* Delete unused sectors @@ -324,8 +328,7 @@ void Client::step(float dtime) core::list deleted_blocks; - float delete_unused_sectors_timeout = - g_settings.getFloat("client_delete_unused_sectors_timeout"); + g_settings.getFloat("client_unload_unused_data_timeout"); // Delete sector blocks /*u32 num = m_env.getMap().unloadUnusedData @@ -392,8 +395,7 @@ void Client::step(float dtime) } } } - - bool connected = connectedAndInitialized(); +#endif if(connected == false) { @@ -438,6 +440,67 @@ void Client::step(float dtime) Do stuff if connected */ + /* + Run Map's timers and unload unused data + */ + const float map_timer_and_unload_dtime = 5.25; + if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) + { + ScopeProfiler sp(&g_profiler, "Client: map timer and unload"); + core::list deleted_blocks; + m_env.getMap().timerUpdate(map_timer_and_unload_dtime, + g_settings.getFloat("client_unload_unused_data_timeout"), + &deleted_blocks); + + /*if(deleted_blocks.size() > 0) + dstream<<"Client: Unloaded "<::Iterator i = deleted_blocks.begin(); + core::list sendlist; + for(;;) + { + if(sendlist.size() == 255 || i == deleted_blocks.end()) + { + if(sendlist.size() == 0) + break; + /* + [0] u16 command + [2] u8 count + [3] v3s16 pos_0 + [3+6] v3s16 pos_1 + ... + */ + u32 replysize = 2+1+6*sendlist.size(); + SharedBuffer reply(replysize); + writeU16(&reply[0], TOSERVER_DELETEDBLOCKS); + reply[2] = sendlist.size(); + u32 k = 0; + for(core::list::Iterator + j = sendlist.begin(); + j != sendlist.end(); j++) + { + writeV3S16(&reply[2+1+6*k], *j); + k++; + } + m_con.Send(PEER_ID_SERVER, 1, reply, true); + + if(i == deleted_blocks.end()) + break; + + sendlist.clear(); + } + + sendlist.push_back(*i); + i++; + } + } + /* Handle environment */ @@ -453,23 +516,23 @@ void Client::step(float dtime) //TimeTaker envtimer("env step", m_device); // Step environment m_env.step(dtime); - - // Step active blocks + + /* + Handle active blocks + NOTE: These old objects are DEPRECATED. TODO: Remove + */ for(core::map::Iterator i = m_active_blocks.getIterator(); i.atEnd() == false; i++) { v3s16 p = i.getNode()->getKey(); - MapBlock *block = NULL; - try - { - block = m_env.getMap().getBlockNoCreate(p); - block->stepObjects(dtime, false, m_env.getDayNightRatio()); - } - catch(InvalidPositionException &e) - { - } + MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(p); + if(block == NULL) + continue; + + // Step MapBlockObjects + block->stepObjects(dtime, false, m_env.getDayNightRatio()); } /* @@ -1183,6 +1246,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) /* Read block objects + NOTE: Deprecated stuff here, TODO: Remove */ // Read active block count diff --git a/src/client.h b/src/client.h index 442eaef5d..bd838fee0 100644 --- a/src/client.h +++ b/src/client.h @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "jmutex.h" #include #include "clientobject.h" +#include "utility.h" // For IntervalLimiter struct MeshMakeData; @@ -306,11 +307,11 @@ private: void sendPlayerInfo(); float m_packetcounter_timer; - float m_delete_unused_sectors_timer; float m_connection_reinit_timer; float m_avg_rtt_timer; float m_playerpos_send_timer; float m_ignore_damage_timer; // Used after server moves player + IntervalLimiter m_map_timer_and_unload_interval; MeshUpdateThread m_mesh_update_thread; diff --git a/src/clientserver.h b/src/clientserver.h index 7972762c0..35484fe76 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -37,7 +37,7 @@ enum ToClientCommand [0] u16 TOSERVER_INIT [2] u8 deployed version [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd - ([4] u64 map seed (new as of 2011-02-27)) + [12] u64 map seed (new as of 2011-02-27) NOTE: The position in here is deprecated; position is explicitly sent afterwards diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 99bead6b0..0213ede1f 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -56,7 +56,7 @@ void set_default_settings() g_settings.setDefault("screenH", "600"); g_settings.setDefault("address", ""); g_settings.setDefault("random_input", "false"); - g_settings.setDefault("client_delete_unused_sectors_timeout", "1200"); + g_settings.setDefault("client_unload_unused_data_timeout", "1200"); g_settings.setDefault("enable_fog", "true"); g_settings.setDefault("new_style_water", "false"); g_settings.setDefault("new_style_leaves", "true"); @@ -94,7 +94,7 @@ void set_default_settings() g_settings.setDefault("max_block_generate_distance", "8"); g_settings.setDefault("time_send_interval", "20"); g_settings.setDefault("time_speed", "96"); - g_settings.setDefault("server_unload_unused_sectors_timeout", "60"); + g_settings.setDefault("server_unload_unused_data_timeout", "60"); g_settings.setDefault("server_map_save_interval", "60"); g_settings.setDefault("full_block_send_enable_min_time_from_building", "2.0"); //g_settings.setDefault("dungeon_rarity", "0.025"); diff --git a/src/environment.cpp b/src/environment.cpp index b52a46dde..ac69c8ae2 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -660,14 +660,6 @@ void ServerEnvironment::step(float dtime) m_game_time_fraction_counter -= (float)inc_i; } - /* - Let map update it's timers - */ - { - //TimeTaker timer("Server m_map->timerUpdate()"); - m_map->timerUpdate(dtime); - } - /* Handle players */ @@ -1469,11 +1461,6 @@ void ClientEnvironment::step(float dtime) bool free_move = g_settings.getBool("free_move"); bool footprints = g_settings.getBool("footprints"); - { - //TimeTaker timer("Client m_map->timerUpdate()"); - m_map->timerUpdate(dtime); - } - // Get local player LocalPlayer *lplayer = getLocalPlayer(); assert(lplayer); @@ -1672,7 +1659,7 @@ void ClientEnvironment::step(float dtime) // Step object obj->step(dtime, this); - if(m_active_object_light_update_interval.step(dtime, 0.5)) + if(m_active_object_light_update_interval.step(dtime, 0.21)) { // Update lighting //u8 light = LIGHT_MAX; diff --git a/src/main.cpp b/src/main.cpp index 9fb17e211..65d6006e3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,33 @@ NOTE: Global locale is now set at initialization NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the hardware buffer (it is not freed automatically) +NOTE: A random to-do list saved here as documentation: +A list of "active blocks" in which stuff happens. (+=done) + + Add a never-resetted game timer to the server + + Add a timestamp value to blocks + + The simple rule: All blocks near some player are "active" + - Do stuff in real time in active blocks + + Handle objects + - Grow grass, delete leaves without a tree + - Spawn some mobs based on some rules + - Transform cobble to mossy cobble near water + - Run a custom script + - ...And all kinds of other dynamic stuff + + Keep track of when a block becomes active and becomes inactive + + When a block goes inactive: + + Store objects statically to block + + Store timer value as the timestamp + + When a block goes active: + + Create active objects out of static objects + - Simulate the results of what would have happened if it would have + been active for all the time + - Grow a lot of grass and so on + + Initially it is fine to send information about every active object + to every player. Eventually it should be modified to only send info + about the nearest ones. + + This was left to be done by the old system and it sends only the + nearest ones. + Old, wild and random suggestions that probably won't be done: ------------------------------------------------------------- @@ -73,9 +100,6 @@ SUGG: Make the amount of blocks sending to client and the total SUGG: Meshes of blocks could be split into 6 meshes facing into different directions and then only those drawn that need to be -SUGG: Calculate lighting per vertex to get a lighting effect like in - bartwe's game - SUGG: Background music based on cellular automata? http://www.earslap.com/projectslab/otomata @@ -90,6 +114,8 @@ SUGG: Make a system for pregenerating quick information for mapblocks, so or even generated. SUGG: Erosion simulation at map generation time + - This might be plausible if larger areas of map were pregenerated + without lighting (which is slow) - Simulate water flows, which would carve out dirt fast and then turn stone into gravel and sand and relocate it. - How about relocating minerals, too? Coal and gold in @@ -231,6 +257,7 @@ FIXME: Server sometimes goes into some infinite PeerNotFoundException loop * Fix the problem with the server constantly saving one or a few blocks? List the first saved block, maybe it explains. - It is probably caused by oscillating water + - TODO: Investigate if this still happens (this is a very old one) * Make a small history check to transformLiquids to detect and log continuous oscillations, in such detail that they can be fixed. @@ -238,42 +265,12 @@ FIXME: The new optimized map sending doesn't sometimes send enough blocks from big caves and such FIXME: Block send distance configuration does not take effect for some reason -SUGG: Map unloading based on sector reference is not very good, it keeps - unnecessary stuff in memory. I guess. Investigate this. - -TODO: When block is placed and it has param_type==CPT_FACEDIR_SIMPLE, set - the direction accordingly. - Environment: ------------ -TODO: A list of "active blocks" in which stuff happens. (+=done) - + Add a never-resetted game timer to the server - + Add a timestamp value to blocks - + The simple rule: All blocks near some player are "active" - - Do stuff in real time in active blocks - + Handle objects - TODO: Make proper hooks in here - - Grow grass, delete leaves without a tree - - Spawn some mobs based on some rules - - Transform cobble to mossy cobble near water - - Run a custom script - - ...And all kinds of other dynamic stuff - + Keep track of when a block becomes active and becomes inactive - + When a block goes inactive: - + Store objects statically to block - + Store timer value as the timestamp - + When a block goes active: - + Create active objects out of static objects - TODO: Make proper hooks in here - - Simulate the results of what would have happened if it would have - been active for all the time - - Grow a lot of grass and so on - + Initially it is fine to send information about every active object - to every player. Eventually it should be modified to only send info - about the nearest ones. - + This was left to be done by the old system and it sends only the - nearest ones. +TODO: Add proper hooks to when adding and removing active blocks + +TODO: Finish the ActiveBlockModifier stuff and use it for something Objects: -------- @@ -285,6 +282,7 @@ TODO: Get rid of MapBlockObjects and use only ActiveObjects SUGG: MovingObject::move and Player::move are basically the same. combine them. + - NOTE: This is a bit tricky because player has the sneaking ability - NOTE: Player::move is more up-to-date. - NOTE: There is a simple move implementation now in collision.{h,cpp} - NOTE: MovingObject will be deleted (MapBlockObject) @@ -303,42 +301,17 @@ TODO: Mineral and ground material properties TODO: Flowing water to actually contain flow direction information - There is a space for this - it just has to be implemented. -SUGG: Try out the notch way of generating maps, that is, make bunches - of low-res 3d noise and interpolate linearly. - -Mapgen v2 (the current one): -* Possibly add some kind of erosion and other stuff -* Better water generation (spread it to underwater caverns but don't - fill dungeons that don't touch big water masses) -* When generating a chunk and the neighboring chunk doesn't have mud - and stuff yet and the ground is fairly flat, the mud will flow to - the other chunk making nasty straight walls when the other chunk - is generated. Fix it. Maybe just a special case if the ground is - flat? -* Consider not updating this one and make a good mainly block-based - generator - -SUGG: Make two "modified states", one that forces the block to be saved at - the next save event, and one that makes the block to be saved at exit - time. - -TODO: Add a not_fully_generated flag to MapBlock, which would be set for - blocks that contain eg. trees from neighboring generations but haven't - been generated itself. This is required for the future generator. - Misc. stuff: ------------ -- Make sure server handles removing grass when a block is placed (etc) - - The client should not do it by itself -- Block cube placement around player's head -- Protocol version field -- Consider getting some textures from cisoun's texture pack - - Ask from Cisoun -- Make sure the fence implementation and data format is good - - Think about using same bits for material for fences and doors, for - example -- Finish the ActiveBlockModifier stuff and use it for something -- Move mineral to param2, increment map serialization version, add conversion +TODO: Make sure server handles removing grass when a block is placed (etc) + - The client should not do it by itself + - NOTE: I think nobody does it currently... +TODO: Block cube placement around player's head +TODO: Protocol version field +TODO: Think about using same bits for material for fences and doors, for + example +TODO: Move mineral to param2, increment map serialization version, add + conversion TODO: Add a per-sector database to store surface stuff as simple flags/values - Light? @@ -354,8 +327,6 @@ TODO: Restart irrlicht completely when coming back to main menu from game. TODO: Merge bahamada's audio stuff (clean patch available) -TODO: Merge spongie's chest/furnace direction (by hand) - TODO: Merge key configuration menu (no clean patch available) Making it more portable: @@ -373,9 +344,6 @@ Stuff to do after release: Doing currently: ---------------- -TODO: Use MapBlock::resetUsageTimer() in appropriate places - (on client and server) - ====================================================================== */ @@ -404,16 +372,12 @@ TODO: Use MapBlock::resetUsageTimer() in appropriate places #include #include -//#include #include #include "main.h" #include "common_irrlicht.h" #include "debug.h" -//#include "map.h" -//#include "player.h" #include "test.h" #include "server.h" -//#include "client.h" #include "constants.h" #include "porting.h" #include "gettime.h" @@ -422,8 +386,6 @@ TODO: Use MapBlock::resetUsageTimer() in appropriate places #include "config.h" #include "guiMainMenu.h" #include "mineral.h" -//#include "noise.h" -//#include "tile.h" #include "materials.h" #include "game.h" #include "keycode.h" diff --git a/src/map.cpp b/src/map.cpp index 2cf7bb2e5..0f3741691 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1386,8 +1386,15 @@ bool Map::dayNightDiffed(v3s16 blockpos) /* Updates usage timers */ -void Map::timerUpdate(float dtime) +void Map::timerUpdate(float dtime, float unload_timeout, + core::list *unloaded_blocks) { + bool save_before_unloading = (mapType() == MAPTYPE_SERVER); + + core::list sector_deletion_queue; + u32 deleted_blocks_count = 0; + u32 saved_blocks_count = 0; + core::map::Iterator si; si = m_sectors.getIterator(); @@ -1395,13 +1402,60 @@ void Map::timerUpdate(float dtime) { MapSector *sector = si.getNode()->getValue(); + bool all_blocks_deleted = true; + core::list blocks; sector->getBlocks(blocks); for(core::list::Iterator i = blocks.begin(); i != blocks.end(); i++) { - (*i)->incrementUsageTimer(dtime); + MapBlock *block = (*i); + + block->incrementUsageTimer(dtime); + + if(block->getUsageTimer() > unload_timeout) + { + v3s16 p = block->getPos(); + + // Save if modified + if(block->getModified() != MOD_STATE_CLEAN + && save_before_unloading) + { + saveBlock(block); + saved_blocks_count++; + } + + // Delete from memory + sector->deleteBlock(block); + + if(unloaded_blocks) + unloaded_blocks->push_back(p); + + deleted_blocks_count++; + } + else + { + all_blocks_deleted = false; + } } + + if(all_blocks_deleted) + { + sector_deletion_queue.push_back(si.getNode()->getKey()); + } + } + + // Finally delete the empty sectors + deleteSectors(sector_deletion_queue); + + if(deleted_blocks_count != 0) + { + PrintInfo(dstream); // ServerMap/ClientMap: + dstream<<"Unloaded "< &list) } } +#if 0 void Map::unloadUnusedData(float timeout, core::list *deleted_blocks) { @@ -1474,6 +1529,7 @@ void Map::unloadUnusedData(float timeout, //return sector_deletion_queue.getSize(); //return deleted_blocks_count; } +#endif void Map::PrintInfo(std::ostream &out) { @@ -1500,7 +1556,7 @@ void Map::transformLiquids(core::map & modified_blocks) */ v3s16 p0 = m_transforming_liquid.pop_front(); - MapNode n0 = getNode(p0); + MapNode n0 = getNodeNoEx(p0); // Don't deal with non-liquids if(content_liquid(n0.d) == false) @@ -1532,13 +1588,10 @@ void Map::transformLiquids(core::map & modified_blocks) }; for(u16 i=0; i<5; i++) { - try - { - bool from_top = (i==0); v3s16 p2 = p0 + dirs_from[i]; - MapNode n2 = getNode(p2); + MapNode n2 = getNodeNoEx(p2); if(content_liquid(n2.d)) { @@ -1572,10 +1625,6 @@ void Map::transformLiquids(core::map & modified_blocks) if(new_liquid_level > new_liquid_level_max) new_liquid_level_max = new_liquid_level; } - - }catch(InvalidPositionException &e) - { - } } //for /* @@ -1618,20 +1667,13 @@ void Map::transformLiquids(core::map & modified_blocks) }; for(u16 i=0; i<6; i++) { - try - { - v3s16 p2 = p0 + dirs[i]; - MapNode n2 = getNode(p2); + MapNode n2 = getNodeNoEx(p2); if(content_flowing_liquid(n2.d)) { m_transforming_liquid.push_back(p2); } - - }catch(InvalidPositionException &e) - { - } } } } @@ -1652,9 +1694,6 @@ void Map::transformLiquids(core::map & modified_blocks) }; for(u16 i=0; i<5; i++) { - try - { - bool to_bottom = (i == 0); // If liquid is at lowest possible height, it's not going @@ -1680,7 +1719,7 @@ void Map::transformLiquids(core::map & modified_blocks) v3s16 p2 = p0 + dirs_to[i]; - MapNode n2 = getNode(p2); + MapNode n2 = getNodeNoEx(p2); //dstream<<"[1] n2.param="<<(int)n2.param< & modified_blocks) // If n2_changed to bottom, don't flow anywhere else if(to_bottom && flowed && !is_source) break; - - }catch(InvalidPositionException &e) - { - } } loopcount++; @@ -1945,7 +1980,6 @@ ServerMap::~ServerMap() { if(m_map_saving_enabled) { - //save(false); // Save only changed parts save(true); dstream<resetUsageTimer(); // This is ugly (spherical distance limit?) /*if(m_control.range_all == false && diff --git a/src/map.h b/src/map.h index 2fe749007..71101b8e4 100644 --- a/src/map.h +++ b/src/map.h @@ -223,19 +223,23 @@ public: virtual void save(bool only_changed){assert(0);}; - // Server implements this + // Server implements this. + // Client leaves it as no-op. virtual void saveBlock(MapBlock *block){}; /* - Updates usage timers + Updates usage timers and unloads unused blocks and sectors. + Saves modified blocks before unloading on MAPTYPE_SERVER. */ - void timerUpdate(float dtime); + void timerUpdate(float dtime, float unload_timeout, + core::list *unloaded_blocks=NULL); // Deletes sectors and their blocks from memory // Takes cache into account // If deleted sector is in sector cache, clears cache void deleteSectors(core::list &list); - + +#if 0 /* Unload unused data = flush changed to disk and delete from memory, if usage timer of @@ -243,8 +247,9 @@ public: */ void unloadUnusedData(float timeout, core::list *deleted_blocks=NULL); +#endif - // For debug printing + // For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: " virtual void PrintInfo(std::ostream &out); void transformLiquids(core::map & modified_blocks); diff --git a/src/server.cpp b/src/server.cpp index b65f0bdb5..798f36ac1 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -602,6 +602,9 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, bool block_is_invalid = false; if(block != NULL) { + // Reset usage timer, this block will be of use in the future. + block->resetUsageTimer(); + // Block is dummy if data doesn't exist. // It means it has been not found from disk and not generated if(block->isDummy()) @@ -1297,12 +1300,21 @@ void Server::AsyncRunStep() } { - // Step environment - // This also runs Map's timers JMutexAutoLock lock(m_env_mutex); + // Step environment ScopeProfiler sp(&g_profiler, "Server: environment step"); m_env.step(dtime); } + + const float map_timer_and_unload_dtime = 5.15; + if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) + { + JMutexAutoLock lock(m_env_mutex); + // Run Map's timers and unload unused data + ScopeProfiler sp(&g_profiler, "Server: map timer and unload"); + m_env.getMap().timerUpdate(map_timer_and_unload_dtime, + g_settings.getFloat("server_unload_unused_data_timeout")); + } /* Do background stuff @@ -1665,8 +1677,15 @@ void Server::AsyncRunStep() if(m_unsent_map_edit_queue.size() >= 4) disable_single_change_sending = true; + bool got_any_events = false; + + // We'll log the amount of each + Profiler prof; + while(m_unsent_map_edit_queue.size() != 0) { + got_any_events = true; + MapEditEvent* event = m_unsent_map_edit_queue.pop_front(); // Players far away from the change are stored here. @@ -1676,7 +1695,8 @@ void Server::AsyncRunStep() if(event->type == MEET_ADDNODE) { - dstream<<"Server: MEET_ADDNODE"<p, event->n, event->already_known_by_peer, &far_players, 5); @@ -1686,7 +1706,8 @@ void Server::AsyncRunStep() } else if(event->type == MEET_REMOVENODE) { - dstream<<"Server: MEET_REMOVENODE"<p, event->already_known_by_peer, &far_players, 5); @@ -1697,15 +1718,18 @@ void Server::AsyncRunStep() else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED) { dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<p); } else if(event->type == MEET_OTHER) { + prof.add("MEET_OTHER", 1); dstream<<"WARNING: Server: MEET_OTHER not implemented" <type)<= 1 && m_unsent_map_edit_queue.size() < 100) break;*/ } + + if(got_any_events) + { + dstream<<"Server: MapEditEvents:"< changed_blocks; - m_env.getMap().nodeMetadataStep(dtime, changed_blocks); - - // Use setBlockNotSent - - for(core::map::Iterator - i = changed_blocks.getIterator(); - i.atEnd() == false; i++) - { - MapBlock *block = i.getNode()->getValue(); - - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd()==false; i++) - { - RemoteClient *client = i.getNode()->getValue(); - client->SetBlockNotSent(block->getPos()); - } - } - }*/ - /* Trigger emergethread (it somehow gets to a non-triggered but bysy state sometimes) @@ -1829,30 +1827,29 @@ void Server::AsyncRunStep() // Map JMutexAutoLock lock(m_env_mutex); - if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true) - { - // Unload unused data (delete from memory) - m_env.getMap().unloadUnusedData( - g_settings.getFloat("server_unload_unused_sectors_timeout")); - /*u32 deleted_count = m_env.getMap().unloadUnusedData( - g_settings.getFloat("server_unload_unused_sectors_timeout")); - */ - // Save only changed parts - m_env.getMap().save(true); + /*// Unload unused data (delete from memory) + m_env.getMap().unloadUnusedData( + g_settings.getFloat("server_unload_unused_sectors_timeout")); + */ + /*u32 deleted_count = m_env.getMap().unloadUnusedData( + g_settings.getFloat("server_unload_unused_sectors_timeout")); + */ - /*if(deleted_count > 0) - { - dout_server<<"Server: Unloaded "< 0) + { + dout_server<<"Server: Unloaded "<clone(); diff --git a/src/server.h b/src/server.h index b88369ddf..1da004da5 100644 --- a/src/server.h +++ b/src/server.h @@ -534,6 +534,7 @@ private: float m_objectdata_timer; float m_emergethread_trigger_timer; float m_savemap_timer; + IntervalLimiter m_map_timer_and_unload_interval; // NOTE: If connection and environment are both to be locked, // environment shall be locked first. -- cgit v1.2.3