X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fserver.cpp;h=6d34a0fac1dd89f323f5775463714385f11a661f;hb=61ffe1eac4565bbb74b79677a618e7f4dd894d3c;hp=14d8942cb0cf6a4a4b5091b8c70923ae207e248a;hpb=1a705523c09a914243d18ae337905de0a1b3de91;p=dragonfireclient.git diff --git a/src/server.cpp b/src/server.cpp index 14d8942cb..6d34a0fac 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -36,6 +36,16 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_nodemeta.h" #include "mapblock.h" #include "serverobject.h" +#include "settings.h" +#include "profiler.h" +#include "log.h" +#include "script.h" +#include "scriptapi.h" +#include "nodedef.h" +#include "tooldef.h" +#include "craftdef.h" + +#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) @@ -68,6 +78,8 @@ void * ServerThread::Thread() { ThreadStarted(); + log_register_thread("ServerThread"); + DSTACK(__FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER @@ -82,7 +94,7 @@ void * ServerThread::Thread() m_server->AsyncRunStep(); } - //dout_server<<"Running m_server->Receive()"<Receive()"<Receive(); } catch(con::NoIncomingDataException &e) @@ -90,11 +102,11 @@ void * ServerThread::Thread() } catch(con::PeerNotFoundException &e) { - dout_server<<"Server: PeerNotFoundException"<getBool("enable_mapgen_debug_info"); /* Get block info from queue, emerge them and send them @@ -137,7 +151,7 @@ void * EmergeThread::Thread() || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) continue; - //derr_server<<"EmergeThread::Thread(): running"<isGenerated() == false) { if(enable_mapgen_debug_info) - dstream<<"EmergeThread: generating"<m_ignore_map_edit_events); // Activate objects and stuff - m_server->m_env.activateBlock(block, 3600); + m_server->m_env->activateBlock(block, 3600); } } else @@ -268,7 +282,7 @@ void * EmergeThread::Thread() #if 0 if(lighting_invalidated_blocks.size() > 0) { - /*dstream<<"lighting "<= 0) { - // Keep this reset - m_nearest_unsent_reset_timer = 0; return; } // Won't send anything if already sending - if(m_blocks_sending.size() >= g_settings.getU16 + if(m_blocks_sending.size() >= g_settings->getU16 ("max_simultaneous_block_sends_per_client")) { - //dstream<<"Not sending any blocks, Queue full."<m_env.getPlayer(peer_id); + Player *player = server->m_env->getPlayer(peer_id); assert(player != NULL); @@ -385,7 +398,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, camera_dir.rotateYZBy(player->getPitch()); camera_dir.rotateXZBy(player->getYaw()); - /*dstream<<"camera_dir=("<getPlayerName(peer_id)<getPlayerName(peer_id)<getFloat( "full_block_send_enable_min_time_from_building")) { max_simul_sends_usually @@ -450,27 +459,29 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, */ s32 new_nearest_unsent_d = -1; - s16 d_max = g_settings.getS16("max_block_send_distance"); - s16 d_max_gen = g_settings.getS16("max_block_generate_distance"); + s16 d_max = g_settings->getS16("max_block_send_distance"); + s16 d_max_gen = g_settings->getS16("max_block_generate_distance"); // Don't loop very much at a time - if(d_max > d_start+1) - d_max = d_start+1; + s16 max_d_increment_at_time = 2; + if(d_max > d_start + max_d_increment_at_time) + d_max = d_start + max_d_increment_at_time; /*if(d_max_gen > d_start+2) d_max_gen = d_start+2;*/ - //dstream<<"Starting from "<getPlayerName(peer_id)<m_emerge_queue.addBlock(peer_id, p, flags); server->m_emergethread.trigger(); + + if(nearest_emerged_d == -1) + nearest_emerged_d = d; + } else { + if(nearest_emergefull_d == -1) + nearest_emergefull_d = d; } // get next one. continue; } + if(nearest_sent_d == -1) + nearest_sent_d = d; + /* Add block to send queue */ + /*errorstream<<"sending from d="<getPlayerName(peer_id)< g_settings->getS16("max_block_send_distance")){ + new_nearest_unsent_d = 0; + m_nothing_to_send_pause_timer = 2.0; + /*infostream<<"GetNextBlocks(): d wrapped around for " + <getPlayerName(peer_id) + <<"; setting to 0 and pausing"<= - g_settings.getS16("max_block_send_distance")) - { - // Pause time in seconds - m_nothing_to_send_pause_timer = 1.0; - /*dstream<<"nothing to send to " - <getPlayerName(peer_id) - <<" (d="< players = server->m_env.getPlayers(true); + core::list players = server->m_env->getPlayers(true); // Write player count u16 playercount = players.size(); @@ -830,137 +845,18 @@ void RemoteClient::SendObjectData( } /* - Get and write object data + Get and write object data (dummy, for compatibility) */ - /* - Get nearby blocks. - - For making players to be able to build to their nearby - environment (building is not possible on blocks that are not - in memory): - - Set blocks changed - - Add blocks to emerge queue if they are not found - - SUGGESTION: These could be ignored from the backside of the player - */ - - Player *player = server->m_env.getPlayer(peer_id); - - assert(player); - - v3f playerpos = player->getPosition(); - v3f playerspeed = player->getSpeed(); - - v3s16 center_nodepos = floatToInt(playerpos, BS); - v3s16 center = getNodeBlockPos(center_nodepos); - - s16 d_max = g_settings.getS16("active_object_range"); - - // Number of blocks whose objects were written to bos - u16 blockcount = 0; - - std::ostringstream bos(std::ios_base::binary); - - for(s16 d = 0; d <= d_max; d++) - { - core::list list; - getFacePositions(list, d); - - core::list::Iterator li; - for(li=list.begin(); li!=list.end(); li++) - { - v3s16 p = *li + center; - - /* - Ignore blocks that haven't been sent to the client - */ - { - if(m_blocks_sent.find(p) == NULL) - continue; - } - - // Try stepping block and add it to a send queue - try - { - - // Get block - MapBlock *block = server->m_env.getMap().getBlockNoCreate(p); - - /* - Step block if not in stepped_blocks and add to stepped_blocks. - */ - if(stepped_blocks.find(p) == NULL) - { - block->stepObjects(dtime, true, server->m_env.getDayNightRatio()); - stepped_blocks.insert(p, true); - block->setChangedFlag(); - } - - // Skip block if there are no objects - if(block->getObjectCount() == 0) - continue; - - /* - Write objects - */ - - // Write blockpos - writeV3S16(buf, p); - bos.write((char*)buf, 6); - - // Write objects - //block->serializeObjects(bos, serialization_version); // DEPRECATED - // count=0 - writeU16(bos, 0); - - blockcount++; - - /* - Stop collecting objects if data is already too big - */ - // Sum of player and object data sizes - s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp(); - // break out if data too big - if(sum > MAX_OBJECTDATA_SIZE) - { - goto skip_subsequent; - } - - } //try - catch(InvalidPositionException &e) - { - // Not in memory - // Add it to the emerge queue and trigger the thread. - // Fetch the block only if it is on disk. - - // Grab and increment counter - /*SharedPtr lock - (m_num_blocks_in_emerge_queue.getLock()); - m_num_blocks_in_emerge_queue.m_value++;*/ - - // Add to queue as an anonymous fetch from disk - u8 flags = BLOCK_EMERGE_FLAG_FROMDISK; - server->m_emerge_queue.addBlock(0, p, flags); - server->m_emergethread.trigger(); - } - } - } - -skip_subsequent: - // Write block count - writeU16(buf, blockcount); + writeU16(buf, 0); os.write((char*)buf, 2); - // Write block objects - os< &l) return checksum; } +struct ModSpec +{ + std::string name; + std::string path; + + ModSpec(const std::string &name_="", const std::string path_=""): + name(name_), + path(path_) + {} +}; + +static core::list getMods(core::list &modspaths) +{ + core::list mods; + for(core::list::Iterator i = modspaths.begin(); + i != modspaths.end(); i++){ + std::string modspath = *i; + std::vector dirlist = fs::GetDirListing(modspath); + for(u32 j=0; j mods = getMods(m_modspaths); + for(core::list::Iterator i = mods.begin(); + i != mods.end(); i++){ + ModSpec mod = *i; + infostream<<"Server: Loading mod \""<getMap().addEventReceiver(this); // If file exists, load environment metadata - if(fs::PathExists(m_mapsavedir+"/env_meta.txt")) + if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt")) { - dstream<<"Server: Loading environment metadata"<loadMeta(m_mapsavedir); } // Load players - dstream<<"Server: Loading players"<deSerializePlayers(m_mapsavedir); } Server::~Server() { - dstream<<"Server::~Server()"<serializePlayers(m_mapsavedir); - /* - Save environment metadata - */ - dstream<<"Server: Saving environment metadata"<saveMeta(m_mapsavedir); + } + /* Stop threads */ @@ -1167,13 +1151,23 @@ Server::~Server() { u16 peer_id = i.getNode()->getKey(); JMutexAutoLock envlock(m_env_mutex); - m_env.removePlayer(peer_id); + m_env->removePlayer(peer_id); }*/ // Delete client delete i.getNode()->getValue(); } } + + // Delete Environment + delete m_env; + + delete m_toolmgr; + delete m_nodedef; + + // Deinitialize scripting + infostream<<"Server: Deinitializing scripting"<add("Server::AsyncRunStep (num)", 1); + float dtime; { JMutexAutoLock lock1(m_step_dtime_mutex); @@ -1229,17 +1227,18 @@ void Server::AsyncRunStep() } { - ScopeProfiler sp(&g_profiler, "Server: selecting and sending " - "blocks to clients"); + ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients"); // Send blocks to clients SendBlocks(dtime); } if(dtime < 0.001) return; + + g_profiler->add("Server::AsyncRunStep with dtime (num)", 1); - //dstream<<"Server steps "<getFloat("time_speed") * 24000./(24.*3600); u32 units = (u32)(m_time_counter*speed); m_time_counter -= (f32)units / speed; - m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000); + m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000); - //dstream<<"Server: m_time_of_day = "<getFloat("time_send_interval"); //JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); @@ -1299,10 +1297,10 @@ void Server::AsyncRunStep() i.atEnd() == false; i++) { RemoteClient *client = i.getNode()->getValue(); - //Player *player = m_env.getPlayer(client->peer_id); + //Player *player = m_env->getPlayer(client->peer_id); SharedBuffer data = makePacket_TOCLIENT_TIME_OF_DAY( - m_env.getTimeOfDay()); + m_env->getTimeOfDay()); // Send as reliable m_con.Send(client->peer_id, 0, data, true); } @@ -1312,18 +1310,19 @@ void Server::AsyncRunStep() { JMutexAutoLock lock(m_env_mutex); // Step environment - ScopeProfiler sp(&g_profiler, "Server: environment step"); - m_env.step(dtime); + ScopeProfiler sp(g_profiler, "SEnv step"); + ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG); + m_env->step(dtime); } - const float map_timer_and_unload_dtime = 5.15; + const float map_timer_and_unload_dtime = 2.92; if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) { JMutexAutoLock lock(m_env_mutex); // Run Map's timers and unload unused data - ScopeProfiler sp(&g_profiler, "Server: map timer and unload"); - m_env.getMap().timerUpdate(map_timer_and_unload_dtime, - g_settings.getFloat("server_unload_unused_data_timeout")); + ScopeProfiler sp(g_profiler, "Server: map timer and unload"); + m_env->getMap().timerUpdate(map_timer_and_unload_dtime, + g_settings->getFloat("server_unload_unused_data_timeout")); } /* @@ -1340,16 +1339,16 @@ void Server::AsyncRunStep() JMutexAutoLock lock(m_env_mutex); - ScopeProfiler sp(&g_profiler, "Server: liquid transform"); + ScopeProfiler sp(g_profiler, "Server: liquid transform"); core::map modified_blocks; - m_env.getMap().transformLiquids(modified_blocks); + m_env->getMap().transformLiquids(modified_blocks); #if 0 /* Update lighting */ core::map lighting_modified_blocks; - ServerMap &map = ((ServerMap&)m_env.getMap()); + ServerMap &map = ((ServerMap&)m_env->getMap()); map.updateLighting(modified_blocks, lighting_modified_blocks); // Add blocks modified by lighting to modified_blocks @@ -1390,48 +1389,51 @@ void Server::AsyncRunStep() counter = 0.0; JMutexAutoLock lock2(m_con_mutex); - + + if(m_clients.size() != 0) + infostream<<"Players:"<::Iterator i = m_clients.getIterator(); i.atEnd() == false; i++) { //u16 peer_id = i.getNode()->getKey(); RemoteClient *client = i.getNode()->getValue(); - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); if(player==NULL) continue; - std::cout<getName()<<"\t"; - client->PrintInfo(std::cout); + infostream<<"* "<getName()<<"\t"; + client->PrintInfo(infostream); } } } - //if(g_settings.getBool("enable_experimental")) + //if(g_settings->getBool("enable_experimental")) { /* Check added and deleted active objects */ { - //dstream<<"Server: Checking added and deleted active objects"<getS16("active_object_send_range_blocks"); + radius *= MAP_BLOCKSIZE; for(core::map::Iterator i = m_clients.getIterator(); i.atEnd() == false; i++) { RemoteClient *client = i.getNode()->getValue(); - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); if(player==NULL) { // This can happen if the client timeouts somehow - /*dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client " + /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client " <peer_id <<" has no associated player"< removed_objects; core::map added_objects; - m_env.getRemovedActiveObjects(pos, radius, + m_env->getRemovedActiveObjects(pos, radius, client->m_known_objects, removed_objects); - m_env.getAddedActiveObjects(pos, radius, + m_env->getAddedActiveObjects(pos, radius, client->m_known_objects, added_objects); // Ignore if nothing happened if(removed_objects.size() == 0 && added_objects.size() == 0) { - //dstream<<"INFO: active objects: none changed"<getKey(); - ServerActiveObject* obj = m_env.getActiveObject(id); + ServerActiveObject* obj = m_env->getActiveObject(id); // Add to data buffer for sending writeU16((u8*)buf, i.getNode()->getKey()); @@ -1487,12 +1489,12 @@ void Server::AsyncRunStep() { // Get object u16 id = i.getNode()->getKey(); - ServerActiveObject* obj = m_env.getActiveObject(id); + ServerActiveObject* obj = m_env->getActiveObject(id); // Get object type u8 type = ACTIVEOBJECT_TYPE_INVALID; if(obj == NULL) - dstream<<"WARNING: "<<__FUNCTION_NAME + infostream<<"WARNING: "<<__FUNCTION_NAME <<": NULL object"<getType(); @@ -1524,7 +1526,7 @@ void Server::AsyncRunStep() // Send as reliable m_con.Send(client->peer_id, 0, reply, true); - dstream<<"INFO: Server: Sent object remove/add: " + infostream<<"Server: Sent object remove/add: " <setKnownActiveObjects(whatever); #endif } @@ -1565,7 +1567,7 @@ void Server::AsyncRunStep() JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); - ScopeProfiler sp(&g_profiler, "Server: sending object messages"); + //ScopeProfiler sp(g_profiler, "Server: sending object messages"); // Key = object id // Value = data sent by object @@ -1574,7 +1576,7 @@ void Server::AsyncRunStep() // Get active object messages from environment for(;;) { - ActiveObjectMessage aom = m_env.getActiveObjectMessage(); + ActiveObjectMessage aom = m_env->getActiveObjectMessage(); if(aom.id == 0) break; @@ -1657,7 +1659,7 @@ void Server::AsyncRunStep() /*if(reliable_data.size() > 0 || unreliable_data.size() > 0) { - dstream<<"INFO: Server: Size of object message data: " + infostream<<"Server: Size of object message data: " <<"reliable: "<type == MEET_ADDNODE) { - //dstream<<"Server: MEET_ADDNODE"<p, event->n, event->already_known_by_peer, @@ -1716,7 +1718,7 @@ void Server::AsyncRunStep() } else if(event->type == MEET_REMOVENODE) { - //dstream<<"Server: MEET_REMOVENODE"<p, event->already_known_by_peer, @@ -1727,13 +1729,13 @@ void Server::AsyncRunStep() } else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED) { - dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<p); } else if(event->type == MEET_OTHER) { - dstream<<"Server: MEET_OTHER"<::Iterator i = event->modified_blocks.getIterator(); @@ -1746,7 +1748,7 @@ void Server::AsyncRunStep() else { prof.add("unknown", 1); - dstream<<"WARNING: Server: Unknown MapEditEvent " + infostream<<"WARNING: Server: Unknown MapEditEvent " <<((u32)event->type)<getKey(); modified_blocks2.insert(p, - m_env.getMap().getBlockNoCreateNoEx(p)); + m_env->getMap().getBlockNoCreateNoEx(p)); } // Set blocks not sent for(core::list::Iterator @@ -1788,25 +1790,24 @@ void Server::AsyncRunStep() if(got_any_events) { - dstream<<"Server: MapEditEvents:"<= g_settings.getFloat("objectdata_interval")) + if(counter >= g_settings->getFloat("objectdata_interval")) { JMutexAutoLock lock1(m_env_mutex); JMutexAutoLock lock2(m_con_mutex); - ScopeProfiler sp(&g_profiler, "Server: sending mbo positions"); + //ScopeProfiler sp(g_profiler, "Server: sending player positions"); SendObjectData(counter); @@ -1833,11 +1834,11 @@ void Server::AsyncRunStep() { float &counter = m_savemap_timer; counter += dtime; - if(counter >= g_settings.getFloat("server_map_save_interval")) + if(counter >= g_settings->getFloat("server_map_save_interval")) { counter = 0.0; - ScopeProfiler sp(&g_profiler, "Server: saving stuff"); + ScopeProfiler sp(g_profiler, "Server: saving stuff"); // Auth stuff if(m_authmanager.isModified()) @@ -1851,27 +1852,27 @@ void Server::AsyncRunStep() JMutexAutoLock lock(m_env_mutex); /*// Unload unused data (delete from memory) - m_env.getMap().unloadUnusedData( - g_settings.getFloat("server_unload_unused_sectors_timeout")); + m_env->getMap().unloadUnusedData( + g_settings->getFloat("server_unload_unused_sectors_timeout")); */ - /*u32 deleted_count = m_env.getMap().unloadUnusedData( - g_settings.getFloat("server_unload_unused_sectors_timeout")); + /*u32 deleted_count = m_env->getMap().unloadUnusedData( + g_settings->getFloat("server_unload_unused_sectors_timeout")); */ // Save only changed parts - m_env.getMap().save(true); + m_env->getMap().save(true); /*if(deleted_count > 0) { - dout_server<<"Server: Unloaded "<serializePlayers(m_mapsavedir); // Save environment metadata - m_env.saveMeta(m_mapsavedir); + m_env->saveMeta(m_mapsavedir); } } } @@ -1879,14 +1880,13 @@ void Server::AsyncRunStep() void Server::Receive() { DSTACK(__FUNCTION_NAME); - u32 data_maxsize = 10000; - Buffer data(data_maxsize); + SharedBuffer data; u16 peer_id; u32 datasize; try{ { JMutexAutoLock conlock(m_con_mutex); - datasize = m_con.Receive(peer_id, *data, data_maxsize); + datasize = m_con.Receive(peer_id, data); } // This has to be called so that the client list gets synced @@ -1897,7 +1897,7 @@ void Server::Receive() } catch(con::InvalidIncomingDataException &e) { - derr_server<<"Server::Receive(): " + infostream<<"Server::Receive(): " "InvalidIncomingDataException: what()=" <removePlayer(peer_id);*/ } } @@ -1925,28 +1925,27 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock conlock(m_con_mutex); - con::Peer *peer; try{ - peer = m_con.GetPeer(peer_id); + Address address = m_con.GetPeerAddress(peer_id); + + // drop player if is ip is banned + if(m_banmanager.isIpBanned(address.serializeString())){ + SendAccessDenied(m_con, peer_id, + L"Your ip is banned. Banned name was " + +narrow_to_wide(m_banmanager.getBanName( + address.serializeString()))); + m_con.DeletePeer(peer_id); + return; + } } catch(con::PeerNotFoundException &e) { - derr_server<address.serializeString())){ - SendAccessDenied(m_con, peer_id, - L"Your ip is banned. Banned name was " - +narrow_to_wide(m_banmanager.getBanName( - peer->address.serializeString()))); - m_con.deletePeer(peer_id, false); - return; - } - - u8 peer_ser_ver = getClient(peer->id)->serialization_version; + u8 peer_ser_ver = getClient(peer_id)->serialization_version; try { @@ -1966,8 +1965,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(datasize < 2+1+PLAYERNAME_SIZE) return; - derr_server<id<serialization_version = deployed; - getClient(peer->id)->pending_serialization_version = deployed; + getClient(peer_id)->pending_serialization_version = deployed; if(deployed == SER_FMT_VER_INVALID) { - derr_server<id)->net_proto_version = net_proto_version; + getClient(peer_id)->net_proto_version = net_proto_version; if(net_proto_version == 0) { @@ -2010,6 +2009,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) L"Your client is too old. Please upgrade."); return; } + + /* Uhh... this should actually be a warning but let's do it like this */ + if(g_settings->getBool("strict_protocol_version_checking")) + { + if(net_proto_version < PROTOCOL_VERSION) + { + SendAccessDenied(m_con, peer_id, + L"Your client is too old. Please upgrade."); + return; + } + } /* Set up player @@ -2025,7 +2035,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(playername[0]=='\0') { - derr_server<get("default_password"); } - /*dstream<<"Server: Client gave password '"<get("default_privs"))); m_authmanager.save(); } + + // Enforce user limit. + // Don't enforce for users that have some admin right + if(m_clients.size() >= g_settings->getU16("max_users") && + (m_authmanager.getPrivs(playername) + & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 && + playername != g_settings->get("name")) + { + SendAccessDenied(m_con, peer_id, L"Too many users."); + return; + } // Get player Player *player = emergePlayer(playername, password, peer_id); - - /*{ - // DEBUG: Test serialization - std::ostringstream test_os; - player->serialize(test_os); - dstream<<"Player serialization test: \""<deSerialize(test_is); - }*/ - // If failed, cancel if(player == NULL) { - derr_server<peer_id != 0) - { - derr_server<peer_id = peer_id; - */ - - // Check if player doesn't exist - if(player == NULL) - throw con::InvalidIncomingDataException - ("Server::ProcessData(): INIT: Player doesn't exist"); - - /*// update name if it was supplied - if(datasize >= 20+3) - { - data[20+3-1] = 0; - player->updateName((const char*)&data[3]); - }*/ - /* Answer with a TOCLIENT_INIT */ @@ -2145,7 +2129,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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], m_env->getServerMap().getSeed()); // Send as reliable m_con.Send(peer_id, 0, reply, true); @@ -2161,38 +2145,46 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(command == TOSERVER_INIT2) { - derr_server<id<id)->serialization_version - = getClient(peer->id)->pending_serialization_version; + getClient(peer_id)->serialization_version + = getClient(peer_id)->pending_serialization_version; /* Send some initialization data */ + + // Send tool definitions + SendToolDef(m_con, peer_id, m_toolmgr); + + // Send node definitions + SendNodeDef(m_con, peer_id, m_nodedef); + + // Send textures + SendTextures(peer_id); // Send player info to all players SendPlayerInfos(); // Send inventory to player - UpdateCrafting(peer->id); - SendInventory(peer->id); + UpdateCrafting(peer_id); + SendInventory(peer_id); // Send player items to all players SendPlayerItems(); + Player *player = m_env->getPlayer(peer_id); + // Send HP - { - Player *player = m_env.getPlayer(peer_id); - SendPlayerHP(player); - } + SendPlayerHP(player); // Send time of day { SharedBuffer data = makePacket_TOCLIENT_TIME_OF_DAY( - m_env.getTimeOfDay()); - m_con.Send(peer->id, 0, data, true); + m_env->getTimeOfDay()); + m_con.Send(peer_id, 0, data, true); } // Send information about server to player in chat @@ -2201,7 +2193,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send information about joining in chat { std::wstring name = L"unknown"; - Player *player = m_env.getPlayer(peer_id); + Player *player = m_env->getPlayer(peer_id); if(player != NULL) name = narrow_to_wide(player->getName()); @@ -2213,26 +2205,56 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } // Warnings about protocol version can be issued here - /*if(getClient(peer->id)->net_proto_version == 0) + if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION) { - SendChatMessage(peer_id, L"# Server: NOTE: YOUR CLIENT IS OLD AND DOES NOT WORK PROPERLY WITH THIS SERVER"); - }*/ + SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER"); + } + + /* + Check HP, respawn if necessary + */ + HandlePlayerHP(player, 0); + + /* + Print out action + */ + { + std::ostringstream os(std::ios_base::binary); + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + // Get player + Player *player = m_env->getPlayer(client->peer_id); + if(!player) + continue; + // Get name of player + os<getName()<<" "; + } + + actionstream<getName()<<" joins game. List of players: " + <GotBlock(p); @@ -2306,7 +2329,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) throw con::InvalidIncomingDataException ("DELETEDBLOCKS length is too short"); v3s16 p = readV3S16(&data[2+1+i*6]); - /*dstream<<"Server: DELETEDBLOCKS (" + /*infostream<<"Server: DELETEDBLOCKS (" <SetBlockNotSent(p); @@ -2314,141 +2337,77 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } else if(command == TOSERVER_CLICK_OBJECT) { - if(datasize < 13) + infostream<<"Server: CLICK_OBJECT not supported anymore"<getObject(id); + u16 id = readS16(&data[3]); + u16 item_i = readU16(&data[5]); + + ServerActiveObject *obj = m_env->getActiveObject(id); if(obj == NULL) { - derr_server<<"CLICK_OBJECT object not found"<m_removed) + return; + //TODO: Check that object is reasonably close + + // Get ServerRemotePlayer + ServerRemotePlayer *srp = (ServerRemotePlayer*)player; + + // Update wielded item + srp->wieldItem(item_i); - // Left click + // Left click, pick/punch if(button == 0) { - InventoryList *ilist = player->inventory.getList("main"); - if(g_settings.getBool("creative_mode") == false && ilist != NULL) - { + actionstream<getName()<<" punches object " + <getId()<punch(srp); + +#if 0 + /* + Try creating inventory item + */ + InventoryItem *item = obj->createPickedUpItem(); - // Skip if inventory has no free space - if(ilist->getUsedSlots() == ilist->getSize()) + if(item) + { + InventoryList *ilist = player->inventory.getList("main"); + if(ilist != NULL) { - dout_server<<"Player inventory has no free space"<getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM) - { - item = ((ItemObject*)obj)->createInventoryItem(); - } - // Else create an item of the object - else - { - item = new MapBlockObjectItem - (obj->getInventoryString()); - } - - // Add to inventory and send inventory - ilist->addItem(item); - UpdateCrafting(player->peer_id); - SendInventory(player->peer_id); - } - - // Remove from block - block->removeObject(id); - } - } - else if(command == TOSERVER_CLICK_ACTIVEOBJECT) - { - if(datasize < 7) - return; - - if((getPlayerPrivs(player) & PRIV_BUILD) == 0) - return; - - /* - length: 7 - [0] u16 command - [2] u8 button (0=left, 1=right) - [3] u16 id - [5] u16 item - */ - u8 button = readU8(&data[2]); - u16 id = readS16(&data[3]); - u16 item_i = readU16(&data[11]); - - ServerActiveObject *obj = m_env.getActiveObject(id); - - if(obj == NULL) - { - derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found" - <m_removed) - return; - - //TODO: Check that object is reasonably close - - // Left click, pick object up (usually) - if(button == 0) - { - /* - Try creating inventory item - */ - InventoryItem *item = obj->createPickedUpItem(); - - if(item) - { - InventoryList *ilist = player->inventory.getList("main"); - if(ilist != NULL) - { - if(g_settings.getBool("creative_mode") == false) + actionstream<getName()<<" picked up " + <getName()<getBool("creative_mode") == false) { // Skip if inventory has no free space if(ilist->roomForItem(item) == false) { - dout_server<<"Player inventory has no free space"<getName()<<" punches object " + <getId()<getBasePosition(); v3f dir = (objpos - playerpos).normalize(); - u16 wear = obj->punch(toolname, dir); + u16 wear = obj->punch(toolname, dir, player->getName()); if(titem) { @@ -2496,22 +2458,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) SendInventory(player->peer_id); } } +#endif } // Right click, do something with object if(button == 1) { - // Track hp changes super-crappily - u16 oldhp = player->hp; - + actionstream<getName()<<" right clicks object " + <getId()<rightClick(player); - - // Send back stuff - if(player->hp != oldhp) - { - SendPlayerHP(player); - } + obj->rightClick(srp); } + + /* + Update player state to client + */ + SendPlayerHP(player); + UpdateCrafting(player->peer_id); + SendInventory(player->peer_id); } else if(command == TOSERVER_GROUND_ACTION) { @@ -2552,6 +2516,33 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) NOTE: This can be used in the future to check if somebody is cheating, by checking the timing. */ + bool cannot_punch_node = false; + + MapNode n(CONTENT_IGNORE); + + try + { + n = m_env->getMap().getNode(p_under); + } + catch(InvalidPositionException &e) + { + infostream<<"Server: Not punching: Node not found." + <<" Adding block to emerge queue." + <id); + RemoteClient *client = getClient(peer_id); JMutexAutoLock digmutex(client->m_dig_mutex); client->m_dig_tool_item = -1; #endif @@ -2578,21 +2569,22 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) u8 mineral = MINERAL_NONE; bool cannot_remove_node = false; - + + MapNode n(CONTENT_IGNORE); try { - MapNode n = m_env.getMap().getNode(p_under); + n = m_env->getMap().getNode(p_under); // Get mineral - mineral = n.getMineral(); + mineral = n.getMineral(m_nodedef); // Get material at position material = n.getContent(); // If not yet cancelled if(cannot_remove_node == false) { // If it's not diggable, do nothing - if(content_diggable(material) == false) + if(m_nodedef->get(material).diggable == false) { - derr_server<<"Server: Not finishing digging: " + infostream<<"Server: Not finishing digging: " <<"Node not diggable" <getMap().getNodeMetadata(p_under); if(meta && meta->nodeRemovalDisabled() == true) { - derr_server<<"Server: Not finishing digging: " + infostream<<"Server: Not finishing digging: " <<"Node metadata disables removal" <getName()<<" cannot remove node" + infostream<<"Player "<getName()<<" cannot remove node" <<" because privileges are "<getName()<<" digs "<getBool("creative_mode") == false) { /* Wear out tool @@ -2679,12 +2675,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) std::string toolname = titem->getToolName(); // Get digging properties for material and tool + ToolDiggingProperties tp = + m_toolmgr->getDiggingProperties(toolname); DiggingProperties prop = - getDiggingProperties(material, toolname); + getDiggingProperties(material, &tp, m_nodedef); if(prop.diggable == false) { - derr_server<<"Server: WARNING: Player digged" + infostream<<"Server: WARNING: Player digged" <<" with impossible material + tool" <<" combination"<get(material).dug_item; if(dug_s != "") { std::istringstream is(dug_s, std::ios::binary); - item = InventoryItem::deSerialize(is); + item = InventoryItem::deSerialize(is, this); } } @@ -2727,6 +2725,34 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) UpdateCrafting(player->peer_id); SendInventory(player->peer_id); } + + item = NULL; + + if(mineral != MINERAL_NONE) + item = getDiggedMineralItem(mineral, this); + + // If not mineral + if(item == NULL) + { + const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item; + s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity; + if(extra_dug_s != "" && extra_rarity != 0 + && myrand() % extra_rarity == 0) + { + std::istringstream is(extra_dug_s, std::ios::binary); + item = InventoryItem::deSerialize(is, this); + } + } + + if(item != NULL) + { + // Add a item to inventory + player->inventory.addItem("main", item); + + // Send inventory + UpdateCrafting(player->peer_id); + SendInventory(player->peer_id); + } } /* @@ -2736,7 +2762,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { MapEditEventIgnorer ign(&m_ignore_map_edit_events); - m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); + m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks); } /* Set blocks not sent to far players @@ -2751,6 +2777,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) continue; client->SetBlocksNotSent(modified_blocks); } + + /* + Run script hook + */ + ServerRemotePlayer *srp = (ServerRemotePlayer*)player; + scriptapi_environment_on_dignode(m_lua, p_under, n, srp); } /* @@ -2777,21 +2809,21 @@ 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); + MapNode n2 = m_env->getMap().getNode(p_over); bool no_enough_privs = ((getPlayerPrivs(player) & PRIV_BUILD)==0); if(no_enough_privs) - dstream<<"Player "<getName()<<" cannot add node" + infostream<<"Player "<getName()<<" cannot add node" <<" because privileges are "<get(n2).buildable_to == false || no_enough_privs) { // Client probably has wrong data. // Set block not sent, so that client will get // a valid one. - dstream<<"Client "<id)->m_time_from_building = 0.0; + getClient(peer_id)->m_time_from_building = 0.0; // Create node data MaterialItem *mitem = (MaterialItem*)item; MapNode n; n.setContent(mitem->getMaterial()); + actionstream<getName()<<" places material " + <<(int)mitem->getMaterial() + <<" at "<get(n).wall_mounted) n.param2 = packDir(p_under - p_over); // Calculate the direction for furnaces and chests and stuff - if(content_features(n).param_type == CPT_FACEDIR_SIMPLE) + if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE) { v3f playerpos = player->getPosition(); v3f blockpos = intToFloat(p_over, BS) - playerpos; @@ -2852,7 +2888,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) Handle inventory */ InventoryList *ilist = player->inventory.getList("main"); - if(g_settings.getBool("creative_mode") == false && ilist) + if(g_settings->getBool("creative_mode") == false && ilist) { // Remove from inventory and send inventory if(mitem->getCount() == 1) @@ -2873,7 +2909,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { MapEditEventIgnorer ign(&m_ignore_map_edit_events); - m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); + std::string p_name = std::string(player->getName()); + m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name); } /* Set blocks not sent to far players @@ -2889,11 +2926,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) client->SetBlocksNotSent(modified_blocks); } + /* + Run script hook + */ + ServerRemotePlayer *srp = (ServerRemotePlayer*)player; + scriptapi_environment_on_placenode(m_lua, p_over, n, srp); + /* Calculate special events */ - /*if(n.d == CONTENT_MESE) + /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE")) { u32 count = 0; for(s16 z=-1; z<=1; z++) @@ -2915,10 +2958,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) Check that the block is loaded so that the item can properly be added to the static list too */ - MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos); + MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos); if(block==NULL) { - derr_server<<"Error while placing object: " + infostream<<"Error while placing object: " "block not found"<getBool("creative_mode") && (getPlayerPrivs(player) & PRIV_BUILD) == 0) { - derr_server<<"Not allowing player to drop item: " + infostream<<"Not allowing player to drop item: " "creative mode and no build privs"<createSAO(&m_env, 0, pos); + ServerActiveObject *obj = item->createSAO(m_env, 0, pos); if(obj == NULL) { - derr_server<<"WARNING: item resulted in NULL object, " + infostream<<"WARNING: item resulted in NULL object, " <<"not placing onto map" <getName()<<" places "<getName() + <<" at "<addActiveObject(obj); - dout_server<<"Placed object"<getBool("creative_mode") == false) { // Delete the right amount of items from the slot u16 dropcount = item->getDropCount(); @@ -2973,7 +3016,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(item->getCount() <= dropcount) { if(item->getCount() < dropcount) - dstream<<"WARNING: Server: dropped more items" + infostream<<"WARNING: Server: dropped more items" <<" than the slot contains"<inventory.getList("main"); @@ -2999,7 +3042,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ else { - derr_server<<"WARNING: Server: Invalid action " + infostream<<"WARNING: Server: Invalid action " <getObject(id); - if(obj == NULL) - { - derr_server<<"Error while setting sign text: " - "object not found"<getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN) - { - derr_server<<"Error while setting sign text: " - "object is not a sign"<setText(text); - - obj->getBlock()->setChangedFlag(); + infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore" + <getMap().getNodeMetadata(p); if(!meta) return; - if(meta->typeId() != CONTENT_SIGN_WALL) + if(meta->typeId() != LEGN(m_nodedef, "CONTENT_SIGN_WALL")) return; SignNodeMetadata *signmeta = (SignNodeMetadata*)meta; signmeta->setText(text); + actionstream<getName()<<" writes \""<getMap().getBlockNoCreateNoEx(blockpos); if(block) { - block->setChangedFlag(); + block->raiseModified(MOD_STATE_WRITE_NEEDED, + "sign node text"); } - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd()==false; i++) - { - RemoteClient *client = i.getNode()->getValue(); - client->SetBlockNotSent(blockpos); - } + setBlockNotSent(blockpos); } else if(command == TOSERVER_INVENTORY_ACTION) { /*// Ignore inventory changes if in creative mode - if(g_settings.getBool("creative_mode") == true) + if(g_settings->getBool("creative_mode") == true) { - dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode" + infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode" <getBool("creative_mode") == false) { IMoveAction *ma = (IMoveAction*)a; if(ma->to_inv == "current_player" && @@ -3184,6 +3172,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { player->craftresult_is_preview = false; clist->decrementMaterials(1); + + /* Print out action */ + InventoryList *list = + player->inventory.getList("craftresult"); + assert(list); + InventoryItem *item = list->getItem(0); + std::string itemname = "NULL"; + if(item) + itemname = item->getName(); + actionstream<getName()<<" crafts " + <from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0) + { + Strfnd fn(ma->from_inv); + std::string id0 = fn.next(":"); + if(id0 == "nodemeta") + { + v3s16 p; + p.X = stoi(fn.next(",")); + p.Y = stoi(fn.next(",")); + p.Z = stoi(fn.next(",")); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); + if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) { + LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; + if (lcm->getOwner() != player->getName()) + return; + } + } + } + else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0) + { + Strfnd fn(ma->to_inv); + std::string id0 = fn.next(":"); + if(id0 == "nodemeta") + { + v3s16 p; + p.X = stoi(fn.next(",")); + p.Y = stoi(fn.next(",")); + p.Z = stoi(fn.next(",")); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); + if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) { + LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; + if (lcm->getOwner() != player->getName()) + return; + } + } + } } if(disable_action == false) @@ -3219,7 +3257,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } else { - dstream<<"TOSERVER_INVENTORY_ACTION: " + infostream<<"TOSERVER_INVENTORY_ACTION: " <<"InventoryAction::deSerialize() returned NULL" <hp > damage) - { - player->hp -= damage; - } - else - { - player->hp = 0; + std::string datastring((char*)&data[2], datasize-2); + std::istringstream is(datastring, std::ios_base::binary); + u8 damage = readU8(is); - dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies" - <setPosition(pos); - player->hp = 20; - SendMovePlayer(player); - SendPlayerHP(player); + if(g_settings->getBool("enable_damage")) + { + actionstream<getName()<<" damaged by " + <<(int)damage<<" hp at "<getPosition()/BS) + <getName(); if(m_authmanager.exists(playername) == false) { - dstream<<"Server: playername not found in authmanager"<getName()<<" changes password"<wieldItem(item); SendWieldedItem(player); } + else if(command == TOSERVER_RESPAWN) + { + if(player->hp != 0) + return; + + RespawnPlayer(player); + + actionstream<getName()<<" respawns at " + <getPosition()/BS)<clone(); @@ -3477,15 +3517,15 @@ Inventory* Server::getInventory(InventoryContext *c, std::string id) p.X = stoi(fn.next(",")); p.Y = stoi(fn.next(",")); p.Z = stoi(fn.next(",")); - NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); if(meta) return meta->getInventory(); - dstream<<"nodemeta at ("<getMap().getNodeMetadata(p); if(meta) meta->inventoryModified(); - - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd()==false; i++) - { - RemoteClient *client = i.getNode()->getValue(); - client->SetBlockNotSent(blockpos); - } + + MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos); + if(block) + block->raiseModified(MOD_STATE_WRITE_NEEDED); + + setBlockNotSent(blockpos); return; } - dstream<<__FUNCTION_NAME<<": unknown id "< Server::getPlayerInfo() @@ -3536,7 +3574,7 @@ core::list Server::getPlayerInfo() core::list list; - core::list players = m_env.getPlayers(); + core::list players = m_env->getPlayers(); core::list::Iterator i; for(i = players.begin(); @@ -3547,11 +3585,10 @@ core::list Server::getPlayerInfo() Player *player = *i; try{ - con::Peer *peer = m_con.GetPeer(player->peer_id); - // Copy info from peer to info struct - info.id = peer->id; - info.address = peer->address; - info.avg_rtt = peer->avg_rtt; + // Copy info from connection to info struct + info.id = player->peer_id; + info.address = m_con.GetPeerAddress(player->peer_id); + info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id); } catch(con::PeerNotFoundException &e) { @@ -3574,7 +3611,7 @@ core::list Server::getPlayerInfo() void Server::peerAdded(con::Peer *peer) { DSTACK(__FUNCTION_NAME); - dout_server<<"Server::peerAdded(): peer->id=" + infostream<<"Server::peerAdded(): peer->id=" <id<id=" + infostream<<"Server::deletingPeer(): peer->id=" <id<<", timeout="< data((u8*)s.c_str(), s.size()); + // Send as reliable + con.Send(peer_id, 0, data, true); +} + +void Server::SendToolDef(con::Connection &con, u16 peer_id, + IToolDefManager *tooldef) +{ + DSTACK(__FUNCTION_NAME); + std::ostringstream os(std::ios_base::binary); + + /* + u16 command + u32 length of the next item + serialized ToolDefManager + */ + writeU16(os, TOCLIENT_TOOLDEF); + std::ostringstream tmp_os(std::ios::binary); + tooldef->serialize(tmp_os); + os<::Iterator i = m_clients.getIterator(); @@ -4056,7 +4160,7 @@ void Server::SendBlocks(float dtime) for(u32 i=0; i= g_settings.getS32 + if(total_sending >= g_settings->getS32 ("max_simultaneous_block_sends_server_total")) break; @@ -4065,7 +4169,7 @@ void Server::SendBlocks(float dtime) MapBlock *block = NULL; try { - block = m_env.getMap().getBlockNoCreate(q.pos); + block = m_env->getMap().getBlockNoCreate(q.pos); } catch(InvalidPositionException &e) { @@ -4082,26 +4186,194 @@ void Server::SendBlocks(float dtime) } } +struct SendableTexture +{ + std::string name; + std::string path; + std::string data; + + SendableTexture(const std::string &name_="", const std::string path_="", + const std::string &data_=""): + name(name_), + path(path_), + data(data_) + {} +}; + +void Server::SendTextures(u16 peer_id) +{ + DSTACK(__FUNCTION_NAME); + + infostream<<"Server::SendTextures(): Sending textures to client"< > texture_bunches; + texture_bunches.push_back(core::list()); + + u32 texture_size_bunch_total = 0; + core::list mods = getMods(m_modspaths); + for(core::list::Iterator i = mods.begin(); + i != mods.end(); i++){ + ModSpec mod = *i; + std::string texturepath = mod.path + DIR_DELIM + "textures"; + std::vector dirlist = fs::GetDirListing(texturepath); + for(u32 j=0; j= bytes_per_bunch){ + texture_bunches.push_back(core::list()); + texture_size_bunch_total = 0; + } + } + } + + /* Create and send packets */ + + u32 num_bunches = texture_bunches.size(); + for(u32 i=0; i::Iterator + j = texture_bunches[i].begin(); + j != texture_bunches[i].end(); j++){ + os<name); + os<data); + } + + // Make data buffer + std::string s = os.str(); + infostream<<"Server::SendTextures(): bunch "<getName()<<" dies"<hp = 0; + + //TODO: Throw items around + + // Handle players that are not connected + if(player->peer_id == PEER_ID_INEXISTENT){ + RespawnPlayer(player); + return; + } + + SendPlayerHP(player); + + RemoteClient *client = getClient(player->peer_id); + if(client->net_proto_version >= 3) + { + SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0)); + } + else + { + RespawnPlayer(player); + } + } +} + +void Server::RespawnPlayer(Player *player) +{ + v3f pos = findSpawnPos(m_env->getServerMap()); + player->setPosition(pos); + player->hp = 20; + SendMovePlayer(player); + SendPlayerHP(player); +} + void Server::UpdateCrafting(u16 peer_id) { DSTACK(__FUNCTION_NAME); - Player* player = m_env.getPlayer(peer_id); + Player* player = m_env->getPlayer(peer_id); assert(player); /* Calculate crafting stuff */ - if(g_settings.getBool("creative_mode") == false) + if(g_settings->getBool("creative_mode") == false) { InventoryList *clist = player->inventory.getList("craft"); InventoryList *rlist = player->inventory.getList("craftresult"); - if(rlist->getUsedSlots() == 0) + if(rlist && rlist->getUsedSlots() == 0) player->craftresult_is_preview = true; if(rlist && player->craftresult_is_preview) @@ -4110,14 +4382,19 @@ void Server::UpdateCrafting(u16 peer_id) } if(clist && rlist && player->craftresult_is_preview) { - InventoryItem *items[9]; - for(u16 i=0; i<9; i++) - { - items[i] = clist->getItem(i); + // Get result of crafting grid + + std::vector items; + for(u16 i=0; i<9; i++){ + if(clist->getItem(i) == NULL) + items.push_back(NULL); + else + items.push_back(clist->getItem(i)->clone()); } + CraftPointerInput cpi(3, items); - // Get result of crafting grid - InventoryItem *result = craft_get_result(items); + InventoryItem *result = m_craftdef->getCraftResult(cpi, this); + //InventoryItem *result = craft_get_result(items, this); if(result) rlist->addItem(result); } @@ -4156,7 +4433,7 @@ std::wstring Server::getStatusString() if(client->serialization_version == SER_FMT_VER_INVALID) continue; // Get player - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); // Get name of player std::wstring name = L"unknown"; if(player != NULL) @@ -4165,19 +4442,74 @@ std::wstring Server::getStatusString() os<isSavingEnabled() == false) + if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false) os<get("motd") != "") + os<get("motd")); return os.str(); } +// Saves g_settings to configpath given at initialization +void Server::saveConfig() +{ + if(m_configpath != "") + g_settings->updateConfigFile(m_configpath.c_str()); +} + +void Server::notifyPlayer(const char *name, const std::wstring msg) +{ + Player *player = m_env->getPlayer(name); + if(!player) + return; + SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg); +} + +void Server::notifyPlayers(const std::wstring msg) +{ + BroadcastChatMessage(msg); +} + +// IGameDef interface +// Under envlock +IToolDefManager* Server::getToolDefManager() +{ + return m_toolmgr; +} +INodeDefManager* Server::getNodeDefManager() +{ + return m_nodedef; +} +ICraftDefManager* Server::getCraftDefManager() +{ + return m_craftdef; +} +ITextureSource* Server::getTextureSource() +{ + return NULL; +} +u16 Server::allocateUnknownNodeId(const std::string &name) +{ + return m_nodedef->allocateDummy(name); +} + +IWritableToolDefManager* Server::getWritableToolDefManager() +{ + return m_toolmgr; +} +IWritableNodeDefManager* Server::getWritableNodeDefManager() +{ + return m_nodedef; +} +IWritableCraftDefManager* Server::getWritableCraftDefManager() +{ + return m_craftdef; +} + v3f findSpawnPos(ServerMap &map) { //return v3f(50,50,50)*BS; - v2s16 nodepos; - s16 groundheight = 0; + v3s16 nodepos; #if 0 nodepos = v2s16(0,0); @@ -4190,41 +4522,50 @@ v3f findSpawnPos(ServerMap &map) { s32 range = 1 + i; // We're going to try to throw the player to this position - nodepos = v2s16(-range + (myrand()%(range*2)), + v2s16 nodepos2d = 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); + //v2s16 sectorpos = getNodeSectorPos(nodepos2d); // Get ground height at point (fallbacks to heightmap function) - groundheight = map.findGroundLevel(nodepos); + s16 groundheight = map.findGroundLevel(nodepos2d); // Don't go underwater if(groundheight < WATER_LEVEL) { - //dstream<<"-> Underwater"< Underwater"< WATER_LEVEL + 4) { - //dstream<<"-> Underwater"< Underwater"<= 2){ + is_good = true; + nodepos.Y -= 1; + break; + } + } + nodepos.Y++; + } + if(is_good){ + // Found a good place + //infostream<<"Searched through "<getPlayer(name); if(player != NULL) { // If player is already connected, cancel if(player->peer_id != 0) { - dstream<<"emergePlayer(): Player already connected"<peer_id = peer_id; // Reset inventory to creative if in creative mode - if(g_settings.getBool("creative_mode")) + if(g_settings->getBool("creative_mode")) { // Warning: double code below // Backup actual inventory player->inventory_backup = new Inventory(); *(player->inventory_backup) = player->inventory; // Set creative inventory - craft_set_creative_inventory(player); + craft_set_creative_inventory(player, this); } return player; @@ -4262,9 +4603,9 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id /* If player with the wanted peer_id already exists, cancel. */ - if(m_env.getPlayer(peer_id) != NULL) + if(m_env->getPlayer(peer_id) != NULL) { - dstream<<"emergePlayer(): Player with wrong name but same" + infostream<<"emergePlayer(): Player with wrong name but same" " peer_id already exists"<peer_id = c.peer_id; - //player->peer_id = PEER_ID_INEXISTENT; - player->peer_id = peer_id; - player->updateName(name); + // Add authentication stuff m_authmanager.add(name); m_authmanager.setPassword(name, password); m_authmanager.setPrivs(name, - stringToPrivs(g_settings.get("default_privs"))); + stringToPrivs(g_settings->get("default_privs"))); /* Set player position */ - dstream<<"Server: Finding spawn place for player \"" - <getName()<<"\""<getServerMap()); - player->setPosition(pos); + player = new ServerRemotePlayer(m_env, pos, peer_id, name); /* Add player to environment */ - m_env.addPlayer(player); + m_env->addPlayer(player); /* Add stuff to inventory */ - if(g_settings.getBool("creative_mode")) + if(g_settings->getBool("creative_mode")) { // Warning: double code above // Backup actual inventory player->inventory_backup = new Inventory(); *(player->inventory_backup) = player->inventory; // Set creative inventory - craft_set_creative_inventory(player); + craft_set_creative_inventory(player, this); } - else if(g_settings.getBool("give_initial_stuff")) + else if(g_settings->getBool("give_initial_stuff")) { - craft_give_initial_stuff(player); + craft_give_initial_stuff(player, this); } return player; @@ -4369,7 +4706,7 @@ void Server::handlePeerChange(PeerChange &c) { // Get object u16 id = i.getNode()->getKey(); - ServerActiveObject* obj = m_env.getActiveObject(id); + ServerActiveObject* obj = m_env->getActiveObject(id); if(obj && obj->m_known_by_count > 0) obj->m_known_by_count--; @@ -4378,28 +4715,56 @@ void Server::handlePeerChange(PeerChange &c) // Collect information about leaving in chat std::wstring message; { - std::wstring name = L"unknown"; - Player *player = m_env.getPlayer(c.peer_id); + Player *player = m_env->getPlayer(c.peer_id); if(player != NULL) - name = narrow_to_wide(player->getName()); - - message += L"*** "; - message += name; - message += L" left game"; - if(c.timeout) - message += L" (timed out)"; + { + std::wstring name = narrow_to_wide(player->getName()); + message += L"*** "; + message += name; + message += L" left game"; + if(c.timeout) + message += L" (timed out)"; + } } /*// Delete player { - m_env.removePlayer(c.peer_id); + m_env->removePlayer(c.peer_id); }*/ // Set player client disconnected { - Player *player = m_env.getPlayer(c.peer_id); + Player *player = m_env->getPlayer(c.peer_id); if(player != NULL) player->peer_id = 0; + + /* + Print out action + */ + if(player != NULL) + { + std::ostringstream os(std::ios_base::binary); + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + // Get player + Player *player = m_env->getPlayer(client->peer_id); + if(!player) + continue; + // Get name of player + os<getName()<<" "; + } + + actionstream<getName()<<" " + <<(c.timeout?"times out.":"leaves game.") + <<" List of players: " + <get("name") == playername) { return PRIV_ALL; } @@ -4454,11 +4819,11 @@ void dedicated_server_loop(Server &server, bool &kill) { DSTACK(__FUNCTION_NAME); - dstream<getFloat("profiler_print_interval"); if(profiler_print_interval != 0) { if(m_profiler_interval.step(0.030, profiler_print_interval)) { - dstream<<"Profiler:"<print(infostream); + g_profiler->clear(); } } @@ -4508,10 +4873,10 @@ void dedicated_server_loop(Server &server, bool &kill) u32 sum = PIChecksum(list); if(sum != sum_old) { - dstream<PrintLine(&dstream); + i->PrintLine(&infostream); } } sum_old = sum;