X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient.cpp;h=585fce11c3557624ac14ae72ef80e23f1da2bb67;hb=d09f9c0d1dd579a640ac4e02d19e8b858f2f1e65;hp=ec2504bc823f45920f9d82335eb7181696e47e58;hpb=1995b59320fe0fdced55c4605635f38cc42768f1;p=dragonfireclient.git diff --git a/src/client.cpp b/src/client.cpp index ec2504bc8..585fce11c 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 @@ -25,6 +25,105 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "main.h" #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() { @@ -36,13 +135,24 @@ 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) { - sleep_ms(50); + sleep_ms(3); continue; } + ScopeProfiler sp(&g_profiler, "mesh make"); + scene::SMesh *mesh_new = NULL; mesh_new = makeMapBlockMesh(q->data); @@ -68,6 +178,7 @@ void * MeshUpdateThread::Thread() Client::Client( IrrlichtDevice *device, const char *playername, + std::string password, MapDrawControl &control): m_mesh_update_thread(), m_env( @@ -83,10 +194,12 @@ Client::Client( m_server_ser_ver(SER_FMT_VER_INVALID), m_inventory_updated(false), m_time_of_day(0), - m_map_seed(0) + m_map_seed(0), + m_password(password), + 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; @@ -190,7 +303,11 @@ void Client::step(float dtime) m_packetcounter.clear(); } } + + // Get connection status + bool connected = connectedAndInitialized(); +#if 0 { /* Delete unused sectors @@ -211,25 +328,24 @@ 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().deleteUnusedSectors + /*u32 num = m_env.getMap().unloadUnusedData (delete_unused_sectors_timeout, true, &deleted_blocks);*/ // Delete whole sectors - u32 num = m_env.getMap().deleteUnusedSectors + m_env.getMap().unloadUnusedData (delete_unused_sectors_timeout, - false, &deleted_blocks); + &deleted_blocks); - if(num > 0) + if(deleted_blocks.size() > 0) { /*dstream< data(2+1+PLAYERNAME_SIZE); + // [23] u8[28] password + SharedBuffer data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE); writeU16(&data[0], TOSERVER_INIT); writeU8(&data[2], SER_FMT_VER_HIGHEST); + memset((char*)&data[3], 0, PLAYERNAME_SIZE); snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName()); + + /*dstream<<"Client: password hash is \""< 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 */ @@ -331,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()); } /* @@ -546,8 +731,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) //dstream<<"Client received command="<<(int)command<= 4) + { + std::string datastring((char*)&data[2], datasize-2); + std::istringstream is(datastring, std::ios_base::binary); + m_access_denied_reason = deSerializeWideString(is); + } + return; + } + if(ser_version == SER_FMT_VER_INVALID) { dout_client<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 - - try{ - block = sector->getBlockNoCreate(p.Y); - /* - Update an existing block - */ - //dstream<<"Updating"<deSerialize(istr, ser_version); - //block->setChangedFlag(); - } - catch(InvalidPositionException &e) - { - /* - Create a new block - */ - //dstream<<"Creating new"<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 + //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 /* @@ -768,6 +932,10 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio()); + /* + Add it to mesh update queue and set it to be acknowledged after update. + */ + //std::cerr<<"Adding mesh update task for received block"<getName(); + std::string oldpwd = translatePassword(playername, oldpassword); + std::string newpwd = translatePassword(playername, newpassword); + + std::ostringstream os(std::ios_base::binary); + u8 buf[2+PASSWORD_SIZE*2]; + /* + [0] u16 TOSERVER_PASSWORD + [2] u8[28] old password + [30] u8[28] new password + */ + + writeU16(buf, TOSERVER_PASSWORD); + for(u32 i=0;i data((u8*)s.c_str(), s.size()); + // Send as reliable + Send(0, data, true); +} + + void Client::sendDamage(u8 damage) { DSTACK(__FUNCTION_NAME); @@ -1694,7 +1895,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) @@ -1922,12 +2123,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 @@ -1941,6 +2136,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(): " @@ -1950,7 +2179,7 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server) MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p); if(b == NULL) return; - + /* Create a task to update the mesh of the block */ @@ -1959,7 +2188,8 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server) { //TimeTaker timer("data fill"); - // 0ms + // Release: ~0ms + // Debug: 1-6ms, avg=2ms data->fill(getDayNightRatio(), b); } @@ -1985,6 +2215,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); }