diff options
-rw-r--r-- | src/client.cpp | 468 | ||||
-rw-r--r-- | src/client.h | 169 | ||||
-rw-r--r-- | src/main.cpp | 16 | ||||
-rw-r--r-- | src/map.cpp | 27 | ||||
-rw-r--r-- | src/mapblock.cpp | 368 | ||||
-rw-r--r-- | src/mapblock.h | 39 | ||||
-rw-r--r-- | src/utility.h | 9 |
7 files changed, 714 insertions, 382 deletions
diff --git a/src/client.cpp b/src/client.cpp index 357cbe368..e381fbce3 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -26,24 +26,38 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <sstream> #include "porting.h" -void * ClientUpdateThread::Thread() +void * MeshUpdateThread::Thread() { ThreadStarted(); DSTACK(__FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER - + while(getRun()) { - //m_client->asyncStep(); + QueuedMeshUpdate *q = m_queue_in.pop(); + if(q == NULL) + { + sleep_ms(50); + continue; + } + + scene::SMesh *mesh_new = NULL; + mesh_new = makeMapBlockMesh(q->data); + + MeshUpdateResult r; + r.p = q->p; + r.mesh = mesh_new; + r.ack_block_to_server = q->ack_block_to_server; - //m_client->updateSomeExpiredMeshes(); + /*dstream<<"MeshUpdateThread: Processed " + <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")" + <<std::endl;*/ - bool was = m_client->AsyncProcessData(); + m_queue_out.push_back(r); - if(was == false) - sleep_ms(10); + delete q; } END_DEBUG_EXCEPTION_HANDLER @@ -55,7 +69,7 @@ Client::Client( IrrlichtDevice *device, const char *playername, MapDrawControl &control): - m_thread(this), + m_mesh_update_thread(), m_env( new ClientMap(this, control, device->getSceneManager()->getRootSceneNode(), @@ -67,7 +81,6 @@ Client::Client( camera_position(0,0,0), camera_direction(0,0,1), m_server_ser_ver(SER_FMT_VER_INVALID), - m_step_dtime(0.0), m_inventory_updated(false), m_time_of_day(0) { @@ -77,19 +90,16 @@ Client::Client( m_avg_rtt_timer = 0.0; m_playerpos_send_timer = 0.0; - //m_fetchblock_mutex.Init(); - m_incoming_queue_mutex.Init(); - m_env_mutex.Init(); - m_con_mutex.Init(); - m_step_dtime_mutex.Init(); + //m_env_mutex.Init(); + //m_con_mutex.Init(); - m_thread.Start(); + m_mesh_update_thread.Start(); /* Add local player */ { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out Player *player = new LocalPlayer(); @@ -102,26 +112,26 @@ Client::Client( Client::~Client() { { - JMutexAutoLock conlock(m_con_mutex); + //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out m_con.Disconnect(); } - m_thread.setRun(false); - while(m_thread.IsRunning()) + m_mesh_update_thread.setRun(false); + while(m_mesh_update_thread.IsRunning()) sleep_ms(100); } void Client::connect(Address address) { DSTACK(__FUNCTION_NAME); - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out m_con.setTimeoutMs(0); m_con.Connect(address); } bool Client::connectedAndInitialized() { - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out if(m_con.Connected() == false) return false; @@ -152,7 +162,7 @@ void Client::step(float dtime) { //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device); // 0ms - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out m_con.RunTimeouts(dtime); } @@ -188,7 +198,7 @@ void Client::step(float dtime) //counter = 180.0; counter = 60.0; - JMutexAutoLock lock(m_env_mutex); + //JMutexAutoLock lock(m_env_mutex); //bulk comment-out core::list<v3s16> deleted_blocks; @@ -217,7 +227,7 @@ void Client::step(float dtime) */ // Env is locked so con can be locked. - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out core::list<v3s16>::Iterator i = deleted_blocks.begin(); core::list<v3s16> sendlist; @@ -271,7 +281,7 @@ void Client::step(float dtime) { counter = 2.0; - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out Player *myplayer = m_env.getLocalPlayer(); assert(myplayer != NULL); @@ -299,7 +309,7 @@ void Client::step(float dtime) { // 0ms - JMutexAutoLock lock(m_env_mutex); + //JMutexAutoLock lock(m_env_mutex); //bulk comment-out // Control local player (0ms) LocalPlayer *player = m_env.getLocalPlayer(); @@ -335,7 +345,7 @@ void Client::step(float dtime) if(counter >= 10) { counter = 0.0; - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out // connectedAndInitialized() is true, peer exists. con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER); dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl; @@ -351,31 +361,50 @@ void Client::step(float dtime) } } - /*{ - JMutexAutoLock lock(m_step_dtime_mutex); - m_step_dtime += dtime; - }*/ -} - -#if 0 -float Client::asyncStep() -{ - DSTACK(__FUNCTION_NAME); - //dstream<<"Client::asyncStep()"<<std::endl; - - /*float dtime; + /* + Replace updated meshes + */ { - JMutexAutoLock lock1(m_step_dtime_mutex); - if(m_step_dtime < 0.001) - return 0.0; - dtime = m_step_dtime; - m_step_dtime = 0.0; - } + //JMutexAutoLock lock(m_env_mutex); //bulk comment-out - return dtime;*/ - return 0.0; + //TimeTaker timer("** Processing mesh update result queue"); + // 0ms + + /*dstream<<"Mesh update result queue size is " + <<m_mesh_update_thread.m_queue_out.size() + <<std::endl;*/ + + while(m_mesh_update_thread.m_queue_out.size() > 0) + { + MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front(); + MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p); + if(block) + { + block->replaceMesh(r.mesh); + } + if(r.ack_block_to_server) + { + /* + Acknowledge block + */ + /* + [0] u16 command + [2] u8 count + [3] v3s16 pos_0 + [3+6] v3s16 pos_1 + ... + */ + u32 replysize = 2+1+6; + SharedBuffer<u8> reply(replysize); + writeU16(&reply[0], TOSERVER_GOTBLOCKS); + reply[2] = 1; + writeV3S16(&reply[3], r.p); + // Send as reliable + m_con.Send(PEER_ID_SERVER, 1, reply, true); + } + } + } } -#endif // Virtual methods from con::PeerHandler void Client::peerAdded(con::Peer *peer) @@ -420,7 +449,7 @@ void Client::Receive() u32 datasize; { //TimeTaker t1("con mutex and receive", m_device); - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out datasize = m_con.Receive(sender_peer_id, *data, data_maxsize); } //TimeTaker t1("ProcessData", m_device); @@ -460,7 +489,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) con::Peer *peer; { - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out // All data is coming from the server // PeerNotFoundException is handled by caller. peer = m_con.GetPeer(PEER_ID_SERVER); @@ -499,7 +528,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0); { //envlock - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out // Set player position Player *player = m_env.getLocalPlayer(); @@ -569,13 +598,138 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) addNode(p, n); } + else if(command == TOCLIENT_BLOCKDATA) + { + // Ignore too small packet + if(datasize < 8) + return; + + v3s16 p; + p.X = readS16(&data[2]); + p.Y = readS16(&data[4]); + p.Z = readS16(&data[6]); + + /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for (" + <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/ + /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for (" + <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/ + + std::string datastring((char*)&data[8], datasize-8); + std::istringstream istr(datastring, std::ios_base::binary); + + 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()=" + <<"("<<sp.X<<","<<sp.Y<<"), tried to get" + <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl; + } + + assert(sp == p2d); + //assert(sector->getPos() == p2d); + + //TimeTaker timer("MapBlock deSerialize"); + // 0ms + + try{ + block = sector->getBlockNoCreate(p.Y); + /* + Update an existing block + */ + //dstream<<"Updating"<<std::endl; + block->deSerialize(istr, ser_version); + //block->setChangedFlag(); + } + catch(InvalidPositionException &e) + { + /* + Create a new block + */ + //dstream<<"Creating new"<<std::endl; + block = new MapBlock(&m_env.getMap(), p); + block->deSerialize(istr, ser_version); + sector->insertBlock(block); + //block->setChangedFlag(); + + //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 + /* + Add some coulds + Well, this is a dumb way to do it, they should just + be drawn as separate objects. But the looks of them + can be tested this way. + */ + if(p.Y == 3) + { + NodeMod mod; + mod.type = NODEMOD_CHANGECONTENT; + mod.param = CONTENT_CLOUD; + v3s16 p2; + p2.Y = 8; + for(p2.X=3; p2.X<=13; p2.X++) + for(p2.Z=3; p2.Z<=13; p2.Z++) + { + block->setTempMod(p2, mod); + } + } +#endif + } + } //envlock + +#if 0 + /* + Acknowledge block + */ + /* + [0] u16 command + [2] u8 count + [3] v3s16 pos_0 + [3+6] v3s16 pos_1 + ... + */ + u32 replysize = 2+1+6; + SharedBuffer<u8> reply(replysize); + writeU16(&reply[0], TOSERVER_GOTBLOCKS); + reply[2] = 1; + writeV3S16(&reply[3], p); + // Send as reliable + m_con.Send(PEER_ID_SERVER, 1, reply, true); +#endif + + /* + Update Mesh of this block and blocks at x-, y- and z-. + Environment should not be locked as it interlocks with the + main thread, from which is will want to retrieve textures. + */ + + //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio()); + + addUpdateMeshTaskWithEdge(p, true); + } else if(command == TOCLIENT_PLAYERPOS) { dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS" <<std::endl; /*u16 our_peer_id; { - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out our_peer_id = m_con.GetPeerID(); } // Cancel if we don't have a peer id @@ -587,7 +741,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) }*/ { //envlock - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out u32 player_size = 2+12+12+4+4; @@ -641,7 +795,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) { u16 our_peer_id; { - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out our_peer_id = m_con.GetPeerID(); } // Cancel if we don't have a peer id @@ -655,7 +809,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) //dstream<<DTIME<<"Client: Server reports players:"<<std::endl; { //envlock - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out u32 item_size = 2+PLAYERNAME_SIZE; u32 player_count = (datasize-2) / item_size; @@ -754,7 +908,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) //dstream<<"Client received TOCLIENT_SECTORMETA"<<std::endl; { //envlock - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); @@ -788,7 +942,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) { //envlock //TimeTaker t2("mutex locking", m_device); - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out //t2.stop(); //TimeTaker t3("istringstream init", m_device); @@ -823,7 +977,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) { //envlock - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out u8 buf[12]; @@ -981,7 +1135,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) u16 time = readU16(&data[2]); time = time % 24000; - m_time_of_day.set(time); + m_time_of_day = time; //dstream<<"Client: time="<<time<<std::endl; /* @@ -992,9 +1146,9 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) 12000 = midday */ { - u32 dr = time_to_daynight_ratio(m_time_of_day.get()); + u32 dr = time_to_daynight_ratio(m_time_of_day); - dstream<<"Client: time_of_day="<<m_time_of_day.get() + dstream<<"Client: time_of_day="<<m_time_of_day <<", dr="<<dr <<std::endl; @@ -1070,7 +1224,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) u16 id = readU16((u8*)buf); // Remove it { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out m_env.removeActiveObject(id); } } @@ -1087,7 +1241,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) std::string data = deSerializeLongString(is); // Add it { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out m_env.addActiveObject(id, type, data); } } @@ -1130,12 +1284,18 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) } // Pass on to the environment { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out m_env.processActiveObjectMessage(id, message); } } } } + else + { + dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command " + <<command<<std::endl; + } +#if 0 // Default to queueing it (for slow commands) else { @@ -1144,8 +1304,10 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) IncomingPacket packet(data, datasize); m_incoming_queue.push_back(packet); } +#endif } +#if 0 /* Returns true if there was something in queue */ @@ -1158,7 +1320,7 @@ bool Client::AsyncProcessPacket() con::Peer *peer; { - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out // All data is coming from the server peer = m_con.GetPeer(PEER_ID_SERVER); } @@ -1192,7 +1354,6 @@ bool Client::AsyncProcessPacket() /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for (" <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/ - /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for (" <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/ @@ -1203,7 +1364,7 @@ bool Client::AsyncProcessPacket() MapBlock *block; { //envlock - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out v2s16 p2d(p.X, p.Z); sector = m_env.getMap().emergeSector(p2d); @@ -1218,6 +1379,9 @@ bool Client::AsyncProcessPacket() assert(sp == p2d); //assert(sector->getPos() == p2d); + + //TimeTaker timer("MapBlock deSerialize"); + // 0ms try{ block = sector->getBlockNoCreate(p.Y); @@ -1248,13 +1412,14 @@ bool Client::AsyncProcessPacket() block->setTempMod(v3s16(8,8,8), mod); block->setTempMod(v3s16(8,7,8), mod); block->setTempMod(v3s16(8,6,8), mod);*/ - +#if 0 /* Add some coulds Well, this is a dumb way to do it, they should just - be drawn as separate objects. + be drawn as separate objects. But the looks of them + can be tested this way. */ - /*if(p.Y == 3) + if(p.Y == 3) { NodeMod mod; mod.type = NODEMOD_CHANGECONTENT; @@ -1266,7 +1431,8 @@ bool Client::AsyncProcessPacket() { block->setTempMod(p2, mod); } - }*/ + } +#endif } } //envlock @@ -1294,7 +1460,20 @@ bool Client::AsyncProcessPacket() main thread, from which is will want to retrieve textures. */ - m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio()); + //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio()); + + MeshMakeData data; + { + //TimeTaker timer("data fill"); + // 0ms + data.fill(getDayNightRatio(), block); + } + { + TimeTaker timer("make mesh"); + scene::SMesh *mesh_new = NULL; + mesh_new = makeMapBlockMesh(&data); + block->replaceMesh(mesh_new); + } } else { @@ -1323,13 +1502,15 @@ bool Client::AsyncProcessData() } return false; } +#endif void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable) { - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out m_con.Send(PEER_ID_SERVER, channelnum, data, reliable); } +#if 0 IncomingPacket Client::getPacket() { JMutexAutoLock lock(m_incoming_queue_mutex); @@ -1349,6 +1530,7 @@ IncomingPacket Client::getPacket() m_incoming_queue.erase(i); return packet; } +#endif void Client::groundAction(u8 action, v3s16 nodepos_undersurface, v3s16 nodepos_oversurface, u16 item) @@ -1496,7 +1678,7 @@ void Client::sendChatMessage(const std::wstring &message) void Client::sendPlayerPos() { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out Player *myplayer = m_env.getLocalPlayer(); if(myplayer == NULL) @@ -1504,7 +1686,7 @@ void Client::sendPlayerPos() u16 our_peer_id; { - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out our_peer_id = m_con.GetPeerID(); } @@ -1543,7 +1725,7 @@ void Client::sendPlayerPos() void Client::removeNode(v3s16 p) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out core::map<v3s16, MapBlock*> modified_blocks; @@ -1567,7 +1749,7 @@ void Client::removeNode(v3s16 p) void Client::addNode(v3s16 p, MapNode n) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out TimeTaker timer1("Client::addNode()"); @@ -1601,19 +1783,19 @@ void Client::updateCamera(v3f pos, v3f dir) MapNode Client::getNode(v3s16 p) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out return m_env.getMap().getNode(p); } NodeMetadata* Client::getNodeMetadataClone(v3s16 p) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out return m_env.getMap().getNodeMetadataClone(p); } v3f Client::getPlayerPosition() { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); return player->getPosition(); @@ -1621,7 +1803,7 @@ v3f Client::getPlayerPosition() void Client::setPlayerControl(PlayerControl &control) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); player->control = control; @@ -1632,7 +1814,7 @@ void Client::setPlayerControl(PlayerControl &control) bool Client::getLocalInventoryUpdated() { // m_inventory_updated is behind envlock - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out bool updated = m_inventory_updated; m_inventory_updated = false; return updated; @@ -1641,7 +1823,7 @@ bool Client::getLocalInventoryUpdated() // Copies the inventory of the local player to parameter void Client::getLocalInventory(Inventory &dst) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out Player *player = m_env.getLocalPlayer(); assert(player != NULL); dst = player->inventory; @@ -1653,7 +1835,7 @@ MapBlockObject * Client::getSelectedObject( core::line3d<f32> shootline_on_map ) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out core::array<DistanceSortedObject> objects; @@ -1715,12 +1897,12 @@ MapBlockObject * Client::getSelectedObject( void Client::printDebugInfo(std::ostream &os) { //JMutexAutoLock lock1(m_fetchblock_mutex); - JMutexAutoLock lock2(m_incoming_queue_mutex); + /*JMutexAutoLock lock2(m_incoming_queue_mutex); os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize() //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size() //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size() - <<std::endl; + <<std::endl;*/ } /*s32 Client::getDayNightIndex() @@ -1731,63 +1913,87 @@ void Client::printDebugInfo(std::ostream &os) u32 Client::getDayNightRatio() { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out return m_env.getDayNightRatio(); } -/*void Client::updateSomeExpiredMeshes() +void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server) { - TimeTaker timer("updateSomeExpiredMeshes()", g_device); + /*dstream<<"Client::addUpdateMeshTask(): " + <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")" + <<std::endl;*/ + + MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p); + if(b == NULL) + return; + + /* + Create a task to update the mesh of the block + */ + + MeshMakeData *data = new MeshMakeData; - Player *player; { - JMutexAutoLock envlock(m_env_mutex); - player = m_env.getLocalPlayer(); + //TimeTaker timer("data fill"); + // 0ms + data->fill(getDayNightRatio(), b); } - u32 daynight_ratio = getDayNightRatio(); - - v3f playerpos = player->getPosition(); - v3f playerspeed = player->getSpeed(); - - v3s16 center_nodepos = floatToInt(playerpos, BS); - v3s16 center = getNodeBlockPos(center_nodepos); - - u32 counter = 0; + // Debug wait + //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10); + + // Add task to queue + m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server); - s16 d_max = 5; + /*dstream<<"Mesh update input queue size is " + <<m_mesh_update_thread.m_queue_in.size() + <<std::endl;*/ - for(s16 d = 0; d <= d_max; d++) +#if 0 + // Temporary test: make mesh directly in here { - core::list<v3s16> list; - getFacePositions(list, d); - - core::list<v3s16>::Iterator li; - for(li=list.begin(); li!=list.end(); li++) - { - v3s16 p = *li + center; - MapBlock *block = NULL; - try - { - //JMutexAutoLock envlock(m_env_mutex); - block = m_env.getMap().getBlockNoCreate(p); - } - catch(InvalidPositionException &e) - { - } - - if(block == NULL) - continue; + //TimeTaker timer("make mesh"); + // 10ms + scene::SMesh *mesh_new = NULL; + mesh_new = makeMapBlockMesh(data); + b->replaceMesh(mesh_new); + delete data; + } +#endif - if(block->getMeshExpired() == false) - continue; + b->setMeshExpired(false); +} - block->updateMesh(daynight_ratio); +void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server) +{ + /*{ + v3s16 p = blockpos; + dstream<<"Client::addUpdateMeshTaskWithEdge(): " + <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")" + <<std::endl; + }*/ - counter++; - if(counter >= 5) - return; - } + try{ + v3s16 p = blockpos + v3s16(0,0,0); + //MapBlock *b = m_env.getMap().getBlockNoCreate(p); + addUpdateMeshTask(p, ack_to_server); } -}*/ + catch(InvalidPositionException &e){} + // Leading edge + try{ + v3s16 p = blockpos + v3s16(-1,0,0); + addUpdateMeshTask(p); + } + catch(InvalidPositionException &e){} + try{ + v3s16 p = blockpos + v3s16(0,-1,0); + addUpdateMeshTask(p); + } + catch(InvalidPositionException &e){} + try{ + v3s16 p = blockpos + v3s16(0,0,-1); + addUpdateMeshTask(p); + } + catch(InvalidPositionException &e){} +} diff --git a/src/client.h b/src/client.h index c6002a469..d46b51a0a 100644 --- a/src/client.h +++ b/src/client.h @@ -37,23 +37,144 @@ public: {} }; -class Client; +struct QueuedMeshUpdate +{ + v3s16 p; + MeshMakeData *data; + bool ack_block_to_server; + + QueuedMeshUpdate(): + p(-1337,-1337,-1337), + data(NULL), + ack_block_to_server(false) + { + } + + ~QueuedMeshUpdate() + { + if(data) + delete data; + } +}; + +/* + A thread-safe queue of mesh update tasks +*/ +class MeshUpdateQueue +{ +public: + MeshUpdateQueue() + { + m_mutex.Init(); + } + + ~MeshUpdateQueue() + { + JMutexAutoLock lock(m_mutex); + + core::list<QueuedMeshUpdate*>::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 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<QueuedMeshUpdate*>::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 * pop() + { + JMutexAutoLock lock(m_mutex); + + core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin(); + if(i == m_queue.end()) + return NULL; + QueuedMeshUpdate *q = *i; + m_queue.erase(i); + return q; + } + + u32 size() + { + JMutexAutoLock lock(m_mutex); + return m_queue.size(); + } + +private: + core::list<QueuedMeshUpdate*> m_queue; + JMutex m_mutex; +}; -class ClientUpdateThread : public SimpleThread +struct MeshUpdateResult { - Client *m_client; + v3s16 p; + scene::SMesh *mesh; + bool ack_block_to_server; + + MeshUpdateResult(): + p(-1338,-1338,-1338), + mesh(NULL), + ack_block_to_server(false) + { + } +}; +class MeshUpdateThread : public SimpleThread +{ public: - ClientUpdateThread(Client *client): - SimpleThread(), - m_client(client) + MeshUpdateThread() { } void * Thread(); + + MeshUpdateQueue m_queue_in; + + MutexedQueue<MeshUpdateResult> m_queue_out; }; +#if 0 struct IncomingPacket { IncomingPacket() @@ -101,13 +222,15 @@ struct IncomingPacket u32 m_datalen; s32 *m_refcount; }; +#endif class Client : public con::PeerHandler { public: /* - NOTE: Every public method should be thread-safe + NOTE: Nothing is thread-safe here. */ + Client( IrrlichtDevice *device, const char *playername, @@ -147,7 +270,7 @@ public: void Send(u16 channelnum, SharedBuffer<u8> data, bool reliable); // Pops out a packet from the packet queue - IncomingPacket getPacket(); + //IncomingPacket getPacket(); void groundAction(u8 action, v3s16 nodepos_undersurface, v3s16 nodepos_oversurface, u16 item); @@ -196,7 +319,7 @@ public: void setTempMod(v3s16 p, NodeMod mod) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); core::map<v3s16, MapBlock*> affected_blocks; @@ -212,7 +335,7 @@ public: } void clearTempMod(v3s16 p) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); core::map<v3s16, MapBlock*> affected_blocks; @@ -229,7 +352,7 @@ public: float getAvgRtt() { - JMutexAutoLock lock(m_con_mutex); + //JMutexAutoLock lock(m_con_mutex); //bulk comment-out con::Peer *peer = m_con.GetPeerNoEx(PEER_ID_SERVER); if(peer == NULL) return 0.0; @@ -246,7 +369,7 @@ public: void addChatMessage(const std::wstring &message) { - JMutexAutoLock envlock(m_env_mutex); + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); std::wstring name = narrow_to_wide(player->getName()); @@ -256,6 +379,13 @@ public: u64 getMapSeed(){ return m_map_seed; } + /* + These are not thread-safe + */ + void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false); + // Including blocks at appropriate edges + void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false); + private: // Virtual methods from con::PeerHandler @@ -275,19 +405,11 @@ private: float m_avg_rtt_timer; float m_playerpos_send_timer; - ClientUpdateThread m_thread; + MeshUpdateThread m_mesh_update_thread; - // NOTE: If connection and environment are both to be locked, - // environment shall be locked first. - ClientEnvironment m_env; - JMutex m_env_mutex; con::Connection m_con; - JMutex m_con_mutex; - - core::list<IncomingPacket> m_incoming_queue; - JMutex m_incoming_queue_mutex; IrrlichtDevice *m_device; @@ -297,9 +419,6 @@ private: // Server serialization version u8 m_server_ser_ver; - float m_step_dtime; - JMutex m_step_dtime_mutex; - // This is behind m_env_mutex. bool m_inventory_updated; @@ -308,7 +427,7 @@ private: PacketCounter m_packetcounter; // Received from the server. 0-23999 - MutexedVariable<u32> m_time_of_day; + u32 m_time_of_day; // 0 <= m_daynight_i < DAYNIGHT_CACHE_COUNT //s32 m_daynight_i; diff --git a/src/main.cpp b/src/main.cpp index a901163df..3ddac369d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -482,8 +482,8 @@ Inventory local_inventory; u16 g_selected_item = 0;
-bool g_show_map_plot = false;
-bool g_refresh_map_plot = false;
+/*bool g_show_map_plot = false;
+bool g_refresh_map_plot = false;*/
/*
Debug streams
@@ -601,7 +601,7 @@ public: if(event.KeyInput.PressedDown)
{
//dstream<<"Pressed key: "<<(char)event.KeyInput.Key<<std::endl;
- if(g_show_map_plot)
+ /*if(g_show_map_plot)
{
if(event.KeyInput.Key == irr::KEY_ESCAPE
|| event.KeyInput.Key == irr::KEY_KEY_M)
@@ -609,7 +609,7 @@ public: g_show_map_plot = false;
}
return true;
- }
+ }*/
/*
Launch menus
@@ -685,13 +685,13 @@ public: }
// Map plot
- if(event.KeyInput.Key == irr::KEY_KEY_M)
+ /*if(event.KeyInput.Key == irr::KEY_KEY_M)
{
dstream<<"Map plot requested"<<std::endl;
g_show_map_plot = !g_show_map_plot;
if(g_show_map_plot)
g_refresh_map_plot = true;
- }
+ }*/
}
}
@@ -2282,7 +2282,7 @@ int main(int argc, char *argv[]) //std::cout<<"busytime_u32="<<busytime_u32<<std::endl;
- // Absolutelu necessary for wine!
+ // Necessary for device->getTimer()->getTime()
device->run();
/*
@@ -2306,7 +2306,7 @@ int main(int argc, char *argv[]) }
}
- // Absolutelu necessary for wine!
+ // Necessary for device->getTimer()->getTime()
device->run();
/*
diff --git a/src/map.cpp b/src/map.cpp index 1608f3e05..39742a892 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -5335,7 +5335,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) */ int time1 = time(0); - u32 daynight_ratio = m_client->getDayNightRatio(); + //u32 daynight_ratio = m_client->getDayNightRatio(); m_camera_mutex.Lock(); v3f camera_position = m_camera_position; @@ -5438,7 +5438,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) continue; } - // This is ugly + // This is ugly (spherical distance limit?) /*if(m_control.range_all == false && d - 0.5*BS*MAP_BLOCKSIZE > range) continue;*/ @@ -5446,6 +5446,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) #if 1 /* Update expired mesh (used for day/night change) + + It doesn't work exactly like it should now with the + tasked mesh update but whatever. */ bool mesh_expired = false; @@ -5482,28 +5485,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) mesh_update_count++; // Mesh has been expired: generate new mesh - block->updateMesh(daynight_ratio); - //m_client->addUpdateMeshTask(block); + //block->updateMesh(daynight_ratio); + m_client->addUpdateMeshTask(block->getPos()); mesh_expired = false; } - /* - Don't draw an expired mesh that is far away - */ - /*if(mesh_expired && d >= faraway) - //if(mesh_expired) - { - // Instead, delete it - JMutexAutoLock lock(block->mesh_mutex); - if(block->mesh) - { - block->mesh->drop(); - block->mesh = NULL; - } - // And continue to next block - continue; - }*/ #endif /* Draw the faces of the block diff --git a/src/mapblock.cpp b/src/mapblock.cpp index c38887b69..e895f7749 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -24,111 +24,60 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "light.h" #include <sstream> - -/* - MapBlock -*/ - -MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy): - m_parent(parent), - m_pos(pos), - changed(true), - is_underground(false), - m_lighting_expired(true), - m_day_night_differs(false), - //m_not_fully_generated(false), - m_objects(this) +void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block) { - data = NULL; - if(dummy == false) - reallocate(); + m_daynight_ratio = daynight_ratio; + m_blockpos = block->getPos(); + + v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE; - m_spawn_timer = -10000; + /* + There is no harm not copying the TempMods of the neighbors + because they are already copied to this block + */ + m_temp_mods.clear(); + block->copyTempMods(m_temp_mods); + + /* + Copy data + */ -#ifndef SERVER - m_mesh_expired = false; - mesh_mutex.Init(); - mesh = NULL; - m_temp_mods_mutex.Init(); -#endif -} + // Allocate this block + neighbors + m_vmanip.clear(); + m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE, + blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1))); -MapBlock::~MapBlock() -{ -#ifndef SERVER { - JMutexAutoLock lock(mesh_mutex); - - if(mesh) - { - mesh->drop(); - mesh = NULL; - } - } -#endif + //TimeTaker timer("copy central block data"); + // 0ms - if(data) - delete[] data; -} - -bool MapBlock::isValidPositionParent(v3s16 p) -{ - if(isValidPosition(p)) - { - return true; + // Copy our data + block->copyTo(m_vmanip); } - else{ - return m_parent->isValidPosition(getPosRelative() + p); - } -} - -MapNode MapBlock::getNodeParent(v3s16 p) -{ - if(isValidPosition(p) == false) - { - return m_parent->getNode(getPosRelative() + p); - } - else { - if(data == NULL) - throw InvalidPositionException(); - return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; - } -} + //TimeTaker timer("copy neighbor block data"); + // 0ms -void MapBlock::setNodeParent(v3s16 p, MapNode & n) -{ - if(isValidPosition(p) == false) - { - m_parent->setNode(getPosRelative() + p, n); - } - else - { - if(data == NULL) - throw InvalidPositionException(); - data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n; - } -} - -MapNode MapBlock::getNodeParentNoEx(v3s16 p) -{ - if(isValidPosition(p) == false) - { - try{ - return m_parent->getNode(getPosRelative() + p); - } - catch(InvalidPositionException &e) - { - return MapNode(CONTENT_IGNORE); - } - } - else - { - if(data == NULL) + /* + Copy neighbors. This is lightning fast. + Copying only the borders would be *very* slow. + */ + + // Get map + NodeContainer *parentcontainer = block->getParent(); + // This will only work if the parent is the map + assert(parentcontainer->nodeContainerId() == NODECONTAINER_ID_MAP); + // OK, we have the map! + Map *map = (Map*)parentcontainer; + + for(u16 i=0; i<6; i++) { - return MapNode(CONTENT_IGNORE); + const v3s16 &dir = g_6dirs[i]; + v3s16 bp = m_blockpos + dir; + MapBlock *b = map->getBlockNoCreateNoEx(bp); + if(b) + b->copyTo(m_vmanip); } - return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; } } @@ -611,17 +560,15 @@ private: core::array<PreMeshBuffer> m_prebuffers; }; -scene::SMesh* makeMapBlockMesh( - u32 daynight_ratio, - NodeModMap &temp_mods, - VoxelManipulator &vmanip, - v3s16 blockpos_nodes) +scene::SMesh* makeMapBlockMesh(MeshMakeData *data) { // 4-21ms for MAP_BLOCKSIZE=16 // 24-155ms for MAP_BLOCKSIZE=32 //TimeTaker timer1("makeMapBlockMesh()"); core::array<FastFace> fastfaces_new; + + v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE; // floating point conversion v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z); @@ -653,15 +600,15 @@ scene::SMesh* makeMapBlockMesh( */ for(s16 y=0; y<MAP_BLOCKSIZE; y++){ for(s16 z=0; z<MAP_BLOCKSIZE; z++){ - updateFastFaceRow(daynight_ratio, posRelative_f, + updateFastFaceRow(data->m_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, - temp_mods, - vmanip, + data->m_temp_mods, + data->m_vmanip, blockpos_nodes); } } @@ -670,15 +617,15 @@ scene::SMesh* makeMapBlockMesh( */ for(s16 x=0; x<MAP_BLOCKSIZE; x++){ for(s16 y=0; y<MAP_BLOCKSIZE; y++){ - updateFastFaceRow(daynight_ratio, posRelative_f, + updateFastFaceRow(data->m_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, - temp_mods, - vmanip, + data->m_temp_mods, + data->m_vmanip, blockpos_nodes); } } @@ -687,15 +634,15 @@ scene::SMesh* makeMapBlockMesh( */ for(s16 z=0; z<MAP_BLOCKSIZE; z++){ for(s16 y=0; y<MAP_BLOCKSIZE; y++){ - updateFastFaceRow(daynight_ratio, posRelative_f, + updateFastFaceRow(data->m_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, - temp_mods, - vmanip, + data->m_temp_mods, + data->m_vmanip, blockpos_nodes); } } @@ -781,7 +728,7 @@ scene::SMesh* makeMapBlockMesh( { v3s16 p(x,y,z); - MapNode &n = vmanip.getNodeRef(blockpos_nodes+p); + MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p); /* Add torches to mesh @@ -851,7 +798,7 @@ scene::SMesh* makeMapBlockMesh( */ if(n.d == CONTENT_SIGN_WALL) { - u8 l = decode_light(n.getLightBlend(daynight_ratio)); + u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); video::SColor c(255,l,l,l); float d = (float)BS/16; @@ -907,13 +854,11 @@ scene::SMesh* makeMapBlockMesh( else if(n.d == CONTENT_WATER) { bool top_is_water = false; - try{ - MapNode n = vmanip.getNode(blockpos_nodes + v3s16(x,y+1,z)); - if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE) - top_is_water = true; - }catch(InvalidPositionException &e){} + MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); + if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE) + top_is_water = true; - u8 l = decode_light(n.getLightBlend(daynight_ratio)); + u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); video::SColor c(WATER_ALPHA,l,l,l); // Neighbor water levels (key = relative position) @@ -938,11 +883,11 @@ scene::SMesh* makeMapBlockMesh( u8 content = CONTENT_AIR; float level = -0.5 * BS; u8 flags = 0; - try{ - // Check neighbor - v3s16 p2 = p + neighbor_dirs[i]; - MapNode n2 = vmanip.getNode(blockpos_nodes + p2); - + // Check neighbor + v3s16 p2 = p + neighbor_dirs[i]; + MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); + if(n2.d != CONTENT_IGNORE) + { content = n2.d; if(n2.d == CONTENT_WATERSOURCE) @@ -955,11 +900,10 @@ scene::SMesh* makeMapBlockMesh( // NOTE: This doesn't get executed if neighbor // doesn't exist p2.Y += 1; - n2 = vmanip.getNode(blockpos_nodes + p2); + n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); if(n2.d == CONTENT_WATERSOURCE || n2.d == CONTENT_WATER) flags |= neighborflag_top_is_water; } - catch(InvalidPositionException &e){} neighbor_levels.insert(neighbor_dirs[i], level); neighbor_contents.insert(neighbor_dirs[i], content); @@ -1169,20 +1113,18 @@ scene::SMesh* makeMapBlockMesh( { //bool top_is_water = false; bool top_is_air = false; - try{ - MapNode n = vmanip.getNode(blockpos_nodes + v3s16(x,y+1,z)); - /*if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE) - top_is_water = true;*/ - if(n.d == CONTENT_AIR) - top_is_air = true; - }catch(InvalidPositionException &e){} + MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); + /*if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE) + top_is_water = true;*/ + if(n.d == CONTENT_AIR) + top_is_air = true; /*if(top_is_water == true) continue;*/ if(top_is_air == false) continue; - u8 l = decode_light(n.getLightBlend(daynight_ratio)); + u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); video::SColor c(WATER_ALPHA,l,l,l); video::S3DVertex vertices[4] = @@ -1216,8 +1158,8 @@ scene::SMesh* makeMapBlockMesh( */ else if(n.d == CONTENT_LEAVES && new_style_leaves) { - /*u8 l = decode_light(n.getLightBlend(daynight_ratio));*/ - u8 l = decode_light(undiminish_light(n.getLightBlend(daynight_ratio))); + /*u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));*/ + u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio))); video::SColor c(255,l,l,l); for(u32 j=0; j<6; j++) @@ -1331,13 +1273,113 @@ scene::SMesh* makeMapBlockMesh( //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl; } -/*scene::SMesh* makeMapBlockMesh( - u32 daynight_ratio, - NodeModMap &temp_mods, - VoxelManipulator &vmanip, - v3s16 blockpos_nodes) + +/* + MapBlock +*/ + +MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy): + m_parent(parent), + m_pos(pos), + changed(true), + is_underground(false), + m_lighting_expired(true), + m_day_night_differs(false), + //m_not_fully_generated(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; + m_temp_mods_mutex.Init(); +#endif +} + +MapBlock::~MapBlock() +{ +#ifndef SERVER + { + JMutexAutoLock lock(mesh_mutex); + + if(mesh) + { + mesh->drop(); + mesh = NULL; + } + } +#endif + + if(data) + delete[] data; +} + +bool MapBlock::isValidPositionParent(v3s16 p) +{ + if(isValidPosition(p)) + { + return true; + } + else{ + return m_parent->isValidPosition(getPosRelative() + p); + } +} + +MapNode MapBlock::getNodeParent(v3s16 p) +{ + if(isValidPosition(p) == false) + { + return m_parent->getNode(getPosRelative() + p); + } + else + { + if(data == NULL) + throw InvalidPositionException(); + return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; + } +} + +void MapBlock::setNodeParent(v3s16 p, MapNode & n) +{ + if(isValidPosition(p) == false) + { + m_parent->setNode(getPosRelative() + p, n); + } + else + { + if(data == NULL) + throw InvalidPositionException(); + data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n; + } +} + +MapNode MapBlock::getNodeParentNoEx(v3s16 p) +{ + if(isValidPosition(p) == false) + { + try{ + return m_parent->getNode(getPosRelative() + p); + } + catch(InvalidPositionException &e) + { + return MapNode(CONTENT_IGNORE); + } + } + else + { + if(data == NULL) + { + return MapNode(CONTENT_IGNORE); + } + return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; + } +} #if 1 void MapBlock::updateMesh(u32 daynight_ratio) @@ -1353,52 +1395,10 @@ void MapBlock::updateMesh(u32 daynight_ratio) } #endif - /* - Avoid interlocks by copying m_temp_mods - */ - NodeModMap temp_mods; - copyTempMods(temp_mods); - - v3s16 blockpos_nodes = getPosRelative(); - - VoxelManipulator vmanip; - // Allocate this block + borders - vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1), - blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE)); - // Copy our data - copyTo(vmanip); - // Copy borders from map - // +-Z - for(s16 x=-1; x<=MAP_BLOCKSIZE; x++) - for(s16 y=-1; y<=MAP_BLOCKSIZE; y++) - for(s16 z=-1; z<=MAP_BLOCKSIZE; z+=MAP_BLOCKSIZE+1) - { - v3s16 p(x,y,z); - vmanip.setNodeNoRef(blockpos_nodes+p, getNodeParentNoEx(p)); - } - // +-Y - for(s16 x=-1; x<=MAP_BLOCKSIZE; x++) - for(s16 y=-1; y<=MAP_BLOCKSIZE; y+=MAP_BLOCKSIZE+1) - for(s16 z=-1; z<=MAP_BLOCKSIZE; z++) - { - v3s16 p(x,y,z); - vmanip.setNodeNoRef(blockpos_nodes+p, getNodeParentNoEx(p)); - } - // +-Z - for(s16 x=-1; x<=MAP_BLOCKSIZE; x+=MAP_BLOCKSIZE+1) - for(s16 y=-1; y<=MAP_BLOCKSIZE; y++) - for(s16 z=-1; z<=MAP_BLOCKSIZE; z++) - { - v3s16 p(x,y,z); - vmanip.setNodeNoRef(blockpos_nodes+p, getNodeParentNoEx(p)); - } + MeshMakeData data; + data.fill(daynight_ratio, this); - scene::SMesh *mesh_new = makeMapBlockMesh( - daynight_ratio, - temp_mods, - vmanip, - getPosRelative() - ); + scene::SMesh *mesh_new = makeMapBlockMesh(&data); /* Replace the mesh diff --git a/src/mapblock.h b/src/mapblock.h index 1894269bd..87abf6a86 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -156,20 +156,42 @@ public: virtual MapNode getNode(v3s16 p) = 0; virtual void setNode(v3s16 p, MapNode & n) = 0; virtual u16 nodeContainerId() const = 0; + + MapNode getNodeNoEx(v3s16 p) + { + try{ + return getNode(p); + } + catch(InvalidPositionException &e){ + return MapNode(CONTENT_IGNORE); + } + } }; /* - Plain functions in mapblock.cpp + Mesh making stuff */ +class MapBlock; + +struct MeshMakeData +{ + u32 m_daynight_ratio; + NodeModMap m_temp_mods; + VoxelManipulator m_vmanip; + v3s16 m_blockpos; + + /* + Copy central data directly from block, and other data from + parent of block. + */ + void fill(u32 daynight_ratio, MapBlock *block); +}; + u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, v3s16 face_dir); -scene::SMesh* makeMapBlockMesh( - u32 daynight_ratio, - NodeModMap &temp_mods, - VoxelManipulator &vmanip, - v3s16 blockpos_nodes); +scene::SMesh* makeMapBlockMesh(MeshMakeData *data); /* MapBlock itself @@ -185,7 +207,7 @@ public: { return NODECONTAINER_ID_MAPBLOCK; } - + NodeContainer * getParent() { return m_parent; @@ -661,8 +683,7 @@ private: Private member variables */ - // Parent container (practically the Map) - // Not a MapSector, it is just a structural element. + // NOTE: Lots of things rely on this being the Map NodeContainer *m_parent; // Position in blocks on parent v3s16 m_pos; diff --git a/src/utility.h b/src/utility.h index 89c5f9981..3640b4b51 100644 --- a/src/utility.h +++ b/src/utility.h @@ -1467,6 +1467,10 @@ protected: core::list<T> m_list; }; +/* + A single worker thread - multiple client threads queue framework. +*/ + template<typename Caller, typename Data> class CallerInfo { @@ -1516,11 +1520,6 @@ public: core::list<CallerInfo<Caller, CallerData> > callers; }; -/* - Quickhands for typical request-result queues. - Used for distributing work between threads. -*/ - template<typename Key, typename T, typename Caller, typename CallerData> class RequestQueue { |