/*
Minetest
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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"
#include "porting.h"
#include "collision.h"
#include "content_mapnode.h"
#include "mapblock.h"
#include "serverobject.h"
#include "content_sao.h"
#include "settings.h"
#include "log.h"
#include "profiler.h"
#include "scripting_game.h"
#include "nodedef.h"
#include "nodemetadata.h"
#include "main.h" // For g_settings, g_profiler
#include "gamedef.h"
#ifndef SERVER
#include "clientmap.h"
#include "localplayer.h"
#include "mapblock_mesh.h"
#include "event.h"
#endif
#include "daynightratio.h"
#include "map.h"
#include "emerge.h"
#include "util/serialize.h"
#include "jthread/jmutexautolock.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
Environment::Environment():
m_time_of_day(9000),
m_time_of_day_f(9000./24000),
m_time_of_day_speed(0),
m_time_counter(0),
m_enable_day_night_ratio_override(false),
m_day_night_ratio_override(0.0f)
{
m_cache_enable_shaders = g_settings->getBool("enable_shaders");
}
Environment::~Environment()
{
// Deallocate players
for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); ++i)
{
delete (*i);
}
}
void Environment::addPlayer(Player *player)
{
DSTACK(__FUNCTION_NAME);
/*
Check that peer_ids are unique.
Also check that names are unique.
Exception: there can be multiple players with peer_id=0
*/
// 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);
for(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end();)
{
Player *player = *i;
if(player->peer_id == peer_id) {
delete player;
i = m_players.erase(i);
} else {
++i;
}
}
}
void Environment::removePlayer(const char *name)
{
for (std::list<Player*>::iterator it = m_players.begin();
it != m_players.end(); ++it) {
if (strcmp((*it)->getName(), name) == 0) {
delete *it;
m_players.erase(it);
return;
}
}
}
Player * Environment::getPlayer(u16 peer_id)
{
for(std::list<Player*>::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(std::list<Player*>::iterator i = m_players.begin();
i != m_players.end(); ++i)
{
Player *player = *i;
if(strcmp(player->getName(), name) == 0)
return player;
}
return NULL;
}
Player * Environment::getRandomConnectedPlayer()
{
std::list<Player*> connected_players = getPlayers(true);
u32 chosen_one = myrand() % connected_players.size();
u32 j = 0;
for(std::list<Player*>::iterator
i = connected_players.begin();
i != connected_players.end(); ++i)
{
if(j == chosen_one)
{
Player *player = *i;
return player;
}
j++;
}
return NULL;
}
Player * Environment::getNearestConnectedPlayer(v3f pos)
{
std::list<Player*> connected_players = getPlayers(true);
f32 nearest_d = 0;
Player *nearest_player = NULL;
for(std::list<Player*>::iterator
i = connected_players.begin();
i != connected_players.end(); ++i)
{
Player *player = *i;
f32 d = player->getPosition().getDistanceFrom(pos);
if(d < nearest_d || nearest_player == NULL)
{
nearest_d = d;
nearest_player = player;
}
}
return nearest_player;
}
std::list<Player*> Environment::getPlayers()
{
return m_players;
}
std::list<Player*> Environment::getPlayers(bool ignore_disconnected)
{
std::list<Player*> newlist;
for(std::list<Player*>::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;
}
u32 Environment::getDayNightRatio()
{
if(m_enable_day_night_ratio_override)
return m_day_night_ratio_override;
return time_to_daynight_ratio(m_time_of_day_f*24000, m_cache_enable_shaders);
}
void Environment::setTimeOfDaySpeed(float speed)
{
JMutexAutoLock(this->m_lock);
m_time_of_day_speed = speed;
}
float Environment::getTimeOfDaySpeed()
{
JMutexAutoLock(this->m_lock);
float retval = m_time_of_day_speed;
return retval;
}
void Environment::stepTimeOfDay(float dtime)
{
float day_speed = 0;
{
JMutexAutoLock(this->m_lock);
day_speed = m_time_of_day_speed;
}
m_time_counter += dtime;
f32 speed = day_speed * 24000./(24.*3600);
u32 units = (u32)(m_time_counter*speed);
bool sync_f = false;
if(units > 0){
// Sync at overflow
if(m_time_of_day + units >= 24000)
sync_f = true;
m_time_of_day = (m_time_of_day + units) % 24000;
if(sync_f)
m_time_of_day_f = (float)m_time_of_day / 24000.0;
}
if (speed > 0) {
m_time_counter -= (f32)units / speed;
}
if(!sync_f){
m_time_of_day_f += day_speed/24/3600*dtime;
if(m_time_of_day_f > 1.0)
m_time_of_day_f -= 1.0;
if(m_time_of_day_f < 0.0)
m_time_of_day_f += 1.0;
}
}
/*
ABMWithState
*/
ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
abm(abm_),
timer(0)
{
// Initialize timer to random value to spread processing
float itv = abm->getTriggerInterval();
itv = MYMAX(0.001, itv); // No less than 1ms
int minval = MYMAX(-0.51*itv, -60); // Clamp to
int maxval = MYMIN(0.51*itv, 60); // +-60 seconds
timer = myrand_range(minval, maxval);
}
/*
ActiveBlockList
*/
void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
{
v3s16 p;
for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
{
// Set in list
list.insert(p);
}
}
void ActiveBlockList::update(std::list<v3s16> &active_positions,
s16 radius,
std::set<v3s16> &blocks_removed,
std::set<v3s16> &blocks_added)
{
/*
Create the new list
*/
std::set<v3s16> newlist = m_forceloaded_list;
for(std::list<v3s16>::iterator i = active_positions.begin();
i != active_positions.end(); ++i)
{
fillRadiusBlock(*i, radius, newlist);
}
/*
Find out which blocks on the old list are not on the new list
*/
// Go through old list
for(std::set<v3s16>::iterator i = m_list.begin();
i != m_list.end(); ++i)
{
v3s16 p = *i;
// If not on new list, it's been removed
if(newlist.find(p) == newlist.end())
blocks_removed.insert(p);
}
/*
Find out which blocks on the new list are not on the old list
*/
// Go through new list
for(std::set<v3s16>::iterator i = newlist.begin();
i != newlist.end(); ++i)
{
v3s16 p = *i;
// If not on old list, it's been added
if(m_list.find(p) == m_list.end())
blocks_added.insert(p);
}
/*
Update m_list
*/
m_list.clear();
for(std::set<v3s16>::iterator i = newlist.begin();
i != newlist.end(); ++i)
{
v3s16 p = *i;
m_list.insert(p);
}
}
/*
ServerEnvironment
*/
ServerEnvironment::ServerEnvironment(ServerMap *map,
GameScripting *scriptIface, IGameDef *gamedef,
const std::string &path_world) :
m_map(map),
m_script(scriptIface),
m_gamedef(gamedef),
m_path_world(path_world),
m_send_recommended_timer(0),
m_active_block_interval_overload_skip(0),
m_game_time(0),
m_game_time_fraction_counter(0),
m_recommended_send_interval(0.1),
m_max_lag_estimate(0.1)
{
}
ServerEnvironment::~ServerEnvironment()
{
|