X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fserver.cpp;h=4e9ff076fc3317692dbaefe404cf764ad4b37bd2;hb=51d308c666dfd023169b7d5e200fbefb3d315d3b;hp=b4c3d71f4670ab64b773a7f8b882378a34515be0;hpb=9d4e9c59de533ae28badb22da87cb553783dd133;p=dragonfireclient.git diff --git a/src/server.cpp b/src/server.cpp index b4c3d71f4..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) @@ -305,8 +308,15 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, { DSTACK(__FUNCTION_NAME); + /*u32 timer_result; + TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/ + // Increment timers m_nearest_unsent_reset_timer += dtime; + m_nothing_to_send_pause_timer -= dtime; + + if(m_nothing_to_send_pause_timer >= 0) + return; // Won't send anything if already sending if(m_blocks_sending.size() >= g_settings.getU16 @@ -337,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) { @@ -355,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; @@ -475,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 @@ -555,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 } /* @@ -573,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; } /* @@ -611,6 +630,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, dest.push_back(q); num_blocks_selected += 1; + sending_something = true; } } queue_full: @@ -619,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(); } @@ -931,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), @@ -950,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); } @@ -1548,6 +1607,8 @@ void Server::AsyncRunStep() Step node metadata */ { + //TimeTaker timer("Step node metadata"); + JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); @@ -1611,6 +1672,9 @@ void Server::AsyncRunStep() // Save players m_env.serializePlayers(m_mapsavedir); + + // Save environment metadata + m_env.saveMeta(m_mapsavedir); } } } @@ -1691,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); } @@ -1935,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) @@ -2003,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); } @@ -2015,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 @@ -2024,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); @@ -2064,11 +2177,42 @@ 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); // Remove object from environment obj->m_removed = true; } + else + { + /* + Item cannot be picked up. Punch it instead. + */ + + 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); + } + } } } } @@ -2133,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; @@ -2181,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. @@ -2274,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); } } @@ -2326,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 @@ -2378,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); } @@ -2468,23 +2619,29 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) dout_server<<"Placed object"<getCount() <= 1) + if(g_settings.getBool("creative_mode") == false) { - InventoryList *ilist = player->inventory.getList("main"); - if(g_settings.getBool("creative_mode") == false && ilist) + // Delete the right amount of items from the slot + u16 dropcount = item->getDropCount(); + + // Delete item if all gone + if(item->getCount() <= dropcount) { - // Remove from inventory and send inventory - ilist->deleteItem(item_i); - // Send inventory - SendInventory(peer_id); + 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(1); + // Else decrement it + else + item->remove(dropcount); + // Send inventory + UpdateCrafting(peer_id); SendInventory(peer_id); } } @@ -2516,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 @@ -2573,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 @@ -2649,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); } } } @@ -2690,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; @@ -2698,6 +2865,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) else { // Send inventory + UpdateCrafting(player->peer_id); SendInventory(player->peer_id); } } @@ -2740,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) @@ -2747,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"") { @@ -2843,6 +2980,61 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } } } + else if(command == TOSERVER_DAMAGE) + { + if(g_settings.getBool("enable_damage")) + { + std::string datastring((char*)&data[2], datasize-2); + std::istringstream is(datastring, std::ios_base::binary); + u8 damage = readU8(is); + if(player->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); + } + else if(command == TOSERVER_PASSWORD) + { + /* + [0] u16 TOSERVER_PASSWORD + [2] u8[28] old password + [30] u8[28] new password + */ + + if(datasize != 2+PASSWORD_SIZE*2) + return; + char password[PASSWORD_SIZE]; + for(u32 i=0; igetPassword(),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 " @@ -2901,6 +3093,7 @@ void Server::inventoryModified(InventoryContext *c, std::string id) { assert(c->current_player); // Send inventory + UpdateCrafting(c->current_player->peer_id); SendInventory(c->current_player->peer_id); return; } @@ -3003,6 +3196,43 @@ void Server::deletingPeer(con::Peer *peer, bool timeout) m_peer_change_queue.push_back(c); } +/* + Static send methods +*/ + +void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp) +{ + DSTACK(__FUNCTION_NAME); + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_HP); + writeU8(os, hp); + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8*)s.c_str(), s.size()); + // Send as reliable + con.Send(peer_id, 0, data, true); +} + +void Server::SendAccessDenied(con::Connection &con, u16 peer_id) +{ + DSTACK(__FUNCTION_NAME); + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_ACCESS_DENIED); + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8*)s.c_str(), s.size()); + // Send as reliable + con.Send(peer_id, 0, data, true); +} + +/* + Non-static send methods +*/ + void Server::SendObjectData(float dtime) { DSTACK(__FUNCTION_NAME); @@ -3066,50 +3296,395 @@ void Server::SendInventory(u16 peer_id) DSTACK(__FUNCTION_NAME); Player* player = m_env.getPlayer(peer_id); + assert(player); /* - Calculate crafting stuff + Serialize it */ - if(g_settings.getBool("creative_mode") == false) - { - InventoryList *clist = player->inventory.getList("craft"); - InventoryList *rlist = player->inventory.getList("craftresult"); - if(rlist) - { - rlist->clearItems(); - } - if(clist && rlist) - { - InventoryItem *items[9]; - for(u16 i=0; i<9; i++) - { - items[i] = clist->getItem(i); - } - - bool found = false; - // Wood - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new MaterialItem(CONTENT_WOOD, 4)); - found = true; - } - } + std::ostringstream os; + //os.imbue(std::locale("C")); - // Stick - if(!found) - { - ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); - if(checkItemCombination(items, specs)) - { - rlist->addItem(new CraftItem("Stick", 4)); - found = true; - } + 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 == 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++; + } +} + +/* + Something random +*/ + +void Server::UpdateCrafting(u16 peer_id) +{ + DSTACK(__FUNCTION_NAME); + + Player* player = m_env.getPlayer(peer_id); + assert(player); + + /* + Calculate crafting stuff + */ + if(g_settings.getBool("creative_mode") == false) + { + InventoryList *clist = player->inventory.getList("craft"); + InventoryList *rlist = player->inventory.getList("craftresult"); + + if(rlist->getUsedSlots() == 0) + player->craftresult_is_preview = true; + + if(rlist && player->craftresult_is_preview) + { + rlist->clearItems(); + } + if(clist && rlist && player->craftresult_is_preview) + { + InventoryItem *items[9]; + for(u16 i=0; i<9; i++) + { + items[i] = clist->getItem(i); + } + + bool found = false; + + // Wood + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new MaterialItem(CONTENT_WOOD, 4)); + found = true; + } + } + + // Stick + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new CraftItem("Stick", 4)); + found = true; + } + } + + // 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 @@ -3208,7 +3783,7 @@ void Server::SendInventory(u16 peer_id) } } - // Wooden showel + // Wooden shovel if(!found) { ItemSpec specs[9]; @@ -3222,7 +3797,7 @@ void Server::SendInventory(u16 peer_id) } } - // Stone showel + // Stone shovel if(!found) { ItemSpec specs[9]; @@ -3236,7 +3811,7 @@ void Server::SendInventory(u16 peer_id) } } - // Steel showel + // Steel shovel if(!found) { ItemSpec specs[9]; @@ -3298,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) { @@ -3356,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); - - 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; + // 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; + } + } - // 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) + // Clay + 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, "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)) { - far_players->push_back(client->peer_id); - continue; + rlist->addItem(new MaterialItem(CONTENT_CLAY, 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); + // Brick + if(!found) + { + 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)) + { + rlist->addItem(new MaterialItem(CONTENT_BRICK, 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; + // 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); @@ -3631,8 +4105,10 @@ std::wstring Server::getStatusString() { std::wostringstream os(std::ios_base::binary); os<::Iterator @@ -3664,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); } @@ -3687,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, @@ -3738,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 @@ -3793,58 +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"<setPosition(intToFloat(v3s16( - nodepos.X, - groundheight + 5, // Accomodate mud - nodepos.Y - ), BS)); -#endif + player->setPosition(pos); /* Add player to environment @@ -3860,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); @@ -3897,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"); @@ -3958,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; {