X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fserver.cpp;h=4e9ff076fc3317692dbaefe404cf764ad4b37bd2;hb=51d308c666dfd023169b7d5e200fbefb3d315d3b;hp=ab4032743121a8abcf34447303a4ae9db475227a;hpb=fd7a0735c9aeaa7978190049319e3cdfe48920a4;p=dragonfireclient.git diff --git a/src/server.cpp b/src/server.cpp index ab4032743..4e9ff076f 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,6 +1,6 @@ /* Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola +Copyright (C) 2010-2011 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 @@ -28,6 +28,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "voxel.h" #include "materials.h" #include "mineral.h" +#include "config.h" +#include "servercommand.h" +#include "filesys.h" #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) @@ -72,7 +75,7 @@ void * EmergeThread::Thread() DSTACK(__FUNCTION_NAME); - bool debug=false; + //bool debug=false; BEGIN_DEBUG_EXCEPTION_HANDLER @@ -91,7 +94,19 @@ void * EmergeThread::Thread() SharedPtr q(qptr); v3s16 &p = q->pos; - + v2s16 p2d(p.X,p.Z); + + /* + Do not generate over-limit + */ + if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) + continue; + //derr_server<<"EmergeThread::Thread(): running"< modified_blocks; - {//envlock - - //TimeTaker envlockwaittimer("block emerge envlock wait time"); + bool only_from_disk = false; - // 0-50ms - JMutexAutoLock envlock(m_server->m_env_mutex); + if(optional) + only_from_disk = true; - //envlockwaittimer.stop(); + v2s16 chunkpos = map.sector_to_chunk(p2d); - //TimeTaker timer("block emerge (while env locked)"); - - try{ - bool only_from_disk = false; - - if(optional) - only_from_disk = true; + bool generate_chunk = false; + if(only_from_disk == false) + { + JMutexAutoLock envlock(m_server->m_env_mutex); + if(map.chunkNonVolatile(chunkpos) == false) + generate_chunk = true; + } + if(generate_chunk) + { + ChunkMakeData data; - // First check if the block already exists - //block = map.getBlockNoCreate(p); + { + JMutexAutoLock envlock(m_server->m_env_mutex); + map.initChunkMake(data, chunkpos); + } + + makeChunk(&data); - if(block == NULL) { - //dstream<<"Calling emergeBlock"<m_env_mutex); + map.finishChunkMake(data, changed_blocks); + } + } + + /* + Fetch block from map or generate a single block + */ + { + JMutexAutoLock envlock(m_server->m_env_mutex); + + // Load sector if it isn't loaded + if(map.getSectorNoGenerateNoEx(p2d) == NULL) + map.loadSectorFull(p2d); -#if 0 - /* - While we're at it, generate some other blocks too - */ - try + block = map.getBlockNoCreateNoEx(p); + if(!block || block->isDummy()) + { + if(only_from_disk) { - map.emergeBlock( - p+v3s16(0,1,0), - only_from_disk, - changed_blocks, - lighting_invalidated_blocks); - map.emergeBlock( - p+v3s16(0,-1,0), - only_from_disk, - changed_blocks, - lighting_invalidated_blocks); + got_block = false; } - catch(InvalidPositionException &e) + else { + // Get, load or create sector + ServerMapSector *sector = + (ServerMapSector*)map.createSector(p2d); + // Generate block + block = map.generateBlock(p, block, sector, changed_blocks, + lighting_invalidated_blocks); + if(block == NULL) + got_block = false; } -#endif } - - // If it is a dummy, block was not found on disk - if(block->isDummy()) + else { - //dstream<<"EmergeThread: Got a dummy block"<getLightingExpired()){ + lighting_invalidated_blocks[block->getPos()] = block; } } + + // TODO: Some additional checking and lighting updating, + // see emergeBlock } - catch(InvalidPositionException &e) - { - // Block not found. - // This happens when position is over limit. - got_block = false; - } + + {//envlock + JMutexAutoLock envlock(m_server->m_env_mutex); if(got_block) { - if(debug && changed_blocks.size() > 0) - { - dout_server<::Iterator i = changed_blocks.getIterator(); - i.atEnd() == false; i++) - { - MapBlock *block = i.getNode()->getValue(); - v3s16 p = block->getPos(); - dout_server<<"("<= 0) + return; // Won't send anything if already sending if(m_blocks_sending.size() >= g_settings.getU16 @@ -336,8 +347,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, /* Get the starting value of the block finder radius. */ - s16 last_nearest_unsent_d; - s16 d_start; if(m_last_center != center) { @@ -354,14 +363,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, //dstream<<"Resetting m_nearest_unsent_d"<= maximum_simultaneous_block_sends_now) - { - /*dstream<<"Not sending more blocks. Queue full. " - <= max_simul_dynamic) goto queue_full; - } - + + // Don't send blocks that are currently being transferred if(m_blocks_sending.find(p) != NULL) continue; @@ -474,37 +481,35 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, continue; } -#if 0 +#if 1 /* If block is far away, don't generate it unless it is - near ground level - - NOTE: We can't know the ground level this way with the - new generator. + near ground level. */ - if(d > 4) + if(d >= 4) { - v2s16 p2d(p.X, p.Z); - MapSector *sector = NULL; - try - { - sector = server->m_env.getMap().getSectorNoGenerate(p2d); - } - catch(InvalidPositionException &e) - { - } - - if(sector != NULL) - { - // Get center ground height in nodes - f32 gh = sector->getGroundHeight( - v2s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2)); - // Block center y in nodes - f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2); - // If differs a lot, don't generate - if(fabs(gh - y) > MAP_BLOCKSIZE*2) - generate = false; - } + #if 1 + // Block center y in nodes + f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2); + // Don't generate if it's very high or very low + if(y < -64 || y > 64) + generate = false; + #endif + #if 0 + v2s16 p2d_nodes_center( + MAP_BLOCKSIZE*p.X, + MAP_BLOCKSIZE*p.Z); + + // Get ground height in nodes + s16 gh = server->m_env.getServerMap().findGroundLevel( + p2d_nodes_center); + + // If differs a lot, don't generate + if(fabs(gh - y) > MAP_BLOCKSIZE*2) + generate = false; + // Actually, don't even send it + //continue; + #endif } #endif @@ -554,6 +559,20 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, v2s16 chunkpos = map->sector_to_chunk(p2d); if(map->chunkNonVolatile(chunkpos) == false) block_is_invalid = true; +#if 1 + /* + If block is not close, don't send it unless it is near + ground level. + + Block is not near ground level if night-time mesh + doesn't differ from day-time mesh. + */ + if(d > 3) + { + if(block->dayNightDiffed() == false) + continue; + } +#endif } /* @@ -572,7 +591,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, */ if(new_nearest_unsent_d == -1 || d < new_nearest_unsent_d) { - new_nearest_unsent_d = d; + if(generate == true) + new_nearest_unsent_d = d; } /* @@ -610,6 +630,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, dest.push_back(q); num_blocks_selected += 1; + sending_something = true; } } queue_full: @@ -618,6 +639,24 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, { m_nearest_unsent_d = new_nearest_unsent_d; } + + if(sending_something == false) + { + m_nothing_to_send_counter++; + if(m_nothing_to_send_counter >= 3) + { + // Pause time in seconds + m_nothing_to_send_pause_timer = 2.0; + } + } + else + { + m_nothing_to_send_counter = 0; + } + + /*timer_result = timer.stop(true); + if(timer_result != 0) + dstream<<"GetNextBlocks duration: "<stepObjects(dtime, true, server->getDayNightRatio()); + block->stepObjects(dtime, true, server->m_env.getDayNightRatio()); stepped_blocks.insert(p, true); block->setChangedFlag(); } @@ -891,6 +930,7 @@ void RemoteClient::SetBlocksNotSent(core::map &blocks) PlayerInfo::PlayerInfo() { name[0] = 0; + avg_rtt = 0; } void PlayerInfo::PrintLine(std::ostream *s) @@ -929,7 +969,6 @@ Server::Server( m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), m_thread(this), m_emergethread(this), - m_time_of_day(9000), m_time_counter(0), m_time_of_day_send_timer(0), m_uptime(0), @@ -948,15 +987,26 @@ Server::Server( m_con_mutex.Init(); m_step_dtime_mutex.Init(); m_step_dtime = 0.0; - + + // Register us to receive map edit events m_env.getMap().addEventReceiver(this); + // If file exists, load environment metadata + if(fs::PathExists(m_mapsavedir+"/env_meta.txt")) + { + dstream<<"Server: Loading environment metadata"<serialization_version == SER_FMT_VER_INVALID) continue; - SendChatMessage(client->peer_id, line); + try{ + SendChatMessage(client->peer_id, line); + } + catch(con::PeerNotFoundException &e) + {} } } /* Save players */ + dstream<<"Server: Saving players"<PrintInfo(std::cout); } @@ -1321,9 +1382,12 @@ void Server::AsyncRunStep() data_buffer.append(buf, 2); writeU8((u8*)buf, type); data_buffer.append(buf, 1); - - data_buffer.append(serializeLongString( - obj->getClientInitializationData())); + + if(obj) + data_buffer.append(serializeLongString( + obj->getClientInitializationData())); + else + data_buffer.append(serializeLongString("")); // Add to known objects client->m_known_objects.insert(i.getNode()->getKey(), false); @@ -1543,6 +1607,8 @@ void Server::AsyncRunStep() Step node metadata */ { + //TimeTaker timer("Step node metadata"); + JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); @@ -1606,6 +1672,9 @@ void Server::AsyncRunStep() // Save players m_env.serializePlayers(m_mapsavedir); + + // Save environment metadata + m_env.saveMeta(m_mapsavedir); } } } @@ -1686,8 +1755,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // [0] u16 TOSERVER_INIT // [2] u8 SER_FMT_VER_HIGHEST // [3] u8[20] player_name + // [23] u8[28] password <--- can be sent without this, from old versions - if(datasize < 3) + if(datasize < 2+1+PLAYERNAME_SIZE) return; derr_server<getPassword(),password)) + { + derr_server<updateName((const char*)&data[3]); }*/ - - // Now answer with a TOCLIENT_INIT - - SharedBuffer reply(2+1+6+8); - writeU16(&reply[0], TOCLIENT_INIT); - writeU8(&reply[2], deployed); - writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS)); - //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed()); - // Send as reliable - m_con.Send(peer_id, 0, reply, true); + /* + Answer with a TOCLIENT_INIT + */ + { + SharedBuffer reply(2+1+6+8); + writeU16(&reply[0], TOCLIENT_INIT); + writeU8(&reply[2], deployed); + writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS)); + //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed()); + writeU64(&reply[2+1+6], 0); // no seed + + // Send as reliable + m_con.Send(peer_id, 0, reply, true); + } + + /* + Send complete position information + */ + SendMovePlayer(player); return; } + if(command == TOSERVER_INIT2) { derr_server<id); SendInventory(peer->id); + + // Send HP + { + Player *player = m_env.getPlayer(peer_id); + SendPlayerHP(player); + } // Send time of day { SharedBuffer data = makePacket_TOCLIENT_TIME_OF_DAY( - m_time_of_day.get()); + m_env.getTimeOfDay()); m_con.Send(peer->id, 0, data, true); } @@ -1930,6 +2041,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(datasize < 13) return; + if((player->privs & PRIV_BUILD) == 0) + return; + /* [0] u16 command [2] u8 button (0=left, 1=right) @@ -1998,6 +2112,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Add to inventory and send inventory ilist->addItem(item); + UpdateCrafting(player->peer_id); SendInventory(player->peer_id); } @@ -2010,6 +2125,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(datasize < 7) return; + if((player->privs & PRIV_BUILD) == 0) + return; + /* length: 7 [0] u16 command @@ -2019,7 +2137,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ u8 button = readU8(&data[2]); u16 id = readS16(&data[3]); - //u16 item_i = readU16(&data[11]); + u16 item_i = readU16(&data[11]); ServerActiveObject *obj = m_env.getActiveObject(id); @@ -2045,28 +2163,57 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) dout_server<<"Player inventory has no free space"<m_removed) + return; /* Create the inventory item */ - InventoryItem *item = NULL; - // If it is an item-object, take the item from it - if(obj->getType() == ACTIVEOBJECT_TYPE_ITEM - && obj->m_removed == false) - { - item = ((ItemSAO*)obj)->createInventoryItem(); - } + InventoryItem *item = obj->createPickedUpItem(); if(item) { // Add to inventory and send inventory ilist->addItem(item); + UpdateCrafting(player->peer_id); SendInventory(player->peer_id); + + // Remove object from environment + obj->m_removed = true; } - } + else + { + /* + Item cannot be picked up. Punch it instead. + */ - // Remove object from environment - obj->m_removed = true; + ToolItem *titem = NULL; + std::string toolname = ""; + + InventoryList *mlist = player->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(); + } + } + + u16 wear = obj->punch(toolname); + + if(titem) + { + bool weared_out = titem->addWear(wear); + if(weared_out) + mlist->deleteItem(item_i); + SendInventory(player->peer_id); + } + } + } } } else if(command == TOSERVER_GROUND_ACTION) @@ -2130,7 +2277,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Mandatory parameter; actually used for nothing core::map modified_blocks; - u8 material; + u8 material = CONTENT_IGNORE; u8 mineral = MINERAL_NONE; bool cannot_remove_node = false; @@ -2178,6 +2325,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) cannot_remove_node = true; } + // Make sure the player is allowed to do it + if((player->privs & PRIV_BUILD) == 0) + cannot_remove_node = true; + /* If node can't be removed, set block to be re-sent to client and quit. @@ -2271,6 +2422,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) player->inventory.addItem("main", item); // Send inventory + UpdateCrafting(player->peer_id); SendInventory(player->peer_id); } } @@ -2323,7 +2475,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) try{ // Don't add a node if this is not a free space MapNode n2 = m_env.getMap().getNode(p_over); - if(content_buildable_to(n2.d) == false) + if(content_buildable_to(n2.d) == false + || (player->privs & PRIV_BUILD) ==0) { // Client probably has wrong data. // Set block not sent, so that client will get @@ -2375,6 +2528,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) else mitem->remove(1); // Send inventory + UpdateCrafting(peer_id); SendInventory(peer_id); } @@ -2436,22 +2590,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } - v3f pos = intToFloat(p_over, BS); - pos.Y -= BS*0.45; - dout_server<<"Placing a miscellaneous item on map" <serialize(os); - dout_server<<"Item string is \""<createSAO(&m_env, 0, pos); if(obj == NULL) { @@ -2466,12 +2619,29 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) dout_server<<"Placed object"<inventory.getList("main"); - if(g_settings.getBool("creative_mode") == false && ilist) + if(g_settings.getBool("creative_mode") == false) { - // Remove from inventory and send inventory - ilist->deleteItem(item_i); + // Delete the right amount of items from the slot + u16 dropcount = item->getDropCount(); + + // Delete item if all gone + if(item->getCount() <= dropcount) + { + if(item->getCount() < dropcount) + dstream<<"WARNING: Server: dropped more items" + <<" than the slot contains"<inventory.getList("main"); + if(ilist) + // Remove from inventory and send inventory + ilist->deleteItem(item_i); + } + // Else decrement it + else + item->remove(dropcount); + // Send inventory + UpdateCrafting(peer_id); SendInventory(peer_id); } } @@ -2503,6 +2673,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) #endif else if(command == TOSERVER_SIGNTEXT) { + if((player->privs & PRIV_BUILD) == 0) + return; /* u16 command v3s16 blockpos @@ -2560,6 +2732,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } else if(command == TOSERVER_SIGNNODETEXT) { + if((player->privs & PRIV_BUILD) == 0) + return; /* u16 command v3s16 p @@ -2636,40 +2810,47 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(ma->to_inv == "current_player" && ma->from_inv == "current_player") { - // Don't allow moving anything to craftresult - if(ma->to_list == "craftresult") + InventoryList *rlist = player->inventory.getList("craftresult"); + assert(rlist); + InventoryList *clist = player->inventory.getList("craft"); + assert(clist); + InventoryList *mlist = player->inventory.getList("main"); + assert(mlist); + /* + Craftresult is no longer preview if something + is moved into it + */ + if(ma->to_list == "craftresult" + && ma->from_list != "craftresult") { - // Do nothing - disable_action = true; + // If it currently is a preview, remove + // its contents + if(player->craftresult_is_preview) + { + rlist->deleteItem(0); + } + player->craftresult_is_preview = false; + } + /* + Crafting takes place if this condition is true. + */ + if(player->craftresult_is_preview && + ma->from_list == "craftresult") + { + player->craftresult_is_preview = false; + clist->decrementMaterials(1); } - // When something is removed from craftresult - if(ma->from_list == "craftresult") + /* + If the craftresult is placed on itself, move it to + main inventory instead of doing the action + */ + if(ma->to_list == "craftresult" + && ma->from_list == "craftresult") { disable_action = true; - // Remove stuff from craft - InventoryList *clist = player->inventory.getList("craft"); - if(clist) - { - u16 count = ma->count; - if(count == 0) - count = 1; - clist->decrementMaterials(count); - } - // Do action - // Feed action to player inventory - //a->apply(&player->inventory); - a->apply(&c, this); - // Eat it - delete a; - // If something appeared in craftresult, throw it - // in the main list - InventoryList *rlist = player->inventory.getList("craftresult"); - InventoryList *mlist = player->inventory.getList("main"); - if(rlist && mlist && rlist->getUsedSlots() == 1) - { - InventoryItem *item1 = rlist->changeItem(0, NULL); - mlist->addItem(item1); - } + + InventoryItem *item1 = rlist->changeItem(0, NULL); + mlist->addItem(item1); } } } @@ -2677,7 +2858,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(disable_action == false) { // Feed action to player inventory - //a->apply(&player->inventory); a->apply(&c, this); // Eat the action delete a; @@ -2685,6 +2865,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) else { // Send inventory + UpdateCrafting(player->peer_id); SendInventory(player->peer_id); } } @@ -2727,6 +2908,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Whether to send to other players bool send_to_others = false; + // Local player gets all privileges regardless of + // what's set on their account. + u64 privs = player->privs; + if(g_settings.get("name") == player->getName()) + privs = PRIV_ALL; + // Parse commands std::wstring commandprefix = L"/#"; if(message.substr(0, commandprefix.size()) == commandprefix) @@ -2734,73 +2921,36 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) line += L"Server: "; message = message.substr(commandprefix.size()); - // Get player name as narrow string - std::string name_s = player->getName(); - // Convert message to narrow string - std::string message_s = wide_to_narrow(message); - // Operator is the single name defined in config. - std::string operator_name = g_settings.get("name"); - bool is_operator = (operator_name != "" && - wide_to_narrow(name) == operator_name); - bool valid_command = false; - if(message_s == "help") - { - line += L"-!- Available commands: "; - line += L"status "; - if(is_operator) - { - line += L"shutdown setting "; - } - else - { - } - send_to_sender = true; - valid_command = true; - } - else if(message_s == "status") - { - line = getStatusString(); - send_to_sender = true; - valid_command = true; - } - else if(is_operator) + + ServerCommandContext *ctx = new ServerCommandContext( + str_split(message, L' '), + this, + &m_env, + player, + privs); + + line += processServerCommand(ctx); + send_to_sender = ctx->flags & 1; + send_to_others = ctx->flags & 2; + delete ctx; + + } + else + { + if(privs & PRIV_SHOUT) { - if(message_s == "shutdown") - { - dstream< "; + line += message; + send_to_others = true; } - - if(valid_command == false) + else { - line += L"-!- Invalid command: " + message; + line += L"Server: You are not allowed to shout"; send_to_sender = true; } } - else - { - line += L"<"; - /*if(is_operator) - line += L"@";*/ - line += name; - line += L"> "; - line += message; - send_to_others = true; - } if(line != L"") { @@ -2830,19 +2980,74 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } } } - else + else if(command == TOSERVER_DAMAGE) { - derr_server<<"WARNING: Server::ProcessData(): Ignoring " - "unknown command "<hp > damage) + { + player->hp -= damage; + } + else + { + player->hp = 0; + + dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies" + <setPosition(pos); + player->hp = 20; + SendMovePlayer(player); + SendPlayerHP(player); + + //TODO: Throw items around + } + } + + SendPlayerHP(player); } - - } //try - catch(SendFailedException &e) + else if(command == TOSERVER_PASSWORD) { - derr_server<<"Server::ProcessData(): SendFailedException: " - <<"what="<getPassword(),password)) + { + // Wrong old password supplied!! + SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed."); + return; + } + for(u32 i=0; iupdatePassword(password); + SendChatMessage(peer_id, L"Password change successful"); + } + else + { + derr_server<<"WARNING: Server::ProcessData(): Ignoring " + "unknown command "<getName()); + start += 2+PLAYERNAME_SIZE; + } + + //JMutexAutoLock conlock(m_con_mutex); + + // Send as reliable + m_con.SendToAll(0, data, true); +} + +void Server::SendInventory(u16 peer_id) +{ + DSTACK(__FUNCTION_NAME); + + Player* player = m_env.getPlayer(peer_id); + assert(player); + + /* + Serialize it + */ + + std::ostringstream os; + //os.imbue(std::locale("C")); + + player->inventory.serialize(os); + + std::string s = os.str(); + + SharedBuffer data(s.size()+2); + writeU16(&data[0], TOCLIENT_INVENTORY); + memcpy(&data[2], s.c_str(), s.size()); + + // Send as reliable + m_con.Send(peer_id, 0, data, true); +} + +void Server::SendChatMessage(u16 peer_id, const std::wstring &message) +{ + DSTACK(__FUNCTION_NAME); + + std::ostringstream os(std::ios_base::binary); + u8 buf[12]; + + // Write command + writeU16(buf, TOCLIENT_CHAT_MESSAGE); + os.write((char*)buf, 2); + + // Write length + writeU16(buf, message.size()); + os.write((char*)buf, 2); + + // Write string + for(u32 i=0; i data((u8*)s.c_str(), s.size()); + // Send as reliable + m_con.Send(peer_id, 0, data, true); +} + +void Server::BroadcastChatMessage(const std::wstring &message) +{ + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + // Get client and check that it is valid + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + + SendChatMessage(client->peer_id, message); + } +} + +void Server::SendPlayerHP(Player *player) +{ + SendHP(m_con, player->peer_id, player->hp); +} + +void Server::SendMovePlayer(Player *player) +{ + DSTACK(__FUNCTION_NAME); + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_MOVE_PLAYER); + writeV3F1000(os, player->getPosition()); + writeF1000(os, player->getPitch()); + writeF1000(os, player->getYaw()); + + { + v3f pos = player->getPosition(); + f32 pitch = player->getPitch(); + f32 yaw = player->getYaw(); + dstream<<"Server sending TOCLIENT_MOVE_PLAYER" + <<" pos=("<serialize(os, ver); + std::string s = os.str(); + SharedBuffer blockdata((u8*)s.c_str(), s.size()); + + u32 replysize = 8 + blockdata.getSize(); + SharedBuffer reply(replysize); + writeU16(&reply[0], TOCLIENT_BLOCKDATA); + writeS16(&reply[2], p.X); + writeS16(&reply[4], p.Y); + writeS16(&reply[6], p.Z); + memcpy(&reply[8], *blockdata, blockdata.getSize()); + + /*dstream<<"Server: Sending block ("< queue; + + s32 total_sending = 0; + + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == peer_id); + assert(client->peer_id == i.getNode()->getKey()); + + total_sending += client->SendingCount(); if(client->serialization_version == SER_FMT_VER_INVALID) continue; - client->SendObjectData(this, dtime, stepped_blocks); + client->GetNextBlocks(this, dtime, queue); } -} - -void Server::SendPlayerInfos() -{ - DSTACK(__FUNCTION_NAME); - //JMutexAutoLock envlock(m_env_mutex); - - // Get connected players - core::list players = m_env.getPlayers(true); - - u32 player_count = players.getSize(); - u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count; + // Sort. + // Lowest priority number comes first. + // Lowest is most important. + queue.sort(); - SharedBuffer data(datasize); - writeU16(&data[0], TOCLIENT_PLAYERINFO); - - u32 start = 2; - core::list::Iterator i; - for(i = players.begin(); - i != players.end(); i++) + for(u32 i=0; ipeer_id); - memset((char*)&data[start+2], 0, PLAYERNAME_SIZE); - snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName()); - start += 2+PLAYERNAME_SIZE; - } + PrioritySortedBlockTransfer q = queue[i]; - //JMutexAutoLock conlock(m_con_mutex); + MapBlock *block = NULL; + try + { + block = m_env.getMap().getBlockNoCreate(q.pos); + } + catch(InvalidPositionException &e) + { + continue; + } - // Send as reliable - m_con.SendToAll(0, data, true); + RemoteClient *client = getClient(q.peer_id); + + SendBlockNoLock(q.peer_id, block, client->serialization_version); + + client->SentBlock(q.pos); + + total_sending++; + } } -void Server::SendInventory(u16 peer_id) +/* + Something random +*/ + +void Server::UpdateCrafting(u16 peer_id) { DSTACK(__FUNCTION_NAME); Player* player = m_env.getPlayer(peer_id); + assert(player); /* Calculate crafting stuff @@ -3061,11 +3628,15 @@ void Server::SendInventory(u16 peer_id) { InventoryList *clist = player->inventory.getList("craft"); InventoryList *rlist = player->inventory.getList("craftresult"); - if(rlist) + + if(rlist->getUsedSlots() == 0) + player->craftresult_is_preview = true; + + if(rlist && player->craftresult_is_preview) { rlist->clearItems(); } - if(clist && rlist) + if(clist && rlist && player->craftresult_is_preview) { InventoryItem *items[9]; for(u16 i=0; i<9; i++) @@ -3099,6 +3670,23 @@ void Server::SendInventory(u16 peer_id) } } + // Fence + if(!found) + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[5] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[6] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[8] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new MaterialItem(CONTENT_FENCE, 2)); + found = true; + } + } + // Sign if(!found) { @@ -3195,7 +3783,7 @@ void Server::SendInventory(u16 peer_id) } } - // Wooden showel + // Wooden shovel if(!found) { ItemSpec specs[9]; @@ -3209,7 +3797,7 @@ void Server::SendInventory(u16 peer_id) } } - // Stone showel + // Stone shovel if(!found) { ItemSpec specs[9]; @@ -3223,7 +3811,7 @@ void Server::SendInventory(u16 peer_id) } } - // Steel showel + // Steel shovel if(!found) { ItemSpec specs[9]; @@ -3285,6 +3873,68 @@ void Server::SendInventory(u16 peer_id) } } + // Wooden sword + if(!found) + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("WSword", 0)); + found = true; + } + } + + // Stone sword + if(!found) + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("STSword", 0)); + found = true; + } + } + + // Steel sword + if(!found) + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("SteelSword", 0)); + found = true; + } + } + + // Rail + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[1] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new MaterialItem(CONTENT_RAIL, 15)); + found = true; + } + } + // Chest if(!found) { @@ -3343,266 +3993,103 @@ void Server::SendInventory(u16 peer_id) } } - } - } // if creative_mode == false - - /* - Serialize it - */ - - std::ostringstream os; - //os.imbue(std::locale("C")); - - player->inventory.serialize(os); - - std::string s = os.str(); - - SharedBuffer data(s.size()+2); - writeU16(&data[0], TOCLIENT_INVENTORY); - memcpy(&data[2], s.c_str(), s.size()); - - // Send as reliable - m_con.Send(peer_id, 0, data, true); -} - -void Server::SendChatMessage(u16 peer_id, const std::wstring &message) -{ - DSTACK(__FUNCTION_NAME); - - std::ostringstream os(std::ios_base::binary); - u8 buf[12]; - - // Write command - writeU16(buf, TOCLIENT_CHAT_MESSAGE); - os.write((char*)buf, 2); - - // Write length - writeU16(buf, message.size()); - os.write((char*)buf, 2); - - // Write string - for(u32 i=0; i data((u8*)s.c_str(), s.size()); - // Send as reliable - m_con.Send(peer_id, 0, data, true); -} - -void Server::BroadcastChatMessage(const std::wstring &message) -{ - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) - { - // Get client and check that it is valid - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; - - SendChatMessage(client->peer_id, message); - } -} - -void Server::sendRemoveNode(v3s16 p, u16 ignore_id, - core::list *far_players, float far_d_nodes) -{ - float maxd = far_d_nodes*BS; - v3f p_f = intToFloat(p, BS); - - // Create packet - u32 replysize = 8; - SharedBuffer reply(replysize); - writeU16(&reply[0], TOCLIENT_REMOVENODE); - writeS16(&reply[2], p.X); - writeS16(&reply[4], p.Y); - writeS16(&reply[6], p.Z); + // Sandstone + if(!found) + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new MaterialItem(CONTENT_SANDSTONE, 1)); + found = true; + } + } - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) - { - // Get client and check that it is valid - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; + // Clay + if(!found) + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[4] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[6] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[7] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new MaterialItem(CONTENT_CLAY, 1)); + found = true; + } + } - // Don't send if it's the same one - if(client->peer_id == ignore_id) - continue; - - if(far_players) - { - // Get player - Player *player = m_env.getPlayer(client->peer_id); - if(player) + // Brick + if(!found) { - // If player is far away, only set modified blocks not sent - v3f player_pos = player->getPosition(); - if(player_pos.getDistanceFrom(p_f) > maxd) + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[4] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[6] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[7] = ItemSpec(ITEM_CRAFT, "clay_brick"); + if(checkItemCombination(items, specs)) { - far_players->push_back(client->peer_id); - continue; + rlist->addItem(new MaterialItem(CONTENT_BRICK, 1)); + found = true; } } - } - - // Send as reliable - m_con.Send(client->peer_id, 0, reply, true); - } -} - -void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id, - core::list *far_players, float far_d_nodes) -{ - float maxd = far_d_nodes*BS; - v3f p_f = intToFloat(p, BS); - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) - { - // Get client and check that it is valid - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; + // Paper + if(!found) + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new CraftItem("paper", 1)); + found = true; + } + } - // Don't send if it's the same one - if(client->peer_id == ignore_id) - continue; + // Book + if(!found) + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_CRAFT, "paper"); + specs[4] = ItemSpec(ITEM_CRAFT, "paper"); + specs[7] = ItemSpec(ITEM_CRAFT, "paper"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new CraftItem("book", 1)); + found = true; + } + } - if(far_players) - { - // Get player - Player *player = m_env.getPlayer(client->peer_id); - if(player) + // Book shelf + if(!found) { - // If player is far away, only set modified blocks not sent - v3f player_pos = player->getPosition(); - if(player_pos.getDistanceFrom(p_f) > maxd) + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[3] = ItemSpec(ITEM_CRAFT, "book"); + specs[4] = ItemSpec(ITEM_CRAFT, "book"); + specs[5] = ItemSpec(ITEM_CRAFT, "book"); + specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + if(checkItemCombination(items, specs)) { - far_players->push_back(client->peer_id); - continue; + rlist->addItem(new MaterialItem(CONTENT_BOOKSHELF, 1)); + found = true; } } } - - // Create packet - u32 replysize = 8 + MapNode::serializedLength(client->serialization_version); - SharedBuffer reply(replysize); - writeU16(&reply[0], TOCLIENT_ADDNODE); - writeS16(&reply[2], p.X); - writeS16(&reply[4], p.Y); - writeS16(&reply[6], p.Z); - n.serialize(&reply[8], client->serialization_version); - - // Send as reliable - m_con.Send(client->peer_id, 0, reply, true); - } -} - -void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver) -{ - DSTACK(__FUNCTION_NAME); - /* - Create a packet with the block in the right format - */ - - std::ostringstream os(std::ios_base::binary); - block->serialize(os, ver); - std::string s = os.str(); - SharedBuffer blockdata((u8*)s.c_str(), s.size()); - - u32 replysize = 8 + blockdata.getSize(); - SharedBuffer reply(replysize); - v3s16 p = block->getPos(); - writeU16(&reply[0], TOCLIENT_BLOCKDATA); - writeS16(&reply[2], p.X); - writeS16(&reply[4], p.Y); - writeS16(&reply[6], p.Z); - memcpy(&reply[8], *blockdata, blockdata.getSize()); - - /*dstream<<"Sending block ("< queue; - - s32 total_sending = 0; - - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd() == false; i++) - { - RemoteClient *client = i.getNode()->getValue(); - assert(client->peer_id == i.getNode()->getKey()); - - total_sending += client->SendingCount(); - - if(client->serialization_version == SER_FMT_VER_INVALID) - continue; - - client->GetNextBlocks(this, dtime, queue); - } - - // Sort. - // Lowest priority number comes first. - // Lowest is most important. - queue.sort(); - - for(u32 i=0; i= g_settings.getS32 - ("max_simultaneous_block_sends_server_total")) - break; - - PrioritySortedBlockTransfer q = queue[i]; - - MapBlock *block = NULL; - try - { - block = m_env.getMap().getBlockNoCreate(q.pos); - } - catch(InvalidPositionException &e) - { - continue; - } - - RemoteClient *client = getClient(q.peer_id); - - SendBlockNoLock(q.peer_id, block, client->serialization_version); - - client->SentBlock(q.pos); - - total_sending++; - } + } // if creative_mode == false } - RemoteClient* Server::getClient(u16 peer_id) { DSTACK(__FUNCTION_NAME); @@ -3618,8 +4105,10 @@ std::wstring Server::getStatusString() { std::wostringstream os(std::ios_base::binary); os<::Iterator @@ -3651,14 +4140,24 @@ void setCreativeInventory(Player *player) { player->resetInventory(); - // Give some good picks + // Give some good tools { - InventoryItem *item = new ToolItem("STPick", 0); + InventoryItem *item = new ToolItem("MesePick", 0); void* r = player->inventory.addItem("main", item); assert(r == NULL); } { - InventoryItem *item = new ToolItem("MesePick", 0); + InventoryItem *item = new ToolItem("SteelPick", 0); + void* r = player->inventory.addItem("main", item); + assert(r == NULL); + } + { + InventoryItem *item = new ToolItem("SteelAxe", 0); + void* r = player->inventory.addItem("main", item); + assert(r == NULL); + } + { + InventoryItem *item = new ToolItem("SteelShovel", 0); void* r = player->inventory.addItem("main", item); assert(r == NULL); } @@ -3674,8 +4173,17 @@ void setCreativeInventory(Player *player) CONTENT_MUD, CONTENT_STONE, CONTENT_SAND, + CONTENT_SANDSTONE, + CONTENT_CLAY, + CONTENT_BRICK, CONTENT_TREE, CONTENT_LEAVES, + CONTENT_CACTUS, + CONTENT_PAPYRUS, + CONTENT_BOOKSHELF, + CONTENT_GLASS, + CONTENT_FENCE, + CONTENT_RAIL, CONTENT_MESE, CONTENT_WATERSOURCE, CONTENT_CLOUD, @@ -3725,8 +4233,55 @@ void setCreativeInventory(Player *player) }*/ } -Player *Server::emergePlayer(const char *name, const char *password, - u16 peer_id) +v3f findSpawnPos(ServerMap &map) +{ + //return v3f(50,50,50)*BS; + + v2s16 nodepos; + s16 groundheight = 0; + + // Try to find a good place a few times + for(s32 i=0; i<1000; i++) + { + s32 range = 1 + i; + // We're going to try to throw the player to this position + nodepos = v2s16(-range + (myrand()%(range*2)), + -range + (myrand()%(range*2))); + v2s16 sectorpos = getNodeSectorPos(nodepos); + // Get sector (NOTE: Don't get because it's slow) + //m_env.getMap().emergeSector(sectorpos); + // Get ground height at point (fallbacks to heightmap function) + groundheight = map.findGroundLevel(nodepos); + // Don't go underwater + if(groundheight < WATER_LEVEL) + { + //dstream<<"-> Underwater"< WATER_LEVEL + 4) + { + //dstream<<"-> Underwater"<peer_id = PEER_ID_INEXISTENT; player->peer_id = peer_id; player->updateName(name); + player->updatePassword(password); + + if(g_settings.exists("default_privs")) + player->privs = g_settings.getU64("default_privs"); /* Set player position @@ -3780,86 +4339,9 @@ Player *Server::emergePlayer(const char *name, const char *password, dstream<<"Server: Finding spawn place for player \"" <getName()<<"\""<setPosition(intToFloat(v3s16( - 0, - 45, //64, - 0 - ), BS)); -#endif -#if 1 - s16 groundheight = 0; -#if 1 - // Try to find a good place a few times - for(s32 i=0; i<1000; i++) - { - s32 range = 1 + i; - // We're going to try to throw the player to this position - nodepos = v2s16(-range + (myrand()%(range*2)), - -range + (myrand()%(range*2))); - v2s16 sectorpos = getNodeSectorPos(nodepos); - // Get sector (NOTE: Don't get because it's slow) - //m_env.getMap().emergeSector(sectorpos); - // Get ground height at point (fallbacks to heightmap function) - groundheight = m_env.getServerMap().findGroundLevel(nodepos); - // Don't go underwater - if(groundheight < WATER_LEVEL) - { - //dstream<<"-> Underwater"< WATER_LEVEL + 4) - { - //dstream<<"-> Underwater"<emergeBlock(blockpos); - // Don't go inside ground - try{ - /*v3s16 footpos(nodepos.X, groundheight+1, nodepos.Y); - v3s16 headpos(nodepos.X, groundheight+2, nodepos.Y);*/ - v3s16 footpos = nodepos3d + v3s16(0,0,0); - v3s16 headpos = nodepos3d + v3s16(0,1,0); - if(m_env.getMap().getNode(footpos).d != CONTENT_AIR - || m_env.getMap().getNode(headpos).d != CONTENT_AIR) - { - dstream<<"-> Inside ground"< Invalid position"<setPosition(intToFloat(v3s16( - nodepos.X, - groundheight + 5, // Accomodate mud - nodepos.Y - ), BS)); -#endif + player->setPosition(pos); /* Add player to environment @@ -3875,13 +4357,33 @@ Player *Server::emergePlayer(const char *name, const char *password, { setCreativeInventory(player); } - else + else if(g_settings.getBool("give_initial_stuff")) { - /*{ - InventoryItem *item = new ToolItem("WPick", 32000); + { + InventoryItem *item = new ToolItem("SteelPick", 0); void* r = player->inventory.addItem("main", item); assert(r == NULL); - }*/ + } + { + InventoryItem *item = new MaterialItem(CONTENT_TORCH, 99); + void* r = player->inventory.addItem("main", item); + assert(r == NULL); + } + { + InventoryItem *item = new ToolItem("SteelAxe", 0); + void* r = player->inventory.addItem("main", item); + assert(r == NULL); + } + { + InventoryItem *item = new ToolItem("SteelShovel", 0); + void* r = player->inventory.addItem("main", item); + assert(r == NULL); + } + { + InventoryItem *item = new MaterialItem(CONTENT_COBBLE, 99); + void* r = player->inventory.addItem("main", item); + assert(r == NULL); + } /*{ InventoryItem *item = new MaterialItem(CONTENT_MESE, 6); void* r = player->inventory.addItem("main", item); @@ -3912,13 +4414,7 @@ Player *Server::emergePlayer(const char *name, const char *password, void* r = player->inventory.addItem("main", item); assert(r == NULL); }*/ - /*// Give some lights - { - InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999); - bool r = player->inventory.addItem("main", item); - assert(r == true); - } - // and some signs + /*// and some signs for(u16 i=0; i<4; i++) { InventoryItem *item = new MapBlockObjectItem("Sign Example text"); @@ -3973,6 +4469,23 @@ void Server::handlePeerChange(PeerChange &c) // The client should exist assert(n != NULL); + /* + Mark objects to be not known by the client + */ + RemoteClient *client = n->getValue(); + // Handle objects + for(core::map::Iterator + i = client->m_known_objects.getIterator(); + i.atEnd()==false; i++) + { + // Get object + u16 id = i.getNode()->getKey(); + ServerActiveObject* obj = m_env.getActiveObject(id); + + if(obj && obj->m_known_by_count > 0) + obj->m_known_by_count--; + } + // Collect information about leaving in chat std::wstring message; {