X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fserver.cpp;h=1e644ce6ce3a672a5f4d414f63409a66940e0fad;hb=37b7f094e3ea502339794f64e8bad22444c6fb54;hp=ba7ac1eceedc1ac0b9d32e957b4cf5d825adf993;hpb=7cac34c807b6f38eaca3bc8296566493c8874e03;p=oweals%2Fminetest.git diff --git a/src/server.cpp b/src/server.cpp index ba7ac1ece..1e644ce6c 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -99,6 +99,8 @@ void * ServerThread::Thread() ThreadStarted(); + porting::setThreadName("ServerThread"); + while(!StopRequested()) { try{ @@ -164,7 +166,8 @@ v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const Server::Server( const std::string &path_world, const SubgameSpec &gamespec, - bool simple_singleplayer_mode + bool simple_singleplayer_mode, + bool ipv6 ): m_path_world(path_world), m_gamespec(gamespec), @@ -174,7 +177,7 @@ Server::Server( m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, - g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), + ipv6, this), m_banmanager(NULL), m_rollback(NULL), @@ -291,9 +294,6 @@ Server::Server( errorstream << std::endl; } - // Path to builtin.lua - std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua"; - // Lock environment JMutexAutoLock envlock(m_env_mutex); @@ -302,16 +302,13 @@ Server::Server( m_script = new GameScripting(this); + std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua"; - // Load and run builtin.lua - infostream<<"Server: Loading builtin.lua [\"" - <loadMod(builtinpath, "__builtin"); - if(!success){ - errorstream<<"Server: Failed to load and run " - <loadScript(scriptpath)) { + throw ModError("Failed to load and run " + scriptpath); } + + // Print 'em infostream<<"Server: Loading mods: "; for(std::vector::iterator i = m_mods.begin(); @@ -347,7 +344,7 @@ Server::Server( // Initialize Environment ServerMap *servermap = new ServerMap(path_world, this, m_emerge); - m_env = new ServerEnvironment(servermap, m_script, this); + m_env = new ServerEnvironment(servermap, m_script, this, m_path_world); m_clients.setEnv(m_env); @@ -364,19 +361,13 @@ Server::Server( servermap->addEventReceiver(this); // If file exists, load environment metadata - if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt")) + if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) { infostream<<"Server: Loading environment metadata"<loadMeta(m_path_world); + m_env->loadMeta(); } - // Load players - infostream<<"Server: Loading players"<deSerializePlayers(m_path_world); - - /* - Add some test ActiveBlockModifiers to environment - */ + // Add some test ActiveBlockModifiers to environment add_legacy_abms(m_env, m_nodedef); m_liquid_transform_every = g_settings->getFloat("liquid_update"); @@ -386,42 +377,23 @@ Server::~Server() { infostream<<"Server destructing"<on_shutdown(); - } - - { - JMutexAutoLock envlock(m_env_mutex); - /* - Save players - */ infostream<<"Server: Saving players"<serializePlayers(m_path_world); + m_env->saveLoadedPlayers(); - /* - Save environment metadata - */ infostream<<"Server: Saving environment metadata"<saveMeta(m_path_world); + m_env->saveMeta(); } - /* - Stop threads - */ + // Stop threads stop(); delete m_thread; @@ -447,12 +419,10 @@ Server::~Server() delete m_script; // Delete detached inventories - { - for(std::map::iterator - i = m_detached_inventories.begin(); - i != m_detached_inventories.end(); i++){ - delete i->second; - } + for (std::map::iterator + i = m_detached_inventories.begin(); + i != m_detached_inventories.end(); i++) { + delete i->second; } } @@ -643,7 +613,7 @@ void Server::AsyncRunStep(bool initial_step) /* Send player breath if changed */ - if(playersao->m_breath_not_sent){ + if(playersao->m_breath_not_sent) { SendPlayerBreath(*i); } @@ -706,15 +676,15 @@ void Server::AsyncRunStep(bool initial_step) { float &counter = m_masterserver_timer; if(!isSingleplayer() && (!counter || counter >= 300.0) && - g_settings->getBool("server_announce") == true) + g_settings->getBool("server_announce")) { - ServerList::sendAnnounce(!counter ? "start" : "update", - m_clients.getPlayerNames(), - m_uptime.get(), - m_env->getGameTime(), - m_lag, - m_gamespec.id, - m_mods); + ServerList::sendAnnounce(counter ? "update" : "start", + m_clients.getPlayerNames(), + m_uptime.get(), + m_env->getGameTime(), + m_lag, + m_gamespec.id, + m_mods); counter = 0.01; } counter += dtime; @@ -744,7 +714,7 @@ void Server::AsyncRunStep(bool initial_step) // If definitions and textures have not been sent, don't // send objects either - if (client->getState() < DefinitionsSent) + if (client->getState() < CS_DefinitionsSent) continue; Player *player = m_env->getPlayer(client->peer_id); @@ -1144,18 +1114,19 @@ void Server::AsyncRunStep(bool initial_step) ScopeProfiler sp(g_profiler, "Server: saving stuff"); - //Ban stuff - if(m_banmanager->isModified()) + // Save ban file + if (m_banmanager->isModified()) { m_banmanager->save(); + } // Save changed parts of map m_env->getMap().save(MOD_STATE_WRITE_NEEDED); // Save players - m_env->serializePlayers(m_path_world); + m_env->saveLoadedPlayers(); // Save environment metadata - m_env->saveMeta(m_path_world); + m_env->saveMeta(); } } } @@ -1176,21 +1147,121 @@ void Server::Receive() "InvalidIncomingDataException: what()=" <getName(); + playersao = emergePlayer(playername.c_str(), peer_id); + } + m_clients.Unlock(); + + RemotePlayer *player = + static_cast(m_env->getPlayer(playername.c_str())); + + // If failed, cancel + if((playersao == NULL) || (player == NULL)) + { + if(player && player->peer_id != 0){ + errorstream<<"Server: "<getBool("enable_damage")) + SendPlayerHP(peer_id); + + // Send Breath + SendPlayerBreath(peer_id); + + // Show death screen if necessary + if(player->hp == 0) + SendDeathscreen(peer_id, false, v3f(0,0,0)); + + // Note things in chat if not in simple singleplayer mode + if(!m_simple_singleplayer_mode) + { + // Send information about server to player in chat + SendChatMessage(peer_id, getStatusString()); - // The peer has been disconnected. - // Find the associated player and remove it. + // Send information about joining in chat + { + std::wstring name = L"unknown"; + Player *player = m_env->getPlayer(peer_id); + if(player != NULL) + name = narrow_to_wide(player->getName()); - /*JMutexAutoLock envlock(m_env_mutex); + std::wstring message; + message += L"*** "; + message += name; + message += L" joined the game."; + SendChatMessage(PEER_ID_INEXISTENT,message); + } + } + Address addr = getPeerAddress(player->peer_id); + std::string ip_str = addr.serializeString(); + actionstream<getName() <<" [" << ip_str << "] joins game. " << std::endl; + /* + Print out action + */ + { + std::vector names = m_clients.getPlayerNames(); + + actionstream<getName() <<" joins game. List of players: "; - infostream<<"ServerThread: peer_id="<::iterator i = names.begin(); + i != names.end(); i++) + { + actionstream << *i << " "; + } - m_env->removePlayer(peer_id);*/ + actionstream << player->getName() <getState() > Created) + if(client->getState() > CS_Created) { verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from " <= g_settings->getU16("max_users") && + if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") && !checkPriv(playername, "server") && !checkPriv(playername, "ban") && !checkPriv(playername, "privs") && @@ -1528,7 +1605,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send as reliable m_clients.send(peer_id, 0, reply, true); - m_clients.event(peer_id, Init); + m_clients.event(peer_id, CSE_Init); } return; @@ -1540,9 +1617,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) verbosestream<<"Server: Got TOSERVER_INIT2 from " <getFloat("time_speed"); SendTimeOfDay(peer_id, time, time_speed); + ///// begin compatibility code + if (protocol_version <= 22) { + m_clients.event(peer_id, CSE_SetClientReady); + m_script->on_joinplayer(playersao); + } + ///// end compatibility code + // Warnings about protocol version can be issued here if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION) { @@ -1582,7 +1681,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } - u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version; + u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version; + u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version; if(peer_ser_ver == SER_FMT_VER_INVALID) { @@ -1615,105 +1715,40 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } else if(command == TOSERVER_RECEIVED_MEDIA) { - std::string playername = ""; - PlayerSAO *playersao = NULL; - m_clients.Lock(); - RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,DefinitionsSent); - if (client != NULL) { - playername = client->getName(); - playersao = emergePlayer(playername.c_str(), peer_id); - } - m_clients.Unlock(); - - RemotePlayer *player = - static_cast(m_env->getPlayer(playername.c_str())); - - // If failed, cancel - if((playersao == NULL) || (player == NULL)) - { - if(player && player->peer_id != 0){ - errorstream<<"Server: "<getBool("enable_damage")) - SendPlayerHP(peer_id); - - // Send Breath - SendPlayerBreath(peer_id); - - // Show death screen if necessary - if(player->hp == 0) - SendDeathscreen(peer_id, false, v3f(0,0,0)); - - // Note things in chat if not in simple singleplayer mode - if(!m_simple_singleplayer_mode) - { - // Send information about server to player in chat - SendChatMessage(peer_id, getStatusString()); - - // Send information about joining in chat - { - std::wstring name = L"unknown"; - Player *player = m_env->getPlayer(peer_id); - if(player != NULL) - name = narrow_to_wide(player->getName()); - - std::wstring message; - message += L"*** "; - message += name; - message += L" joined the game."; - SendChatMessage(PEER_ID_INEXISTENT,message); - } + if (playersao == NULL) { + errorstream + << "TOSERVER_CLIENT_READY stage 2 client init failed for peer " + << peer_id << std::endl; + return; } - actionstream<getName()<<" ["< names = m_clients.getPlayerNames(); - - actionstream<getName()<<" ["<::iterator i = names.begin(); - i != names.end(); i++) - { - actionstream << *i << " "; - } + if(datasize < 2+8) + return; - actionstream<on_joinplayer(playersao); - return; + } else if(command == TOSERVER_GOTBLOCKS) { @@ -1743,7 +1778,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } - if (m_clients.getClientState(peer_id) < Active) + if (m_clients.getClientState(peer_id) < CS_Active) { if (command == TOSERVER_PLAYERPOS) return; @@ -1754,18 +1789,20 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } Player *player = m_env->getPlayer(peer_id); - if(player == NULL){ + if(player == NULL) { errorstream<<"Server::ProcessData(): Cancelling: " "No player for peer_id="<getPlayerSAO(); - if(playersao == NULL){ + if(playersao == NULL) { errorstream<<"Server::ProcessData(): Cancelling: " "No player object for peer_id="<setBreath(breath); + m_script->player_event(playersao,"breath_changed"); } else if(command == TOSERVER_PASSWORD) { @@ -2801,7 +2839,7 @@ void Server::deletingPeer(con::Peer *peer, bool timeout) verbosestream<<"Server::deletingPeer(): peer->id=" <id<<", timeout="<id,Disconnect); + m_clients.event(peer->id, CSE_Disconnect); con::PeerChange c; c.type = con::PEER_REMOVED; c.peer_id = peer->id; @@ -2809,6 +2847,48 @@ void Server::deletingPeer(con::Peer *peer, bool timeout) m_peer_change_queue.push_back(c); } +bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval) +{ + *retval = m_con.getPeerStat(peer_id,type); + if (*retval == -1) return false; + return true; +} + +bool Server::getClientInfo( + u16 peer_id, + ClientState* state, + u32* uptime, + u8* ser_vers, + u16* prot_vers, + u8* major, + u8* minor, + u8* patch, + std::string* vers_string + ) +{ + *state = m_clients.getClientState(peer_id); + m_clients.Lock(); + RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid); + + if (client == NULL) { + m_clients.Unlock(); + return false; + } + + *uptime = client->uptime(); + *ser_vers = client->serialization_version; + *prot_vers = client->net_proto_version; + + *major = client->getMajor(); + *minor = client->getMinor(); + *patch = client->getPatch(); + *vers_string = client->getPatch(); + + m_clients.Unlock(); + + return true; +} + void Server::handlePeerChanges() { while(m_peer_change_queue.size() > 0) @@ -3054,10 +3134,11 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec, std::ostringstream os(std::ios_base::binary); u8 buf[12]; + // Write command writeU16(buf, TOCLIENT_SHOW_FORMSPEC); os.write((char*)buf, 2); - os<align); writeV2F1000(os, form->offset); writeV3F1000(os, form->world_pos); + writeV2S32(os,form->size); // Make data buffer std::string s = os.str(); @@ -3228,6 +3310,9 @@ void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value case HUD_STAT_WORLD_POS: writeV3F1000(os, *(v3f *)value); break; + case HUD_STAT_SIZE: + writeV2S32(os,*(v2s32 *)value); + break; case HUD_STAT_NUMBER: case HUD_STAT_ITEM: case HUD_STAT_DIR: @@ -3249,6 +3334,10 @@ void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask) // Write command writeU16(os, TOCLIENT_HUD_SET_FLAGS); + + //////////////////////////// compatibility code to be removed ////////////// + flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE); + //////////////////////////////////////////////////////////////////////////// writeU32(os, flags); writeU32(os, mask); @@ -3338,6 +3427,7 @@ void Server::SendPlayerHP(u16 peer_id) assert(playersao); playersao->m_hp_not_sent = false; SendHP(peer_id, playersao->getHP()); + m_script->player_event(playersao,"health_changed"); // Send to other clients std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP()); @@ -3351,6 +3441,7 @@ void Server::SendPlayerBreath(u16 peer_id) PlayerSAO *playersao = getPlayerSAO(peer_id); assert(playersao); playersao->m_breath_not_sent = false; + m_script->player_event(playersao,"breath_changed"); SendBreath(peer_id, playersao->getBreath()); } @@ -3384,6 +3475,38 @@ void Server::SendMovePlayer(u16 peer_id) m_clients.send(peer_id, 0, data, true); } +void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed) +{ + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS); + writeV2S32(os, animation_frames[0]); + writeV2S32(os, animation_frames[1]); + writeV2S32(os, animation_frames[2]); + writeV2S32(os, animation_frames[3]); + writeF1000(os, animation_speed); + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8 *)s.c_str(), s.size()); + // Send as reliable + m_clients.send(peer_id, 0, data, true); +} + +void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third) +{ + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_EYE_OFFSET); + writeV3F1000(os, first); + writeV3F1000(os, third); + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8 *)s.c_str(), s.size()); + // Send as reliable + m_clients.send(peer_id, 0, data, true); +} void Server::SendPlayerPrivileges(u16 peer_id) { Player *player = m_env->getPlayer(peer_id); @@ -3418,7 +3541,7 @@ void Server::SendPlayerInventoryFormspec(u16 peer_id) std::ostringstream os(std::ios_base::binary); writeU16(os, TOCLIENT_INVENTORY_FORMSPEC); - os<inventory_formspec); + os<inventory_formspec); // Make data buffer std::string s = os.str(); @@ -3721,7 +3844,7 @@ void Server::SendBlocks(float dtime) i = clients.begin(); i != clients.end(); ++i) { - RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active); + RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active); if (client == NULL) return; @@ -3757,7 +3880,7 @@ void Server::SendBlocks(float dtime) continue; } - RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active); + RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active); if(!client) continue; @@ -4148,7 +4271,7 @@ void Server::DenyAccess(u16 peer_id, const std::wstring &reason) DSTACK(__FUNCTION_NAME); SendAccessDenied(peer_id, reason); - m_clients.event(peer_id,SetDenied); + m_clients.event(peer_id, CSE_SetDenied); m_con.DisconnectPeer(peer_id); } @@ -4414,24 +4537,25 @@ bool Server::showFormspec(const char *playername, const std::string &formspec, c u32 Server::hudAdd(Player *player, HudElement *form) { if (!player) return -1; - - u32 id = player->getFreeHudID(); - if (id < player->hud.size()) - player->hud[id] = form; - else - player->hud.push_back(form); + u32 id = player->addHud(form); + SendHUDAdd(player->peer_id, id, form); + return id; } bool Server::hudRemove(Player *player, u32 id) { - if (!player || id >= player->hud.size() || !player->hud[id]) + if (!player) return false; - delete player->hud[id]; - player->hud[id] = NULL; + HudElement* todel = player->removeHud(id); + + if (!todel) + return false; + delete todel; + SendHUDRemove(player->peer_id, id); return true; } @@ -4449,6 +4573,9 @@ bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) { return false; SendHUDSetFlags(player->peer_id, flags, mask); + player->hud_flags = flags; + + m_script->player_event(player->getPlayerSAO(),"hud_changed"); return true; } @@ -4478,6 +4605,24 @@ void Server::hudSetHotbarSelectedImage(Player *player, std::string name) { SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name); } +bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed) +{ + if (!player) + return false; + + SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed); + return true; +} + +bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third) +{ + if (!player) + return false; + + SendEyeOffset(player->peer_id, first, third); + return true; +} + bool Server::setSky(Player *player, const video::SColor &bgcolor, const std::string &type, const std::vector ¶ms) { @@ -4853,15 +4998,16 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id) return NULL; } - /* - Create a new player if it doesn't exist yet - */ - if(player == NULL) - { + // Load player if it isn't already loaded + if (!player) { + player = static_cast(m_env->loadPlayer(name)); + } + + // Create player if it doesn't exist + if (!player) { newplayer = true; player = new RemotePlayer(this); player->updateName(name); - /* Set player position */ infostream<<"Server: Finding spawn place for player \"" <addPlayer(player); } - /* - Create a new player active object - */ + // Create a new player active object PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id, getPlayerEffectivePrivs(player->getName()), isSingleplayer()); /* Clean up old HUD elements from previous sessions */ - player->hud.clear(); + player->clearHud(); /* Add object to environment */ m_env->addActiveObject(playersao); /* Run scripts */ - if(newplayer) + if (newplayer) { m_script->on_newplayer(playersao); + } return playersao; }