X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient.cpp;h=2148bfe59b438749d52dcac8ed668c3f6e5d080f;hb=569fca53089b7b7e87b02edd44e2ad47166f7af6;hp=7093a5190a2c40d176bf8279bb1437c2ba9cdba5;hpb=01ae0daea501f47ec56a8368e530cb4176fc44cd;p=dragonfireclient.git diff --git a/src/client.cpp b/src/client.cpp index 7093a5190..2148bfe59 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -33,8 +33,25 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "nodemetadata.h" #include "nodedef.h" -#include "tooldef.h" +#include "itemdef.h" #include +#include "sha1.h" +#include "base64.h" +#include "clientmap.h" + +static std::string getTextureCacheDir() +{ + return porting::path_user + DIR_DELIM + "cache" + DIR_DELIM + "textures"; +} + +struct TextureRequest +{ + std::string name; + + TextureRequest(const std::string &name_=""): + name(name_) + {} +}; /* QueuedMeshUpdate @@ -66,8 +83,9 @@ MeshUpdateQueue::~MeshUpdateQueue() { JMutexAutoLock lock(m_mutex); - core::list::Iterator i; - for(i=m_queue.begin(); i!=m_queue.end(); i++) + for(std::vector::iterator + i = m_queue.begin(); + i != m_queue.end(); i++) { QueuedMeshUpdate *q = *i; delete q; @@ -77,7 +95,7 @@ MeshUpdateQueue::~MeshUpdateQueue() /* peer_id=0 adds with nobody to send to */ -void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server) +void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server, bool urgent) { DSTACK(__FUNCTION_NAME); @@ -85,12 +103,16 @@ void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_se JMutexAutoLock lock(m_mutex); + if(urgent) + m_urgents.insert(p); + /* 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++) + for(std::vector::iterator + i = m_queue.begin(); + i != m_queue.end(); i++) { QueuedMeshUpdate *q = *i; if(q->p == p) @@ -120,12 +142,19 @@ 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; + bool must_be_urgent = !m_urgents.empty(); + for(std::vector::iterator + i = m_queue.begin(); + i != m_queue.end(); i++) + { + QueuedMeshUpdate *q = *i; + if(must_be_urgent && m_urgents.count(q->p) == 0) + continue; + m_queue.erase(i); + m_urgents.erase(q->p); + return q; + } + return NULL; } /* @@ -162,8 +191,12 @@ void * MeshUpdateThread::Thread() ScopeProfiler sp(g_profiler, "Client: Mesh making"); - scene::SMesh *mesh_new = NULL; - mesh_new = makeMapBlockMesh(q->data, m_gamedef); + MapBlockMesh *mesh_new = new MapBlockMesh(q->data); + if(mesh_new->getMesh()->getMeshBufferCount() == 0) + { + delete mesh_new; + mesh_new = NULL; + } MeshUpdateResult r; r.p = q->p; @@ -190,11 +223,11 @@ Client::Client( std::string password, MapDrawControl &control, IWritableTextureSource *tsrc, - IWritableToolDefManager *tooldef, + IWritableItemDefManager *itemdef, IWritableNodeDefManager *nodedef ): m_tsrc(tsrc), - m_tooldef(tooldef), + m_itemdef(itemdef), m_nodedef(nodedef), m_mesh_update_thread(this), m_env( @@ -202,16 +235,28 @@ Client::Client( device->getSceneManager()->getRootSceneNode(), device->getSceneManager(), 666), device->getSceneManager(), - tsrc, this + tsrc, this, device ), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), m_device(device), m_server_ser_ver(SER_FMT_VER_INVALID), + m_playeritem(0), m_inventory_updated(false), - m_time_of_day(0), + m_inventory_from_server(NULL), + m_inventory_from_server_age(0.0), + m_animation_time(0), + m_crack_level(-1), + m_crack_pos(0,0,0), m_map_seed(0), m_password(password), - m_access_denied(false) + m_access_denied(false), + m_texture_receive_progress(0), + m_textures_received(false), + m_itemdef_received(false), + m_nodedef_received(false), + m_time_of_day_set(false), + m_last_time_of_day_f(-1), + m_time_of_day_update_timer(0) { m_packetcounter_timer = 0.0; //m_delete_unused_sectors_timer = 0.0; @@ -226,12 +271,6 @@ Client::Client( else infostream<<"Not building texture atlas."<updateTextures(m_tsrc); - - // Start threads after setting up content definitions - m_mesh_update_thread.Start(); - /* Add local player */ @@ -241,9 +280,6 @@ Client::Client( player->updateName(playername); m_env.addPlayer(player); - - // Initialize player in the inventory context - m_inventory_context.current_player = player; } } @@ -257,6 +293,8 @@ Client::~Client() m_mesh_update_thread.setRun(false); while(m_mesh_update_thread.IsRunning()) sleep_ms(100); + + delete m_inventory_from_server; } void Client::connect(Address address) @@ -293,6 +331,12 @@ void Client::step(float dtime) else m_ignore_damage_timer = 0.0; + m_animation_time += dtime; + if(m_animation_time > 60.0) + m_animation_time -= 60.0; + + m_time_of_day_update_timer += dtime; + //infostream<<"Client steps "<replaceMesh(r.mesh); + //JMutexAutoLock lock(block->mesh_mutex); + + // Delete the old mesh + if(block->mesh != NULL) + { + // TODO: Remove hardware buffers of meshbuffers of block->mesh + delete block->mesh; + block->mesh = NULL; + } + + // Replace with the new mesh + block->mesh = r.mesh; } if(r.ack_block_to_server) { @@ -643,6 +700,30 @@ void Client::step(float dtime) } } } + + /* + If the server didn't update the inventory in a while, revert + the local inventory (so the player notices the lag problem + and knows something is wrong). + */ + if(m_inventory_from_server) + { + float interval = 10.0; + float count_before = floor(m_inventory_from_server_age / interval); + + m_inventory_from_server_age += dtime; + + float count_after = floor(m_inventory_from_server_age / interval); + + if(count_after != count_before) + { + // Do this every seconds after TOCLIENT_INVENTORY + // Reset the locally changed inventory to the authoritative inventory + Player *player = m_env.getLocalPlayer(); + player->inventory = *m_inventory_from_server; + m_inventory_updated = true; + } + } } // Virtual methods from con::PeerHandler @@ -661,8 +742,14 @@ void Client::deletingPeer(con::Peer *peer, bool timeout) void Client::ReceiveAll() { DSTACK(__FUNCTION_NAME); + u32 start_ms = porting::getTimeMs(); for(;;) { + // Limit time even if there would be huge amounts of data to + // process + if(porting::getTimeMs() > start_ms + 100) + break; + try{ Receive(); } @@ -820,9 +907,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) //TimeTaker t1("TOCLIENT_REMOVENODE"); - // This will clear the cracking animation after digging - ((ClientMap&)m_env.getMap()).clearTempMod(p); - removeNode(p); } else if(command == TOCLIENT_ADDNODE) @@ -838,7 +922,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) //TimeTaker t1("TOCLIENT_ADDNODE"); MapNode n; - n.deSerialize(&data[8], ser_version, m_nodedef); + n.deSerialize(&data[8], ser_version); addNode(p, n); } @@ -879,7 +963,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) Update an existing block */ //infostream<<"Updating"<deSerialize(istr, ser_version); + block->deSerialize(istr, ser_version, false); } else { @@ -888,18 +972,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) */ //infostream<<"Creating new"<deSerialize(istr, ser_version); + block->deSerialize(istr, ser_version, false); 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 @@ -922,232 +996,12 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) 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()); /* Add it to mesh update queue and set it to be acknowledged after update. */ //infostream<<"Adding mesh update task for received block"<isLocal()) - { - start += player_size; - continue; - } - - v3s32 ps = readV3S32(&data[start+2]); - v3s32 ss = readV3S32(&data[start+2+12]); - s32 pitch_i = readS32(&data[start+2+12+12]); - s32 yaw_i = readS32(&data[start+2+12+12+4]); - /*infostream<<"Client: got " - <<"pitch_i="< players_alive; - for(u32 i=0; iupdateName((char*)&data[start+2]); - - start += item_size; - } - - /* - Remove those players from the environment that - weren't listed by the server. - */ - //infostream<<"Removing dead players"< players = m_env.getPlayers(); - core::list::Iterator ip; - for(ip=players.begin(); ip!=players.end(); ip++) - { - // Ingore local player - if((*ip)->isLocal()) - continue; - - // Warn about a special case - if((*ip)->peer_id == 0) - { - infostream<<"Client: Removing " - "dead player with id=0"<::Iterator i; - for(i=players_alive.begin(); i!=players_alive.end(); i++) - { - if((*ip)->peer_id == *i) - { - is_alive = true; - break; - } - } - /*infostream<<"peer_id="<<((*ip)->peer_id) - <<" is_alive="<peer_id - <peer_id); - } - } //envlock - } - else if(command == TOCLIENT_SECTORMETA) - { - infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<inventory.deSerialize(is, this); + player->inventory.deSerialize(is); //t1.stop(); m_inventory_updated = true; + delete m_inventory_from_server; + m_inventory_from_server = new Inventory(player->inventory); + m_inventory_from_server_age = 0.0; + //infostream<<"Client got player inventory:"<inventory.print(infostream); } } - //DEBUG - else if(command == TOCLIENT_OBJECTDATA) - { - // Strip command word and create a stringstream - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - - u8 buf[12]; - - /* - Read players - */ - - is.read((char*)buf, 2); - u16 playercount = readU16(buf); - - for(u16 i=0; iisLocal()) - { - continue; - } - - f32 pitch = (f32)pitch_i / 100.0; - f32 yaw = (f32)yaw_i / 100.0; - v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.); - v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.); - - player->setPosition(position); - player->setSpeed(speed); - player->setPitch(pitch); - player->setYaw(yaw); - } - - /* - Read block objects - NOTE: Deprecated stuff - */ - - // Read active block count - u16 blockcount = readU16(is); - if(blockcount != 0){ - infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 " - "not supported"<deleteItem(0); - infostream - <<"Client: empty player item for peer " - << peer_id << std::endl; - } else { - std::istringstream iss(itemstring); - delete inv->changeItem(0, - InventoryItem::deSerialize(iss, this)); - infostream<<"Client: player item for peer " << peer_id << ": "; - player->getWieldItem()->serialize(infostream); - infostream<changeItem(0, item); + if(itemstring.empty()) + { + infostream<<"Client: empty player item for peer " + <getFileSystem(); + video::IVideoDriver *vdrv = m_device->getVideoDriver(); std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); - // Stop threads while updating content definitions - m_mesh_update_thread.stop(); + // Mesh update thread must be stopped while + // updating content definitions + assert(!m_mesh_update_thread.IsRunning()); - std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary); - m_tooldef->deSerialize(tmp_is); - - // Resume threads - m_mesh_update_thread.setRun(true); - m_mesh_update_thread.Start(); + int num_textures = readU16(is); + + core::list texture_requests; + + for(int i=0; i data_rw(tmp_os.str().c_str(), tmp_os.str().size()); + + // Create an irrlicht memory file + io::IReadFile *rfile = irrfs->createMemoryReadFile( + *data_rw, tmp_os.str().size(), "_tempreadfile"); + assert(rfile); + // Read image + video::IImage *img = vdrv->createImageFromFile(rfile); + if(!img){ + infostream<<"Client: Cannot create image from data of " + <<"received texture \""<drop(); + } + else { + m_tsrc->insertSourceImage(name, img); + img->drop(); + rfile->drop(); + + texture_found = true; + } + } + else { + infostream<<"Client::Texture cached sha1 hash not matching server hash: " + <"< "<::Iterator i = texture_requests.begin(); + i != texture_requests.end(); i++) { + os<name); + } + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8*)s.c_str(), s.size()); + // Send as reliable + Send(0, data, true); + infostream<<"Client: Sending request list to server " <getFileSystem(); video::IVideoDriver *vdrv = m_device->getVideoDriver(); std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); - // Stop threads while updating content definitions - m_mesh_update_thread.stop(); - + // Mesh update thread must be stopped while + // updating content definitions + assert(!m_mesh_update_thread.IsRunning()); + /* u16 command - u32 number of textures + u16 total number of texture bunches + u16 index of this bunch + u32 number of textures in this bunch for each texture { u16 length of name string name @@ -1546,12 +1493,26 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) data } */ + int num_bunches = readU16(is); + int bunch_i = readU16(is); + m_texture_receive_progress = (float)bunch_i / (float)(num_bunches - 1); + if(bunch_i == num_bunches - 1) + m_textures_received = true; int num_textures = readU32(is); - infostream<<"Client: Received textures: count: "< data_rw(data.c_str(), data.size()); // Create an irrlicht memory file @@ -1566,29 +1527,79 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) rfile->drop(); continue; } + + fs::CreateAllDirs(getTextureCacheDir()); + + std::string filename = getTextureCacheDir() + DIR_DELIM + name; + std::ofstream outfile(filename.c_str(), std::ios_base::binary | std::ios_base::trunc); + + if (outfile.good()) { + outfile.write(data.c_str(),data.length()); + outfile.close(); + } + else { + errorstream<<"Client: Unable to open cached texture file "<< filename <insertSourceImage(name, img); img->drop(); rfile->drop(); } - - // Rebuild inherited images and recreate textures - m_tsrc->rebuildImagesAndTextures(); - - // Update texture atlas - if(g_settings->getBool("enable_texture_atlas")) - m_tsrc->buildMainAtlas(this); - - // Update node textures - m_nodedef->updateTextures(m_tsrc); - - // Resume threads - m_mesh_update_thread.setRun(true); - m_mesh_update_thread.Start(); ClientEvent event; event.type = CE_TEXTURES_UPDATED; m_client_event_queue.push_back(event); } + else if(command == TOCLIENT_TOOLDEF) + { + infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<deSerialize(tmp_is2); + m_nodedef_received = true; + } + else if(command == TOCLIENT_CRAFTITEMDEF) + { + infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<deSerialize(tmp_is2); + m_itemdef_received = true; + } else { infostream<<"Client: Ignoring unknown command " @@ -1602,93 +1613,41 @@ void Client::Send(u16 channelnum, SharedBuffer data, bool reliable) m_con.Send(PEER_ID_SERVER, channelnum, data, reliable); } -void Client::groundAction(u8 action, v3s16 nodepos_undersurface, - v3s16 nodepos_oversurface, u16 item) +void Client::interact(u8 action, const PointedThing& pointed) { if(connectedAndInitialized() == false){ - infostream<<"Client::groundAction() " + infostream<<"Client::interact() " "cancelled (not connected)" < data(datasize); - writeU16(&data[0], TOSERVER_GROUND_ACTION); - writeU8(&data[2], action); - writeV3S16(&data[3], nodepos_undersurface); - writeV3S16(&data[9], nodepos_oversurface); - writeU16(&data[15], item); - Send(0, data, true); -} - -void Client::clickActiveObject(u8 button, u16 id, u16 item_i) -{ - if(connectedAndInitialized() == false){ - infostream<<"Client::clickActiveObject() " - "cancelled (not connected)" - <inventory.getList("main"); - if(mlist != NULL) - { - InventoryItem *item = mlist->getItem(item_i); - if(item && (std::string)item->getName() == "ToolItem") - { - titem = (ToolItem*)item; - toolname = titem->getToolName(); - } - } + std::string s = os.str(); + SharedBuffer data((u8*)s.c_str(), s.size()); - v3f playerpos = player->getPosition(); - v3f objpos = obj->getPosition(); - v3f dir = (objpos - playerpos).normalize(); - - bool disable_send = obj->directReportPunch(toolname, dir); - - if(disable_send) - return; - } - } - - /* - length: 7 - [0] u16 command - [2] u8 button (0=left, 1=right) - [3] u16 id - [5] u16 item - */ - u8 datasize = 2 + 1 + 6 + 2 + 2; - SharedBuffer data(datasize); - writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT); - writeU8(&data[2], button); - writeU16(&data[3], id); - writeU16(&data[5], item_i); + // Send as reliable Send(0, data, true); } @@ -1909,8 +1868,6 @@ void Client::sendPlayerItem(u16 item) void Client::removeNode(v3s16 p) { - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - core::map modified_blocks; try @@ -1922,20 +1879,20 @@ void Client::removeNode(v3s16 p) { } + // add urgent task to update the modified node + addUpdateMeshTaskForNode(p, false, true); + for(core::map::Iterator i = modified_blocks.getIterator(); i.atEnd() == false; i++) { v3s16 p = i.getNode()->getKey(); - //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio()); addUpdateMeshTaskWithEdge(p); } } void Client::addNode(v3s16 p, MapNode n) { - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - TimeTaker timer1("Client::addNode()"); core::map modified_blocks; @@ -1943,50 +1900,20 @@ void Client::addNode(v3s16 p, MapNode n) try { //TimeTaker timer3("Client::addNode(): addNodeAndUpdate"); - std::string st = std::string(""); - m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st); + m_env.getMap().addNodeAndUpdate(p, n, modified_blocks); } catch(InvalidPositionException &e) {} - //TimeTaker timer2("Client::addNode(): updateMeshes"); - for(core::map::Iterator i = modified_blocks.getIterator(); i.atEnd() == false; i++) { v3s16 p = i.getNode()->getKey(); - //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio()); addUpdateMeshTaskWithEdge(p); } } -void Client::updateCamera(v3f pos, v3f dir, f32 fov) -{ - m_env.getClientMap().updateCamera(pos, dir, fov); -} - -void Client::renderPostFx() -{ - m_env.getClientMap().renderPostFx(); -} - -MapNode Client::getNode(v3s16 p) -{ - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - return m_env.getMap().getNode(p); -} - -NodeMetadata* Client::getNodeMetadata(v3s16 p) -{ - return m_env.getMap().getNodeMetadata(p); -} - -LocalPlayer* Client::getLocalPlayer() -{ - return m_env.getLocalPlayer(); -} - void Client::setPlayerControl(PlayerControl &control) { //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out @@ -1997,11 +1924,9 @@ void Client::setPlayerControl(PlayerControl &control) void Client::selectPlayerItem(u16 item) { - LocalPlayer *player = m_env.getLocalPlayer(); - assert(player != NULL); - - player->wieldItem(item); - + //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out + m_playeritem = item; + m_inventory_updated = true; sendPlayerItem(item); } @@ -2025,42 +1950,51 @@ void Client::getLocalInventory(Inventory &dst) dst = player->inventory; } -InventoryContext *Client::getInventoryContext() -{ - return &m_inventory_context; -} - -Inventory* Client::getInventory(InventoryContext *c, std::string id) +Inventory* Client::getInventory(const InventoryLocation &loc) { - if(id == "current_player") + switch(loc.type){ + case InventoryLocation::UNDEFINED: + {} + break; + case InventoryLocation::CURRENT_PLAYER: { - assert(c->current_player); - return &(c->current_player->inventory); + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + return &player->inventory; } - - Strfnd fn(id); - std::string id0 = fn.next(":"); - - if(id0 == "nodemeta") + break; + case InventoryLocation::PLAYER: { - v3s16 p; - p.X = stoi(fn.next(",")); - p.Y = stoi(fn.next(",")); - p.Z = stoi(fn.next(",")); - NodeMetadata* meta = getNodeMetadata(p); - if(meta) - return meta->getInventory(); - infostream<<"nodemeta at ("<inventory; + } + break; + case InventoryLocation::NODEMETA: + { + NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p); + if(!meta) + return NULL; + return meta->getInventory(); + } + break; + default: + assert(0); + } return NULL; } void Client::inventoryAction(InventoryAction *a) { + /* + Send it to the server + */ sendInventoryAction(a); + + /* + Predict some local inventory changes + */ + a->clientApply(this, this); } ClientActiveObject * Client::getSelectedActiveObject( @@ -2115,58 +2049,97 @@ void Client::printDebugInfo(std::ostream &os) //<<", m_opt_not_found_history.size()="< Client::getConnectedPlayerNames() { - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - return m_env.getDayNightRatio(); + core::list players = m_env.getPlayers(true); + core::list playerNames; + for(core::list::Iterator + i = players.begin(); + i != players.end(); i++) + { + Player *player = *i; + playerNames.push_back(narrow_to_wide(player->getName())); + } + return playerNames; } -u16 Client::getHP() +float Client::getAnimationTime() { - Player *player = m_env.getLocalPlayer(); - assert(player != NULL); - return player->hp; + return m_animation_time; } -void Client::setTempMod(v3s16 p, NodeMod mod) +int Client::getCrackLevel() { - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); + return m_crack_level; +} - core::map affected_blocks; - ((ClientMap&)m_env.getMap()).setTempMod(p, mod, - &affected_blocks); +void Client::setCrack(int level, v3s16 pos) +{ + int old_crack_level = m_crack_level; + v3s16 old_crack_pos = m_crack_pos; - for(core::map::Iterator - i = affected_blocks.getIterator(); - i.atEnd() == false; i++) + m_crack_level = level; + m_crack_pos = pos; + + if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos)) { - i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio()); + // remove old crack + addUpdateMeshTaskForNode(old_crack_pos, false, true); + } + if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos)) + { + // add new crack + addUpdateMeshTaskForNode(pos, false, true); } } -void Client::clearTempMod(v3s16 p) +u16 Client::getHP() { - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - assert(m_env.getMap().mapType() == MAPTYPE_CLIENT); + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + return player->hp; +} + +bool Client::getChatMessage(std::wstring &message) +{ + if(m_chat_queue.size() == 0) + return false; + message = m_chat_queue.pop_front(); + return true; +} - core::map affected_blocks; - ((ClientMap&)m_env.getMap()).clearTempMod(p, - &affected_blocks); +void Client::typeChatMessage(const std::wstring &message) +{ + // Discard empty line + if(message == L"") + return; - for(core::map::Iterator - i = affected_blocks.getIterator(); - i.atEnd() == false; i++) + // Send to others + sendChatMessage(message); + + // Show locally + if (message[0] == L'/') { - i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio()); + m_chat_queue.push_back( + (std::wstring)L"issued command: "+message); + } + else + { + LocalPlayer *player = m_env.getLocalPlayer(); + assert(player != NULL); + std::wstring name = narrow_to_wide(player->getName()); + m_chat_queue.push_back( + (std::wstring)L"<"+name+L"> "+message); } } -void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server) +void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent) { /*infostream<<"Client::addUpdateMeshTask(): " <<"("<fill(getDayNightRatio(), b); + data->fill(b); + data->setCrack(m_crack_level, m_crack_pos); + data->setSmoothLighting(g_settings->getBool("smooth_lighting")); } // 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); + m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent); /*infostream<<"Mesh update input queue size is " <replaceMesh(mesh_new); - delete data; - } -#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); } -void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server) +void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent) { /*{ v3s16 p = blockpos; @@ -2227,27 +2184,68 @@ void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server) try{ v3s16 p = blockpos + v3s16(0,0,0); //MapBlock *b = m_env.getMap().getBlockNoCreate(p); - addUpdateMeshTask(p, ack_to_server); + addUpdateMeshTask(p, ack_to_server, urgent); } catch(InvalidPositionException &e){} // Leading edge try{ v3s16 p = blockpos + v3s16(-1,0,0); - addUpdateMeshTask(p); + addUpdateMeshTask(p, false, urgent); } catch(InvalidPositionException &e){} try{ v3s16 p = blockpos + v3s16(0,-1,0); - addUpdateMeshTask(p); + addUpdateMeshTask(p, false, urgent); } catch(InvalidPositionException &e){} try{ v3s16 p = blockpos + v3s16(0,0,-1); - addUpdateMeshTask(p); + addUpdateMeshTask(p, false, urgent); } catch(InvalidPositionException &e){} } +void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent) +{ + { + v3s16 p = nodepos; + infostream<<"Client::addUpdateMeshTaskForNode(): " + <<"("<rebuildImagesAndTextures(); + + // Update texture atlas + if(g_settings->getBool("enable_texture_atlas")) + m_tsrc->buildMainAtlas(this); + + // Update node aliases + m_nodedef->updateAliases(m_itemdef); + + // Update node textures + m_nodedef->updateTextures(m_tsrc); + + // Update item textures and meshes + m_itemdef->updateTexturesAndMeshes(this); + + // Start mesh update thread after setting up content definitions + m_mesh_update_thread.Start(); +} + float Client::getRTT(void) { try{ @@ -2270,16 +2294,28 @@ float Client::getRTT(void) // IGameDef interface // Under envlock -IToolDefManager* Client::getToolDefManager() +IItemDefManager* Client::getItemDefManager() { - return m_tooldef; + return m_itemdef; } INodeDefManager* Client::getNodeDefManager() { return m_nodedef; } +ICraftDefManager* Client::getCraftDefManager() +{ + return NULL; + //return m_craftdef; +} ITextureSource* Client::getTextureSource() { return m_tsrc; } +u16 Client::allocateUnknownNodeId(const std::string &name) +{ + errorstream<<"Client::allocateUnknownNodeId(): " + <<"Client cannot allocate node IDs"<