/* Minetest-c55 Copyright (C) 2010 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "environment.h" #include "filesys.h" Environment::Environment(Map *map, std::ostream &dout): m_dout(dout) { m_map = map; m_daynight_ratio = 0.2; } Environment::~Environment() { // Deallocate players for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { delete (*i); } // The map is removed by the SceneManager m_map->drop(); //delete m_map; } void Environment::step(float dtime) { DSTACK(__FUNCTION_NAME); /* Run Map's timers */ //TimeTaker maptimerupdatetimer("m_map->timerUpdate()", g_device); // 0ms m_map->timerUpdate(dtime); //maptimerupdatetimer.stop(); /* Get the highest speed some player is going */ //TimeTaker playerspeed("playerspeed", g_device); // 0ms f32 maximum_player_speed = 0.001; // just some small value for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { f32 speed = (*i)->getSpeed().getLength(); if(speed > maximum_player_speed) maximum_player_speed = speed; } //playerspeed.stop(); /* Maximum position increment */ //f32 position_max_increment = 0.05*BS; f32 position_max_increment = 0.1*BS; // Maximum time increment (for collision detection etc) // time = distance / speed f32 dtime_max_increment = position_max_increment / maximum_player_speed; // Maximum time increment is 10ms or lower if(dtime_max_increment > 0.01) dtime_max_increment = 0.01; //TimeTaker playerupdate("playerupdate", g_device); /* Stuff that has a maximum time increment */ // Don't allow overly huge dtime if(dtime > 0.5) dtime = 0.5; u32 loopcount = 0; do { loopcount++; f32 dtime_part; if(dtime > dtime_max_increment) dtime_part = dtime_max_increment; else dtime_part = dtime; dtime -= dtime_part; /* Handle players */ for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; v3f playerpos = player->getPosition(); // Apply physics to local player bool free_move = g_settings.getBool("free_move"); if(player->isLocal() && free_move == false) { // Apply gravity to local player v3f speed = player->getSpeed(); if(player->swimming_up == false) speed.Y -= 9.81 * BS * dtime_part * 2; /* Apply water resistance */ if(player->in_water_stable || player->in_water) { f32 max_down = 2.0*BS; if(speed.Y < -max_down) speed.Y = -max_down; f32 max = 2.5*BS; if(speed.getLength() > max) { speed = speed / speed.getLength() * max; } } player->setSpeed(speed); } /* Move the player. For local player, this also calculates collision detection. */ player->move(dtime_part, *m_map, position_max_increment); /* Update lighting on remote players on client */ u8 light = LIGHT_MAX; try{ // Get node at feet v3s16 p = floatToInt(playerpos + v3f(0,BS/4,0)); MapNode n = m_map->getNode(p); light = n.getLightBlend(m_daynight_ratio); } catch(InvalidPositionException &e) {} player->updateLight(light); /* Add footsteps to grass */ if(g_settings.getBool("footprints")) { // Get node that is at BS/4 under player v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0)); try{ MapNode n = m_map->getNode(bottompos); if(n.d == CONTENT_GRASS) { n.d = CONTENT_GRASS_FOOTSTEPS; m_map->setNode(bottompos, n); #ifndef SERVER // Update mesh on client if(m_map->mapType() == MAPTYPE_CLIENT) { v3s16 p_blocks = getNodeBlockPos(bottompos); MapBlock *b = m_map->getBlockNoCreate(p_blocks); b->updateMesh(m_daynight_ratio); } #endif } } catch(InvalidPositionException &e) { } } } } while(dtime > 0.001); //std::cout<<"Looped "<isLocal() == true && getLocalPlayer() != NULL)); #endif // If peer id is non-zero, it has to be unique. if(player->peer_id != 0) assert(getPlayer(player->peer_id) == NULL); // Name has to be unique. assert(getPlayer(player->getName()) == NULL); // Add. m_players.push_back(player); } void Environment::removePlayer(u16 peer_id) { DSTACK(__FUNCTION_NAME); re_search: for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; if(player->peer_id != peer_id) continue; delete player; m_players.erase(i); // See if there is an another one // (shouldn't be, but just to be sure) goto re_search; } } #ifndef SERVER LocalPlayer * Environment::getLocalPlayer() { for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; if(player->isLocal()) return (LocalPlayer*)player; } return NULL; } #endif Player * Environment::getPlayer(u16 peer_id) { for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; if(player->peer_id == peer_id) return player; } return NULL; } Player * Environment::getPlayer(const char *name) { for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; if(strcmp(player->getName(), name) == 0) return player; } return NULL; } core::list Environment::getPlayers() { return m_players; } core::list Environment::getPlayers(bool ignore_disconnected) { core::list newlist; for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; if(ignore_disconnected) { // Ignore disconnected players if(player->peer_id == 0) continue; } newlist.push_back(player); } return newlist; } void Environment::printPlayers(std::ostream &o) { o<<"Players in environment:"<::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; o<<"Player peer_id="<peer_id< saved_players; std::vector player_files = fs::GetDirListing(players_path); for(u32 i=0; iserialize(os); saved_players.insert(player, true); } } for(core::list::Iterator i = m_players.begin(); i != m_players.end(); i++) { Player *player = *i; if(saved_players.find(player) != NULL) { /*dstream<<"Player "<getName() <<" was already saved."<getName(); // Don't save unnamed player if(playername == "") { //dstream<<"Not saving unnamed player."<getName()<<" to " <serialize(os); saved_players.insert(player, true); } } //dstream<<"Saved "< saved_players; std::vector player_files = fs::GetDirListing(players_path); for(u32 i=0; ideSerialize(is); } if(newplayer) addPlayer(player); } } #ifndef SERVER void Environment::updateMeshes(v3s16 blockpos) { m_map->updateMeshes(blockpos, m_daynight_ratio); } void Environment::expireMeshes(bool only_daynight_diffed) { m_map->expireMeshes(only_daynight_diffed); } #endif void Environment::setDayNightRatio(u32 r) { m_daynight_ratio = r; } u32 Environment::getDayNightRatio() { return m_daynight_ratio; }